5 layerinfo "type" = "core";
6 layerinfo "name" = "LiveJournal S2 Core, v1";
7 layerinfo "redist_uniq" = "core1";
8 layerinfo "majorversion" = "1";
9 layerinfo "author_name" = "LiveJournal Webmaster";
10 layerinfo "author_email" = "webmaster@livejournal.com";
15 "An integer number. This isn't really a class, as suggested by its lower-case name. Parameters of type int pass by value, unlike all variables of real object types, which pass by reference. Instead, this is just a pseudo-class which provides convenience methods on instances of integers. The other pseudo-class is [class[string]]."
17 function builtin zeropad(int digits) : string
18 "Return the integer as a string formatted at least \$digits characters long, left-padded with zeroes.";
20 function builtin compare(int n) : int
21 "Compare one integer with another. Returns a negative number if n is less than the subject, positive if greater or zero if the two are numerically equal.";
25 "A series of characters. This isn't really a class, as suggested by its lower-case name. Parameters of type string pass by value, unlike all variables of real object types, which pass by reference. Instead, this is just a pseudo-class which provides convenience methods on instances of strings. The other pseudo-class is [class[int]]."
27 function builtin substr(int start, int length) : string
28 "Returns up to \$length characters from string, skipping \$start characters from the beginning.";
30 function builtin ends_with (string sub) : bool
31 "Returns true if string ends in \$sub";
33 function builtin starts_with (string sub) : bool
34 "Returns true if string begins with \$sub";
36 function builtin contains (string sub) : bool
37 "Return true if string contains \$sub";
39 function builtin lower : string
40 "Returns string in lower case.";
42 function builtin upper : string
43 "Returns string in upper case";
45 function builtin upperfirst : string
46 "Return string with the first character capitalized.";
48 function builtin length() : int
49 "Return the number of characters in the string.";
51 function builtin repeat(int n) : string
52 "Returns the string repeated n times";
54 function builtin compare(string s) : int
55 "Compare one string with another. Returns a negative number if n is alphabetically before the subject, positive if greater or zero if the two are equal. Note that this function currently does a simple ASCII compare, not a proper unicode-aware sort.";
57 function builtin css_string() : string
58 "Returns the string escaped and quoted as a CSS string literal, safe for insertion into a stylesheet.";
60 function builtin css_keyword() : string
61 "If the string is syntactically valid as a CSS keyword (only letters and spaces) returns it, else returns an empty string.";
63 function builtin css_keyword_list() : string
64 "Analyses the string as a space-separated list of CSS keywords and returns a string containing the items that are syntactically acceptable.";
66 function builtin css_keyword(string[] allowed) : string
67 "Same as [method[string.css_keyword()]] except also imposes a whitelist of valid keywords given in \$allowed.";
69 function builtin css_keyword_list(string[] allowed) : string
70 "Same as [method[string.css_keyword_list()]] except also imposes a whitelist of valid keywords given in \$allowed.";
72 function builtin css_length_value() : string
73 "If the string contains a valid CSS length value, returns a canonical version. Else returns an empty string.";
75 function builtin css_url_value : string
76 "If the string contains a valid HTTP or HTTPS URL it is returned. Otherwise, an empty string is returned.";
82 var readonly int r "Red value, 0-255.";
83 var readonly int g "Green value, 0-255.";
84 var readonly int b "Blue value, 0-255.";
85 var string as_string "HTML hex encoded: #rrggbb";
86 function builtin Color(string s) : Color "Constructor for color class. Lets you make a Color object from a string of form #rrggbb";
87 function builtin set_hsl (int h, int s, int v) "Set the HSL value for a color class.";
89 function builtin red(int r) "Set the red value. (0-255)";
90 function builtin green(int g) "Set the green value. (0-255)";
91 function builtin blue(int b) "Set the blue value. (0-255)";
92 function builtin red() : int "Get the red value.";
93 function builtin green() : int "Get the green value.";
94 function builtin blue() : int "Get the blue value.";
96 function builtin hue(int h) "Set the hue value. (0-255)";
97 function builtin saturation(int s) "Set the saturation value. (0-255)";
98 function builtin lightness(int v) "Set the lightness value. (0-255)";
99 function builtin hue() : int "Get the hue value. (0-255)";
100 function builtin saturation() : int "Get the saturation value. (0-255)";
101 function builtin lightness() : int "Get the lightness value. (0-255)";
103 function builtin clone() : Color "Returns identical color.";
104 function builtin lighter() : Color "Returns a new color with lightness increased by 30.";
105 function builtin lighter(int amt) : Color "Returns a new color with lightness increased by amount given.";
106 function builtin darker() : Color "Returns a new color with lightness decreased by 30.";
107 function builtin darker(int amt) : Color "Returns a new color with lightness decreased by amount given.";
108 function builtin inverse() : Color "Returns inverse of color.";
109 function builtin average(Color other) : Color "Returns color averaged with \$other color.";
110 function builtin blend(Color other, int value) : Color "Returns color blended with \$other color by percentage value (int between 0 and 100).";
114 ##[ site-core classes ]
119 var int year "Year; 4 digits.";
120 var int month "Month; 1-12.";
121 var int day "Day; 1-31.";
123 function builtin day_of_week() : int
124 "Returns the day of the week this date falls on, from Sunday=1 to Saturday=7";
126 function builtin date_format () : string
127 "Returns date formatted as normal. /// SeeAlso: siteapi.core1.dateformats";
129 function builtin date_format (string fmt) : string
130 "Returns date formatted as indicated by \$fmt. One of: short, med, long, med_day, long_day. Or a custom format. Default is 'short'. /// SeeAlso: siteapi.core1.dateformats";
132 function builtin compare(Date d) : int
133 "Compare two dates. Returns a negative number if d is before the subject in time, positive if it is after, or zero if the two dates are equal. When comparing a Date with a DateTime, the time on the bare Date value is assumed to be midnight.";
135 function builtin compare(DateTime d) : int
136 "Compare two dates. Returns a negative number if d is before the subject in time, positive if it is after, or zero if the two dates are equal. When comparing a Date with a DateTime, the time on the bare Date value is assumed to be midnight.";
139 class DateTime extends Date
140 "Represents both a date and time."
142 var int hour "Hour; 0-23.";
143 var int min "Minute; 0-59.";
144 var int sec "Second; 0-59.";
146 function builtin time_format () : string
147 "Returns time formatted as normal. /// SeeAlso: siteapi.core1.dateformats";
149 function builtin time_format (string fmt) : string
150 "Returns time formatted as indicated by \$fmt, or normal if blank. /// SeeAlso: siteapi.core1.dateformats";
154 "Represents an image."
156 var readonly string url "URL of the image";
157 var int width "Width in pixels";
158 var int height "Height in pixels";
159 var string alttext "Default alternative text for image";
160 var readonly string{} extra "Extra params for img tag";
162 function builtin set_url (string url)
163 "Sets the URL, doing any necessary escaping.";
166 "Print an HTML tag for this Image";
168 function print (string alttext)
169 "Print an HTML tag for this Image with given alttext";
171 function print (string{} opts)
172 "Print the HTML for an image, Supported keys are 'href' to create a link to the image source
173 and 'a_attr' which adds attributes to the anchor tag if a link is to be printed.";
175 function as_string () : string
176 "Return the HTML tag for this image";
178 function as_string (string alttext) : string
179 "Return an HTML tag for this Image with given alttext";
181 function as_string_ex (string alttext, string attributes) : string
182 "Return an HTML tag for this Image with given alttext and given additional HTML tag attributes";
184 function as_string (string{} opts) : string
185 "Return the HTML for an image, Supported keys are 'href' to create a link to the image source
186 and 'a_attr' which adds attributes to the anchor tag if a link is to be printed.";
192 var readonly string url "URL which the link points to";
193 var readonly string caption "The caption for the link";
195 "A suggestion from the server as to which icon to use. layouts/users can override this of course.
196 alt text works similarly to [member[Link.caption]].";
198 function print_button
199 "Output this Link as a clickable button using [member[Link.icon]]";
201 function as_string() : string
202 "Return the button HTML link.";
204 function builtin print_raw()
205 "Output additional link HTML code.";
209 "Represents a range of items which optionally contain items."
211 var bool all_subitems_displayed "True if the subitems in this range represent the entire set. In this case, all of the URL members are blank.";
212 var int num_subitems_displayed "The number of subitems in this range.";
213 var int total "The total number of items that are navigable to.";
214 var int current "The currently-active item.";
215 var int from_subitem "The index of the first subitem in this range.";
216 var int to_subitem "The index of the last subitem in this range.";
217 var int total_subitems "The number of subitems.";
218 var readonly string url_next "URL for the 'next' link. Blank if there isn't a next URL.";
219 var readonly string url_prev "URL for the 'previous' link. Blank if there isn't a previous URL.";
220 var readonly string url_first "URL for the 'first' link. Blank if already on the first page.";
221 var readonly string url_last "URL for the 'last' link. Blank if already on the last page.";
222 function builtin url_of(int n) : string "Returns the URL to use to link to the nth item";
224 function print () "Prints the item range links";
225 function print(string labeltext) "Prints the item range links with the given \$labeltext";
228 ### LJ Specific Classes
231 "Information about comments attached to something."
233 var readonly string read_url "URL pointer to the 'Read Comments' view.";
234 var readonly string read_spam_url "URL pointer to the 'Show/Hide Spam' view.";
235 var readonly string post_url "URL pointer to the 'Post Comments' view.";
236 var int count "Current number of comments available to be read by the viewer.";
237 var int spam_counter "Current number of spam comments.";
238 var bool screened "Set to true if there are screened comments and remote user can unscreen them.";
239 var bool enabled "Set to false if comments disabled journal-wide or just on this item.";
240 var bool locked "Set to true if no further comments can be left on this entry.";
241 var bool maxcomments "Set to true if entry has reached a comment maximum.";
242 var bool show_postlink "Indicates whether the Post Comment link for this entry should be shown.";
243 var bool show_readlink "Indicates whether the Read Comments link for this entry should be shown.";
246 "Print all comment related links";
247 function print_readlink
248 "Print the formatted link to the 'Read Comments' view";
249 function print_postlink
250 "Print the formatted link to the 'Post Comments' view";
251 function print_spamlink
252 "Print the formatted link to the 'Show spam' view";
256 "A user-defined link to an outside resource."
258 var readonly bool is_heading "Is this link a heading or category name? If so, it has no url and a list of children.";
259 var readonly string title "The title or label for the link";
260 var readonly string url "The url to which the link points";
261 var readonly UserLink[] children "Not Implemented: An array of child UserLink objects.";
265 "A 'lite' version of a [class[User]] which the system often has more readily-available than a full version."
267 var readonly string username "Canonical Username, ex: johnqpub. Note that if journal_type is an external identity, there will be no username, so this field will be a display version of their URL, longer than 15 characters, and with characters other than a-z, 0-9 and underscore.";
268 var readonly string name "User's formatted name, ex: John Q. Public";
269 var readonly string journal_type "Type of account: P (personal), C (community), Y (syndicated), S (shared), I (external identity) etc";
271 var Link{} data_link "Links to various machine-readable data sources relating to this user";
272 var string[] data_links_order "An array of data views which can be used to order the data_link hash";
274 var string[] link_keyseq "Array of keys which can be passed into the get_link";
276 function builtin equals(UserLite u) : bool "Returns true if the two user objects refer to the same user. Use this rather than comparing usernames, since usernames aren't globally unique.";
277 function builtin ljuser() : string "Returns an LJ user tag for the user.";
278 function builtin ljuser(Color link_color) : string "Returns an LJ user tag for the user. The color of the link will be link_color.";
279 function builtin get_link(string key) : Link "Returns a link based on the given key, or null if the link is unavailable";
280 function base_url () : string "Returns URL of user's journal.";
281 function tag_manage_url () : string "Returns URL to user's tag management page.";
282 function print_linkbar() "Print the link bar for this user/journal.";
283 function as_string() : string;
288 "Represents a tag in its most basic form."
290 var readonly string name "Textual representation of this tag.";
291 var readonly string url "URL to view entries with this tag.";
294 class TagDetail extends Tag
295 "A rich structure with lots of information about a Tag."
297 var readonly int use_count "Count of how many times this tag has been used.";
298 var readonly string visibility "The visibility level for this tag. Based on the entries it's used on. Can be one of: public, private, friends, group.";
299 var readonly int{} security_counts "How many times this tag has used this security. The keys are which security, one of: public, private, friends, group. The value is the count of times the tag is used on entries with that security level.";
303 "Base class for both journal entries and comments."
305 var readonly string subject "Subject. May contain HTML. Don't do substring chops on this.";
307 var readonly string text
308 "Entry Text; Use [method[EntryLite.print_text()]] to print this so that the entry's trust level is not affected by your layer's trust level.";
311 var readonly bool text_must_print_trusted
312 "Indicates that this entry's text contains some content that must be printed trusted, with [method[EntryLite.print_text()]], rather than printed directly from an untrusted context. Use this to fall back to a plain trusted print if you are doing something unusual with [member[EntryLite.text]]. Most layers can just ignore this and always use [method[EntryLite.print_text()]].";
314 var DateTime time "The user-specified time of the post, or the GMT time if it's a comment.";
315 var DateTime system_time "The system time (in GMT) this entry or comment was posted.";
317 var UserLite poster "Author of the entry, or null if an anonymous comment";
318 var UserLite journal "Journal the entry has been posted to";
320 var readonly Tag[] tags "Array of tags applied to this entry.";
322 var Image userpic "The userpic selected to relate to this entry.";
324 var readonly string{} metadata "Post metadata. Keys: 'music', 'mood'";
326 var readonly string dom_id "The DOM 'id' attribute you should put on your outer-most element";
328 var readonly string permalink_url "A URL at which this specific entry can be viewed, for linking purposes.";
329 var int depth "Visual depth of entry. Top-level journal entries are always depth zero. Comments have a depth greater than or equal to one, depending on where the thread is rooted at.";
331 var string[] link_keyseq "An array of keys which you should pass to [method[EntryLite.get_link(string key)]] to produce an entry 'toolbar'. Does not contain nav_next and nav_prev for entries; you should retrieve those separately and put them somewhere appropriate for your layout.";
333 function print_text() [fixed]
334 "Print the entry text. Doesn't print anything in some contexts, such as on a month view or in a collapsed comment.";
335 function builtin get_link (string key) : Link "Get a link to some action related to this entry or comment. You can iterate over [member[EntryLite.link_keyseq]] to get keys to pass in here to produce a 'toolbar' of links.";
336 function builtin get_plain_subject () : string "For Entries that can contain HTML subjects, this returns the subject without HTML. Comments can't have HTML in subjects, so this is equivalent to just using \$.subject. The returned 'plain' subject may still contain HTML entities, so don't do substring chops on it either.";
337 function builtin get_tags_text () : string "Returns a string containing a div of class 'ljtags' with the tags for the entry. If there are no tags on the entry, returns a blank string. The string is formatted according to the 'text_tags' property.";
338 function print_linkbar() "Print the link bar for this entry or comment.";
339 function time_display () : string "Show the time of this post, with most useful information for user, and with tooltip for more.";
340 function time_display (string datefmt, string timefmt) : string "time_display, with customized date/time formats.";
341 function builtin formatted_subject (string{} opts) : string "formats subject - outputs subject as html-link, gets hash of attributes - class and(or) style ";
344 class Entry extends EntryLite
347 var readonly string security "The security level of the entry ('private', 'protected'), or blank if public.";
348 var Image security_icon "A little icon which should be displayed somewhere on an entry to represent the security setting";
350 var Image mood_icon "Mood icon, or null.";
351 var CommentInfo comments "Comment information on this entry";
353 var bool new_day "Is this entry on a different day to the previous one?";
354 var bool end_day "Is this the last entry of a day?";
356 var int itemid "Server stored ID number for this entry";
358 function print_metadata ();
359 function builtin plain_subject () : string
360 "Return entry's subject as plain text, with all HTML removed.";
362 function print_link_next() "Print the link to the next entry in this journal.";
363 function print_link_prev() "Print the link to the previous entry in this journal.";
364 function builtin viewer_sees_ebox() [fixed] : bool
365 "True if opaque horizontal site-specific content boxes between entries should be displayed to the user.";
366 function builtin print_ebox() [fixed]
367 "Prints a small horizontal bar of site-specific content between entries in a journal.";
369 function builtin is_eventrate_enable() : bool
370 "True if users can rate entry.";
371 function builtin get_eventratescounters() : int
372 "How many users rates this entry.";
373 function builtin get_eventrates() : UserLite[]
374 "Id list of users who rates this entry.";
375 function builtin is_myvoice() : bool
376 "Is my voice already counted by the system.";
379 class Comment extends EntryLite
380 "A comment to a journal entry, or to another comment."
382 var Image subject_icon "Subject icon, or null.";
383 var int talkid "Server stored ID number for this comment.";
384 var Comment[] replies "Comments replying to this comment.";
385 var bool full "True if all information is available for this comment. False if only the subject, poster, and date are available. (collapsed threads)";
386 var readonly string parent_url "URL to parent comment, or blank if a top-level comment.";
387 var readonly string reply_url "URL to reply to this comment.";
388 var readonly string thread_url "URL to view threaded rooted at this comment, or blank if comment has no children.";
389 var readonly bool screened "True if comment is in screened state.";
390 var readonly bool frozen "True if comment is in frozen state.";
391 var readonly bool deleted "True if comment has been deleted. Deleted comments still show up if they are the parent of a thread.";
392 var readonly string anchor "Direct link to comment, via HTML name anchors";
393 var readonly bool comment_posted "True if comment was just posted by the current user.";
394 var readonly bool edited "True if the comment has been edited.";
395 var readonly bool spam "This is spam message.";
397 var readonly DateTime time_remote "The local time the comment appeared, in the remote user's (reader's) timezone. Or undef if no remote user, or remote user hasn't set their timezone.";
398 var readonly DateTime time_poster "The local time the comment appeared, in the commenter's timezone. Or undef if anonymous comment, or commenter's timezone is unknown.";
399 var readonly int seconds_since_entry "The number of elapsed seconds from the time of the journal entry until the comment was initially posted.";
401 var readonly DateTime edittime "The GMT time the comment was edited. Or undef if the comment hasn't been edited.";
402 var readonly DateTime edittime_remote "The local time the comment was edited, in the remote user's (reader's) timezone. Or undef if no remote user, or remote user hasn't set their timezone, or the comment hasn't been edited.";
403 var readonly DateTime edittime_poster "The local time the comment was edited, in the commenter's timezone. Or undef if anonymous comment, or commenter's timezone is unknown, or the comment hasn't been edited.";
405 function builtin print_multiform_check "Prints the select checkbox in CSS class 'ljcomsel' with DOM id 'ljcomsel_\$talkid' for a multi-action form started with [method[EntryPage.print_multiform_start()]].";
407 function builtin print_reply_link(string{} opts) "Prints a link to reply to the comment. You may specify the link text in the 'linktext' option, and the link CSS class in 'class'. You may also specify the url of an image to use as a button in 'img_url'.";
409 function builtin print_reply_container() "Prints the area in which the quickreply box will go. If no container is available, quickreply will not work.";
411 function builtin print_reply_container(string{} opts) "Prints the area in which the quickreply box will go. You may 'class' which will be the CSS class used by the container. If no container is available, quickreply will not work.";
413 function builtin expand_link () : string "Returns a link to expand a collapsed comment. Uses the value of the 'text_comment_expand' property as the text. Will not work in untrusted layers.";
414 function builtin expand_link (string{} opts) : string "Returns a link to expand a collapsed comment. Can pass options 'text', 'title', 'class', and 'img_url' (and other 'img_*' options). Will not work in untrusted layers.";
416 function builtin print_expand_link () : string "Prints a link to expand a collapsed comment. Uses the value of the 'text_comment_expand' property as the text.";
417 function builtin print_expand_link (string{} opts) : string "Prints a link to expand a collapsed comment. Can pass options 'text', 'title', 'class', and 'img_url' (and other 'img_*' options).";
419 function builtin print_expand_collapse_links () "Prints links to expand and to collapse this comment.";
421 function time_display (string datefmt, string timefmt, bool edittime) : string "Same as EntryLite::time_display, except can pass in if we want the edit time or not.";
422 function edittime_display () : string "Show the time that this comment was edited, with most useful information for user. Empty string if the comment hasn't been edited.";
423 function edittime_display (string datefmt, string timefmt) : string "edittime_display, with customized date/time formats.";
425 function print_edit_text () "Print the text that says when this comment was edited.";
430 class Friend extends UserLite
431 "Represents a friends or friendof list"
433 var Color bgcolor "Background color selected for friend";
434 var Color fgcolor "Foreground color selected for friend";
437 class User extends UserLite
438 "A more information-rich userinfo structure"
440 var Image default_pic "Information about default userpic";
441 var readonly string userpic_listing_url "URL of a page listing this user's userpics";
442 var readonly string website_url "URL pointer to user's website";
443 var readonly string website_name "'pretty' name of user's website";
449 "A redirector makes either a GET URL which redirects to a pretty URL or an HTML form which posts to a URL that redirects to a pretty URL. This class exists because it's often desirable to use a form to end up at a URL, instead of doing a GET request. It's also used in cases where finding the previous or next URL would incur database overhead which would be wasteful, considering most people don't click previous/next links. Instead, the system will give you a Redirector object which has a URL that'll do the lookup for you later, followed by a redirect."
452 var readonly string user;
453 var readonly string vhost;
454 var readonly string type;
455 var readonly string url;
457 function start_form() "Starts an inline HTML form, then calls [method[Redirector.print_hiddens()]]. You can also make it yourself, using [member[Redirector.url]], if you need special form attributes.";
458 function print_hiddens() "Prints the necessary hidden elements for a form. Called automatically by [method[Redirector.start_form()]].";
459 function end_form() "Prints a form close tag.";
461 function builtin get_url(string redir_key) "Returns a GET URL, given a redir_key";
467 "Base template for all views"
469 var readonly string view "The view type (recent, friends, archive, month, day, entry)";
470 var readonly string{} args
471 "Arguments from the URL's query string (after the question mark). S2 code can only access arguments starting with a period, and this period is not included in the hash key.";
473 var User journal "User whose journal is being viewed";
474 var readonly string journal_type "Journal type, ex: 'P' (personal), 'C' (community), etc.";
475 var readonly string base_url "The base URL of the journal being viewed.";
476 var readonly string{} view_url
477 "Links to top-level views where id equals the name of the view being linked to.
478 (if one of views == \$.view, already looking at that view)";
480 var readonly string[] views_order "An array of view identifiers which can be used to order the views hash.";
481 var readonly string head_content
482 "Extra tags supplied by the server to go in the <head> section of the output HTML document. Layouts
483 should include this in the head section if they are writing HTML.";
485 var readonly string stylesheet_url
486 "The URL to use in a link element for the server-supported external stylesheet to put stuff in it)";
488 var readonly string global_title
489 "A title selected by the user for their whole journal.";
491 var readonly string global_subtitle
492 "A sub-title selected by the user for their whole journal.";
494 var readonly UserLink[] linklist
495 "An array of UserLink objects defined by the user to be displayed on their journal.";
497 var readonly DateTime time
498 "A DateTime object filled with the time (GMT) when the page was created.";
500 var Link{} data_link "Links to various machine-readable data sources relating to this page";
501 var string[] data_links_order "An array of data views which can be used to order the data_link hash";
504 "Set to true if need show only spam messages.";
506 var bool view_my_games
507 "View my games on profilepage.";
510 "The main entry point that LiveJournal calls. Layouts should override this to create HTML that's the
511 same for all view types, and use \$this->title, \$this->head and \$this->body to include view-specific
512 content into the template.";
514 function view_title : string
515 "Return a title for this particular page, such as \"Friends' Recent Entries\" for the friends view,
516 or a date for the day view. Should be overridden in i18n layers. Ideally, layout layers should never override
517 this. See [method[Page.title()]].";
519 function title : string
520 "Return a relevant combination of [member[Page.global_title]] and [method[Page.view_title()]]. May be
521 overridden in layout layers or left untouched for the core layer to handle.";
524 "Call from [method[Page.print()]] to render parts of the view that are specific to the view, eg print
525 the recent set of journal entries, recent friends entries, or rows of user information";
527 function print_head [fixed]
528 "Print server side supplied head content. This is a fixed function, so you can't override it. See
529 [method[Page.print_custom_head()]] if you want to supply custom head content.";
531 function builtin print_hbox_top [fixed]
532 "Prints an horizontal bar of site-specific content at the top of a journal.";
534 function builtin print_hbox_bottom [fixed]
535 "Prints an horizontal bar of site-specific content at the bottom of a journal.";
537 function builtin print_vbox [fixed]
538 "Prints an vertical bar of site-specific content on a journal.";
540 function builtin print_ad_box(string type) [fixed]
541 "Prints an side bar of site-specific content on a journal.";
543 function builtin print_ad(string type) [fixed]
544 "Deprecated function. Use print_hbox_(top|bottom) or print_vbox from now on.";
546 function builtin print_control_strip [fixed]
547 "Prints a control strip for the user's convenience";
549 function print_custom_head
550 "Layers can override this to add extra HTML to the head section of the HTML document.
551 Note that layouts are not intended to override this method.";
553 function print_linklist
554 "Print the list of UserLink objects specified by the user.";
556 function print_entry(Entry e)
557 "Output a journal entry. Layouts should override this and the inherited versions in RecentPage, FriendsPage
558 and DayPage to change how entries display.";
560 function print_entry_poster(Entry e)
561 "Output a line of text which says who posted an entry (just \"user\", or \"user posting in somejournal\")";
563 function builtin get_latest_month() : YearMonth
564 "Returns information about the latest month the user posted (or the current month, if no posts), so that the page may include a mini-calendar or similar features.";
566 function builtin visible_tag_list() : TagDetail[]
567 "Returns an array of tags that the logged in user can see for the journal being viewed.";
569 function builtin print_reply_link(string{} opts) "Prints a link to reply to the comment. You may specify the link text in the 'linktext' option, the link CSS class in 'class', and the target container in the 'target' option. You may also specify the url of an image to use as a button in 'img_url'.";
571 function builtin print_reply_container(string{} opts) "Prints the area in which the quickreply box will go. Options you may specify are 'target' which will be the target id, and 'class' which will be the CSS class used by the container. If no container is available, quickreply will not work.";
573 function builtin print_show_spam_button()
576 function print_stylesheets
577 "Prints all defined stylesheets, including default and user-defined ones.";
579 function builtin print_trusted(string key)
580 "Prints a trusted string by key.";
582 function builtin widget(string{} opts) : string
583 "Returns rendered widget body.";
585 function builtin render_widget(string{} opts)
586 "Prints rendered widget body.";
589 class TagsPage extends Page
590 "A detail page listing a user's tags."
592 var TagDetail[] tags "List of tags visible to the user viewing the page.";
595 class MessagePage extends Page
596 "A page showing an error or confirmation message."
598 var readonly string title "The title of the message.";
599 var readonly string message "The body of the message. Do not print this directly; use [method[MessagePage.print_body()]] instead.";
600 var Link{} links "An associative array of links to be displayed alongside this message. Iterate over [member[MessagePage.link_keyseq]] to find the keys.";
601 var string[] link_keyseq "A list of links, indicated by key, that should be displayed alongside this error. They should ideally be displayed in a similar way to the entry links displayed on the entry page.";
603 function print_message() [fixed] "Print the message. Call this rather than printing [member[MessagePage.message]] directly.";
604 function print_links() "Print the links from the [member[MessagePage.links]] and [member[MessagePage.link_keyseq]] members. Layouts will probably want to override this.";
608 "Navigation position within a [class[RecentPage]] or [class[FriendsPage]] and URLs to move about."
610 var int version "Currently version 1. A new method of navigation has been frequently discussed, so this is planning for the future";
612 # version 1 attributes:
613 var int skip "Indicates how many entries are being skipped back.";
614 var int count "Indicates how many entries we're currently seeing";
615 var readonly string forward_url "URL to go forward in time, or blank if furthest forward.";
616 var int forward_skip "Number of items we'd be skipping going forward.";
617 var int forward_count "Number of items we'd be potentially seeing going forward.";
618 var readonly string backward_url "URL to go backward in time, or blank if furthest back server will allow.";
619 var int backward_skip "Number of items we'd be skipping going back more.";
620 var int backward_count "Number of items we'd be potentially seeing going backward.";
623 class RecentPage extends Page
624 "Most recent entries page, formerly known as the LASTN view in the previous style system"
627 "Array of entries available to be seen by the viewer of the page.";
632 class FriendsPage extends RecentPage
633 "Friends most recent entries"
636 "A mapping from friend username to color association information. There will only be keys for friends whose entries are in the entries array.";
638 var readonly string friends_title
639 "A user-selected title for their friends page.";
641 var string friends_mode
642 "The 'mode' of this view. An empty string indicates a normal friends view, while 'friendsfriends' indicates the Friends-of-friends view.";
644 var bool filter_active
645 "If true, some kind of filter is in effect. If this filter has a name, it will be included in [member[FriendsPage.filter_name]]";
647 var string filter_name
648 "The name of the filter in effect, if it has a name. This is only used when 'custom' [member[FriendsPage.filter_active]] is true.";
651 class DayPage extends Page
652 "View entries by specific day"
654 var Date prev_date "Previous day";
655 var Date next_date "Next day";
656 var readonly string prev_url "URL to previous day";
657 var readonly string next_url "URL to next day";
658 var bool has_entries "True if there are entries on the specified day";
659 var Entry[] entries "Array of entries available to be seen by the viewer of the page";
660 var Date date "Date of the current day";
666 "Information on how to link to a year in the year archive"
668 var int year "Number of the year, eg 2001.";
669 var readonly string url "URL to link to for this year.";
670 var bool displayed "If this is the year currently being displayed, this will be true.";
674 "Information on how to link to a day in the year archive"
676 var int day "Day of month number";
677 var Date date "Date of day";
679 # http://zilla.livejournal.org/show_bug.cgi?id=504
680 # var bool is_today "True if the day represents the current day.";
682 var int num_entries "Number of entries made on this day";
683 var readonly string url "A URL to view the day, if there are entries, else blank.";
687 "Represents a week on the [class[YearMonth]] on the [class[YearPage]]."
689 var int pre_empty "How many days at the start of the week are blank? (From previous month)";
690 var int post_empty "How many days at the end of the week are blank? (From next month)";
691 var YearDay[] days "An array of the days of the week (0=sunday)";
694 "Print formatted week";
698 "A month on the [class[YearPage]]."
700 var bool has_entries "If this is false, you probably don't want to display this month.";
701 var int month "The number of the month";
702 var int year "The number of the year";
703 var YearWeek[] weeks "An array of the weeks of the month (for ease of building a row-per-week calendar)";
704 var readonly string url "A url to link to in order to view this month.";
705 var readonly string prev_url "A url to link to in order to view the previous month.";
706 var readonly string next_url "A url to link to in order to view the next month.";
707 var Date prev_date "Date of previous month, with day of zero, or null if none.";
708 var Date next_date "Date of next month, with day of zero, or null if none.";
710 function builtin month_format () : string
711 "Returns month formatted long (February 1980) /// SeeAlso: siteapi.core1.dateformats";
712 function builtin month_format (string fmt) : string
713 "Returns time formatted as indicated by \$fmt, or 'long' if blank. /// SeeAlso: siteapi.core1.dateformats";
716 class YearPage extends Page
717 "Entire calendar page for a single year."
719 var int year "The year being viewed";
720 var YearYear[] years "Information for linking to other years";
721 var YearMonth[] months "12 months objects, even if no entries are in that month.";
723 function print_month(YearMonth m)
724 "Print the calendar cell for the given month";
726 function print_year_links()
727 "Print the navigation links to move between years";
730 class MonthDay extends YearDay
731 "Summaries of posts on a given day on the [class[MonthPage]]."
733 var bool has_entries "True if there are entries on this day.";
734 var Entry[] entries "Only populated on the month view. Entry text not present.";
736 function print_subjectlist
737 "Print a list of entry summaries including subjects";
741 "A month the user has journal entries, along with information to link to it."
743 var Date date "Date of month, with day of zero.";
744 var readonly string url "URL for the [class[MonthPage]] month view.";
745 var readonly string redir_key "The 'redir_key' parameter for a [class[Redirector]] instance.";
748 class MonthPage extends Page
749 "A page which contains a list of posts made in that month"
751 var Date date "Date of this month, with day of zero.";
752 var MonthDay[] days "One entry for each day of the month.";
753 var MonthEntryInfo[] months "Other months this journal has entries.";
754 var Date prev_date "Date of previous month, with day of zero, or null if none.";
755 var Date next_date "Date of next month, with day of zero, or null if none.";
756 var readonly string prev_url "URL of previous month, or empty string if none.";
757 var readonly string next_url "URL of next month, or empty string if none.";
758 var Redirector redir "Necessary to make a form which POSTs to a redirector";
761 class EntryPage extends Page
762 "A page with a single journal entry and associated comments."
764 var Entry entry "Journal entry being viewed";
765 var ItemRange comment_pages "Represents what comment page is being displayed.";
766 var Comment[] comments "Comments to journal entry, or at least some of them.";
767 var bool viewing_thread "True if viewing a specific sub-thread of the comments. Style may which to hide the journal entry at this point, since the focus is the comments.";
769 function print_comments(Comment[] comments) "Prints comments";
770 function print_comment(Comment comment) "Prints a full comment";
771 function print_comment_full(Comment comment) "Prints a expanded comment";
772 function print_comment_partial(Comment comment) "Prints a collapsed comment";
774 var bool multiform_on "Set to true if the multi-action is to be printed, which requires both comments and applicable permissions for the remote user.";
775 function builtin print_multiform_start "Prints start of form tag and hidden elements to do a multi-comment action (multiple delete, screen, unscreen, etc...)";
776 function builtin print_multiform_end "Prints end of form tag to do a multi-comment action.";
777 function builtin print_multiform_actionline "Prints the line of the multiform giving instructions, options, and the submit button, using the text of the different \$*text_multiform_ properties.";
781 "This class will be used more in the future to set options on the reply form before
782 it's printed out by the system. The system has to print it since it contains
783 sensitive information which can't be made available to S2."
785 var readonly bool subj_icons "Whether user has enabled subject icons or not. Currently read-only until policy is decided on whether layers should be able to change it (rather than changing it in the user preferences)";
786 function builtin print() "Prints the reply form";
789 class ReplyPage extends Page
790 "A page to reply to a journal entry or comment"
792 var Entry entry "The journal entry for this talk page";
793 var EntryLite replyto "The object which is being replied to, either the entry or a comment";
794 var ReplyForm form "The reply form.";
798 "A specification for a numbered palette index in a GIF or PNG to be changed to a certain color"
800 var int index "Integer palette index.";
801 var Color color "Color to put at specified index.";
804 ##[ Built-in Functions ]
806 function builtin eurl (string s) : string
809 function builtin ehtml (string s) : string
810 "Escapes all HTML tags and entities from the text";
812 function builtin etags (string s) : string
813 "Escapes all HTML tags (but not entities) from text";
815 function builtin clean_url (string s) : string
816 "Returns the given URL back if it's a valid URL.";
818 function builtin rand (int high) : int
819 "Returns a random integer between 1 and \$high, inclusive.";
821 function builtin rand (int low, int high) : int
822 "Returns a random integer between \$low and \$high, inclusive.";
824 function builtin pageview_unique_string () : string
825 "Returns a unique string for the remote user.";
827 function builtin alternate (string a, string b) : string
828 "With each call, this function will alternate between the two values and return one of them.
829 Useful for making tables whose rows alternate in background color.";
831 function builtin zeropad (int n, int digits) : string
832 "Returns the number padded with zeroes so it has the amount of digits indicated.";
834 function builtin zeropad (string n, int digits) : string
835 "Returns the number padded with zeroes so it has the amount of digits indicated.";
837 function builtin striphtml (string s) : string
838 "Similar to ehtml, but the HTML tags are stripped rather than escaped.";
840 function builtin viewer_logged_in() : bool
841 "Returns true if the user viewing the page is logged in. It's recommended that your page links to the site
842 login page if the user isn't logged in.";
844 function builtin viewer_is_owner() : bool
845 "Returns true if the user viewing the page is both logged in, and is the owner of the content in question.
846 Useful for returning links to manage information, or edit entries.";
848 function builtin viewer_is_friend() : bool
849 "Returns true if the user viewing the page is both logged in, and is a friend of the journal being viewed. Always returns false for communities, since they cannot have friends.";
851 function builtin viewer_is_member() : bool
852 "Returns true if the user viewing the page is both logged in, and is a member of the community being viewed. Always returns false for personal journals, since they cannot have members.";
854 function builtin viewer_sees_ads() [fixed] : bool
855 "Deprecated function. Use viewer_sees_hbox_(top|bottom) or viewer_sees_vbox from now on.";
857 function builtin viewer_sees_vbox() [fixed] : bool
858 "True if opaque vertical site-specific content box should be displayed to the user.";
860 function builtin viewer_sees_hbox_top() [fixed] : bool
861 "True if opaque horizontal site-specific content box should be displayed to the user at the top of the page.";
863 function builtin viewer_sees_hbox_bottom() [fixed] : bool
864 "True if opaque horizontal site-specific content box should be displayed to the user at the bottom of the page.";
866 function builtin viewer_sees_ad_box(string type) [fixed] : bool
867 "True if opaque sidebar site-specific content box should be displayed to the user.";
869 function builtin viewer_sees_ebox() [fixed] : bool
870 "True if the user has selected to see opaque content boxes between entries.";
872 function builtin viewer_sees_control_strip [fixed] : bool
873 "Returns true if reader will see the built in control strip.";
875 function builtin control_strip_logged_out_userpic_css [fixed] : string
876 "Returns CSS for the userpic div in the logged out version of the control strip.";
878 function builtin control_strip_logged_out_full_userpic_css [fixed] : string
879 "Returns CSS for the loggedout_userpic div in the logged out version of the control strip.";
881 function builtin get_page () : Page
882 "Gets the top-level [class[Page]] instance that LiveJournal ran the [method[Page.print()]] method on.";
884 function builtin get_url(string user, string view) : string
885 "Returns a URL to the specified view for the specified user. Views use the same names as elsewhere. (recent, friends, archive, month, userinfo, usergames)";
887 function builtin get_url(UserLite user, string view) : string
888 "Returns a URL to the specified view for the specified user. Views use the same names as elsewhere. (recent, friends, archive, month, userinfo, usergames)";
890 function builtin string(int i) : string
891 "Return the given integer as a string";
893 function builtin int(string s) : int
894 "Convert the string to an integer and return";
896 function builtin set_content_type(string text)
897 "Set the HTTP Content-type response header (for example, if outputting XML). Must be called before printing any data.";
899 function builtin get_plural_phrase(int n, string prop) : string
900 "Picks the phrase with the proper plural form from those in the property \$prop, passing \$n to [function[lang_map_plural(int)]] to get the proper form for the current language, and then substituting the # character with \$n. Also, returned string is HTML-escaped.";
902 function builtin weekdays() : int[]
903 "Integers representing the days of the week. This will start on Monday (2) or Sunday (1) depending on the property setting for start-of-week and go to Sunday (1) or Saturday (7)";
905 function builtin PalItem(int index, Color c) : PalItem
906 "Convenience constructor to make populating an array of PalItems (like in [function[palimg_modify(string,PalItem[])]]) easy.";
909 function builtin UserLite(string username) : UserLite
910 "Constructor for making a UserLite object from a username";
912 function builtin palimg_modify(string filename, PalItem[] items) : string
913 "Return a URL to the specified filename (relative to the palimg root) with its palette table altered, once for each provided [class[PalItem]]. Restrictions: only 7 palette entries may be modified, and the PalItem indexes must be 0-15.";
915 function builtin palimg_tint(string filename, Color bright) : string
916 "Return a URL to the specified filename (relative to the palimg root) with its palette table tinted. The given 'bright' color will be the new white, and darkest color remains black.";
918 function builtin palimg_tint(string filename, Color bright, Color dark) : string
919 "Return a URL to the specified filename (relative to the palimg root) with its palette table tinted. The given 'bright' color will be the new white, and the given 'dark' color is the new black.";
921 function builtin palimg_gradient(string filename, PalItem start, PalItem end) : string
922 "Return a URL to the specified filename (relative to the palimg root) with its palette table made into a gradient. All palette entries between the inclusive indexes of \$start and \$end will fade from the colors in \$start and \$end. The palette indexes for the start and end can be between 0 and 255.";
924 function builtin set_handler(string eventname, string[][] commands);
926 function builtin userlite_base_url(UserLite ul) : string;
927 function builtin userlite_as_string(UserLite ul) : string "Deprecated function. Use ljuser() from now on.";
929 function builtin start_css () "Declare that you're about to start printing out CSS that should be buffered, then later cleaned when you call end_css(). WARNING: this is not re-entrant. You can't call start_css recursively.";
930 function builtin end_css () "Declare that you're done printing CSS and the output thus buffered should be cleaned and printed.";
932 function builtin journal_current_datetime() : DateTime
933 "Returns the current datetime in the timezone of the journal being viewed.";
935 function builtin style_is_active() : bool
936 "Returns if the style (layout and theme) calling it is active based on a hook. If hook isn't defined, returns true always.";
940 propgroup colors = "Colors";
941 propgroup fonts = "Fonts";
942 propgroup presentation = "Presentation";
943 propgroup other = "Other";
944 propgroup text = "Text";
945 propgroup background = "Background";
946 propgroup sidebar = "Sidebar";
947 propgroup appearance = "Appearance";
948 propgroup options = "Options";
949 propgroup images = "Images";
950 propgroup customcss = "Custom CSS";
952 property string lang_current {
954 des = "Current language code. So layouts can change date/time formats more safely if they want.";
956 set lang_current = "en"; # core is English.
958 property string lang_fmt_date_short {
960 des = "Short date format. All numeric.";
962 set lang_fmt_date_short = "%%m%%/%%d%%/%%yy%%";
964 property string lang_fmt_date_med {
966 des = "Medium date format. Abbreviated month name, no day of the week.";
968 set lang_fmt_date_med = "%%mon%%. %%dayord%%, %%yyyy%%";
970 property string lang_fmt_date_med_day {
972 des = "Medium date format with day of week. Abbreviated month name and abbreviated day of the week.";
974 set lang_fmt_date_med_day = "%%da%%, %%mon%%. %%dayord%%, %%yyyy%%";
976 property string lang_fmt_date_long {
978 des = "Long date format. With full month name, but no day of the week.";
980 set lang_fmt_date_long = "%%month%% %%dayord%%, %%yyyy%%";
982 property string lang_fmt_date_long_day {
984 des = "Long date format. With full month name and full day of the week.";
986 set lang_fmt_date_long_day = "%%day%%, %%month%% %%dayord%%, %%yyyy%%";
988 property string lang_fmt_time_short {
990 des = "Time format.";
992 set lang_fmt_time_short = "%%hh%%:%%min%% %%a%%m";
994 property string lang_fmt_month_short {
996 des = "Short month format.";
998 set lang_fmt_month_short = "%%m%%/%%yy%%";
1000 property string lang_fmt_month_med {
1002 des = "Medium month format.";
1004 set lang_fmt_month_med = "%%mon%% %%yyyy%%";
1006 property string lang_fmt_month_long {
1008 des = "Long month format.";
1010 set lang_fmt_month_long = "%%month%% %%yyyy%%";
1012 property string[] lang_monthname_long {
1014 des = "Months of the year. Indexed from 1 (January) to 12 (December).";
1016 set lang_monthname_long = [ "", "January", "February", "March",
1017 "April", "May", "June",
1018 "July", "August", "September",
1019 "October", "November", "December" ];
1021 property string[] lang_monthname_short {
1023 des = "Months of the year, in their short forms. Indexed from 1 (Jan) to 12 (Dec).";
1025 set lang_monthname_short = [ "", "Jan", "Feb", "Mar",
1026 "Apr", "May", "Jun",
1027 "Jul", "Aug", "Sep",
1028 "Oct", "Nov", "Dec" ];
1030 property string[] lang_dayname_long {
1032 des = "Days of the week. Indexed from 1 (Sunday) to 7 (Saturday).";
1034 set lang_dayname_long = [ "", "Sunday", "Monday", "Tuesday", "Wednesday",
1035 "Thursday", "Friday", "Saturday" ];
1037 property string[] lang_dayname_short {
1039 des = "Days of the week, in their short forms. Indexed from 1 (Sun) to 7 (Sat).";
1041 set lang_dayname_short = [ "", "Sun", "Mon", "Tue", "Wed",
1042 "Thu", "Fri", "Sat" ];
1044 property string[] lang_dayname_shorter {
1046 des = "Days of the week, in their one letter forms. Indexed from 1 (S) to 7 (S).";
1048 set lang_dayname_shorter = [ "", "S", "M", "T", "W",
1051 property builtin string IMGDIR {
1053 doc_flags = "[sys]";
1054 des = "The base URL of the current LiveJournal site's image directory, without a trailing slash. Example: \"http://www.livejournal.com/img\".";
1056 property builtin string STATDIR {
1058 doc_flags = "[sys]";
1059 des = "The base URL of the current LiveJournal site's static files directory, without a trailing slash. Example: \"http://www.livejournal.com/stc\".";
1061 property builtin string SITENAME {
1063 doc_flags = "[sys]";
1064 des = "Name of the current LiveJournal site. Example: \"LiveJournal.com\".";
1067 property builtin string SITENAMESHORT {
1069 doc_flags = "[sys]";
1070 des = "Shorter name of the current LiveJournal site. Example: \"LiveJournal\".";
1073 property builtin string SITENAMEABBREV {
1075 doc_flags = "[sys]";
1076 des = "Abbreviation of the current LiveJournal site. Example: \"LJ\".";
1079 property builtin string SITEROOT {
1081 doc_flags = "[sys]";
1082 des = "The base URL of the current LiveJournal site, without a trailing slash. Example: \"http://www.livejournal.com\".";
1085 property builtin string PALIMGROOT {
1087 doc_flags = "[sys]";
1088 des = "The base URL of palimg files, without a trailing slash. Example: \"http://www.livejournal.com/palimg\".";
1091 property int page_recent_items {
1092 des = "Number of journal entries to show on recent entries page";
1093 doc_flags = "[construct]";
1097 property int page_friends_items {
1098 des = "Number of journal entries to show on friends page";
1099 doc_flags = "[construct]";
1103 set page_recent_items = 10;
1104 set page_friends_items = 10;
1106 property string page_day_sortorder {
1107 des = "Order of entries shown on a day page";
1108 values = "forward|Least recent first|reverse|Most recent first";
1110 property string page_year_sortorder {
1111 des = "Order of months shown on the year archive page";
1112 values = "forward|Least recent first|reverse|Most recent first";
1114 set page_day_sortorder = "forward";
1115 set page_year_sortorder = "forward";
1117 property bool page_month_textsubjects {
1118 des = "If set, subjects will be provided for the month view in plain text only, with HTML removed.";
1119 doc = "If set, subjects will be provided for the [class[MonthPage]] in plain text only, with HTML removed.";
1121 set page_month_textsubjects = true;
1123 property string text_meta_music {
1124 des = "Text for 'Current Music'";
1126 set text_meta_music = "Current Music";
1128 property string text_meta_mood {
1129 des = "Text for 'Current Mood'";
1131 set text_meta_mood = "Current Mood";
1133 property string text_meta_location {
1134 des = "Text for 'Current Location'";
1136 set text_meta_location = "Current Location";
1138 property string text_meta_groups {
1139 des = "Text for 'Custom Friends Groups'";
1141 set text_meta_groups = "Custom Friends Groups";
1143 property string text_copyr_agree {
1144 des = "Text for copyright post agree"; }
1145 set text_copyr_agree= "Hereinafter I give my permission to reproduce in any form";
1147 property string text_copyr_disagree {
1148 des = "Text for copyright post disagree"; }
1149 set text_copyr_disagree= "The reproduction is prohibited in any form";
1152 property string text_post_comment {
1153 des = "Link text to leave a comment";
1154 example = "Leave a comment";
1156 property string text_max_comments {
1157 des = "Text when entry has reached a comment maximum";
1158 example = "Maximum comments reached";
1160 property string text_read_comments {
1161 des = "Link text to read comments";
1163 example = "1 comment // # comments";
1165 property string text_read_all_comments {
1166 des = "Link text to read all comments";
1168 example = "Read 1 comment // Read # comments";
1170 set text_post_comment = "Leave a comment";
1171 set text_max_comments = "Maximum comments reached";
1172 set text_read_comments = "1 comment // # comments";
1173 set text_read_all_comments = "Read 1 comment // Read # comments";
1175 property string text_read_spam_comments {
1176 des = "Link text to read spam comments";
1178 example = "1 spam comment // # spam comments";
1180 property string text_read_all_spam_comments {
1181 des = "Link text to read all spam comments";
1183 example = "Read 1 spam comment // Read # spam comments";
1185 set text_read_spam_comments = "1 spam comment // # spam comments";
1186 set text_read_all_spam_comments = "Read 1 spam comment // Read # spam comments";
1188 property string text_post_comment_friends {
1189 des = "Link text to leave a comment on friends view entry";
1190 example = "Leave a comment";
1192 property string text_read_comments_friends {
1193 des = "Link text to read comments on a friends view entry";
1195 example = "1 comment // # comments";
1197 set text_post_comment_friends = "Leave a comment";
1198 set text_read_comments_friends = "1 comment // # comments";
1200 property string text_showspam {
1201 des = "Show spam messages";
1202 example = "Show spam";
1204 property string text_hidespam {
1205 des = "Hide spam messages";
1206 example = "Hide spam";
1208 set text_showspam = "Show spam";
1209 set text_hidespam = "Hide spam";
1211 property string text_spam_comment {
1212 des = "Spam comment messages";
1213 example = "Spam comment";
1215 set text_spam_comment = "(Spam comment)";
1217 property string text_view_games {
1218 des = "Text for view games on profile page";
1219 example = "My Games";
1221 set text_view_games = "My Games";
1223 property string text_tags_page_header {
1224 des = "Text for the header of the Tags page";
1225 example = "Visible Tags";
1227 set text_tags_page_header = "Visible Tags";
1229 property string text_tag_uses {
1230 des = "Text to show how many times a tag has been used";
1232 example = "1 use // # uses";
1234 set text_tag_uses = "1 use // # uses";
1236 property string text_skiplinks_back {
1237 des = "Text to show in a link to skip back through entries";
1240 example = "Go back #";
1241 note = "Include a # character to insert the number of entries that will be viewable when skipping back.";
1243 property string text_skiplinks_forward {
1244 des = "Text to show in a link to skip forward through entries";
1247 example = "Go forward #";
1248 note = "Include a # character to insert the number of entries that will be viewable when skipping forward.";
1250 property string text_skiplinks_forward_words {
1251 des = "Text to show in a link to skip forward through entries";
1254 example = "Go forward";
1256 set text_skiplinks_back="Previous #";
1257 set text_skiplinks_forward="Next #";
1259 property string text_view_recent {
1260 des = "Text used to link to the 'Recent Entries' view";
1263 example = "Recent Posts";
1265 property string text_view_friends {
1266 des = "Text used to link to the 'Friends' view";
1269 example = "My Friends' Entries";
1271 property string text_view_friends_comm {
1272 des = "Text used to link to the 'Friends' view for a community";
1275 example = "Members' Journals";
1277 property string text_view_friendsfriends {
1278 des = "Title of the 'Friends of Friends' view";
1281 example = "Friends of Friends";
1283 property string text_view_friends_filter {
1284 des = "Title of a Friends page with an unnamed filter in effect";
1287 example = "Friends (Custom filter)";
1289 property string text_view_friendsfriends_filter {
1290 des = "Title of a Friends of Friends page with an unnamed filter in effect";
1293 example = "Friends of Friends (Custom filter)";
1295 property string text_view_archive {
1296 des = "Text used to link to the 'Archive' view";
1299 example = "Journal Archive";
1301 property string text_view_userinfo {
1302 des = "Text used to link to the 'User Information' view";
1305 example = "My Profile";
1308 property string text_view_usergames {
1309 des = "Text used to link to the 'My Games' view";
1312 example = "My Games";
1315 property string text_view_memories {
1316 des = "Text used to link to the 'Memories' view";
1319 example = "My Memories";
1322 property string text_view_month {
1323 des = "Text used to link to a list of subjects for a month";
1326 example = "View Subjects";
1328 set text_view_recent = "Recent Entries";
1329 set text_view_friends = "Friends";
1330 set text_view_friends_comm = "Members";
1331 set text_view_friends_filter = "Friends (Custom filter)";
1332 set text_view_friendsfriends = "Friends of Friends";
1333 set text_view_friendsfriends_filter = "Friends of Friends (Custom filter)";
1334 set text_view_archive = "Archive";
1335 set text_view_userinfo = "User Info";
1336 set text_view_usergames = "My Games";
1337 set text_view_memories = "Memories";
1338 set text_view_month = "View Subjects";
1340 property string text_links {
1341 des = "Text used for the heading of the links list";
1346 set text_links = "Links";
1348 property string text_page_summary {
1349 des = "Text used for the heading for the Page Summary navigation section";
1352 example = "Entries on This Page";
1354 set text_page_summary = "Page Summary";
1356 property string text_syndicate {
1357 des = "Text used for the heading for the Syndication navigation section";
1360 example = "Subscribe to my feeds";
1362 set text_syndicate = "Syndicate";
1364 property string text_nosubject {
1365 des = "Text to replace a subject line when no subject is specified";
1368 example = "No Subject";
1369 note = "This only appears in places where a subject line is required, such as on a month view.";
1371 set text_nosubject = "(no subject)";
1373 property string text_noentries_recent {
1374 des = "Text to display when there are no entries on the recent or friends views";
1378 set text_noentries_recent = "There are no entries to display.";
1380 property string text_noentries_day {
1381 des = "Text to display when there are no entries on the day view";
1385 set text_noentries_day = "There were no entries on this day.";
1387 property string text_entry_prev {
1388 des = "Text to link to the previous entry";
1390 set text_entry_prev = "Previous Entry";
1392 property string text_entry_next {
1393 des = "Text to link to the next entry";
1395 set text_entry_next = "Next Entry";
1397 property string text_permalink {
1398 des = "Text for an entry's permanent link";
1402 set text_permalink = "Link";
1404 property string text_edit_entry {
1405 des = "Text to edit an entry";
1407 set text_edit_entry = "Edit Entry";
1409 property string text_edit_tags {
1410 des = "Text to edit tags for an entry";
1412 set text_edit_tags = "Edit Tags";
1414 property string text_tell_friend {
1415 des = "Text to tell a friend about an entry";
1417 set text_tell_friend = "Tell a Friend";
1419 property string text_share_this {
1420 des = "Text to share this with a friend";
1422 set text_share_this = "Share this!";
1424 property string text_share {
1425 des = "Text to share this with a friend";
1427 set text_share = "Share";
1429 property string text_share_facebook {
1430 des = "Text to share this with a friend on Facebook";
1432 set text_share_facebook = "Post to Facebook";
1434 property string text_share_twitter {
1435 des = "Text to share this with a friend on Twitter";
1437 set text_share_twitter = "Tweet this";
1439 property string text_share_email {
1440 des = "Text to share this with a friend by mail";
1442 set text_share_email = "Send by e-mail";
1444 property string text_mem_add {
1445 des = "Text to add an entry into memories";
1447 set text_mem_add = "Add to Memories";
1449 property string text_watch_comments {
1450 des = "Text to track events on an entry";
1452 set text_watch_comments = "Track This";
1454 property string text_unwatch_comments {
1455 des = "Text to stop tracking events on an entry";
1457 set text_unwatch_comments = "Untrack This";
1459 property string text_flag {
1460 des = "Text to flag an entry";
1462 set text_flag = "Flag";
1464 property string text_month_screened_comments {
1465 des = "Text to indicate there are screened comments";
1467 set text_month_screened_comments = "w/ Screened";
1469 property string text_month_form_btn {
1470 des = "Text used for Submit button in MonthPage selector";
1472 set text_month_form_btn = "View";
1474 property string text_replyform_header {
1475 des = "Text for the heading above the form on the reply page";
1477 set text_replyform_header = "Comment Form";
1479 property string text_multiform_check {
1480 des = "Text beside a comment multi-action checkbox";
1482 set text_multiform_check = "Select:";
1484 property string text_multiform_des {
1485 des = "Text on the multiform action line.";
1487 set text_multiform_des = "Mass action on comments:";
1489 property string text_multiform_btn {
1490 des = "Text on the multiform action button.";
1492 set text_multiform_btn = "Perform Action";
1494 property string text_multiform_opt_spam {
1495 des = "Text for the comment mark as spam action";
1497 set text_multiform_opt_spam = "Spam";
1499 property string text_multiform_opt_unspam {
1500 des = "Text for the comment mark as unspam action";
1502 set text_multiform_opt_unspam = "Unspam";
1504 property string text_multiform_opt_unscreen {
1505 des = "Text for the comment unscreening action";
1507 set text_multiform_opt_unscreen = "Unscreen";
1509 property string text_multiform_opt_unscreen_to_reply {
1510 des = "Text for the comment unscreening action it's showed instead of reply-link for screened comments";
1512 set text_multiform_opt_unscreen_to_reply = "Unscreen to reply";
1514 property string text_multiform_opt_screen {
1515 des = "Text for the comment screening action";
1517 set text_multiform_opt_screen = "Screen";
1519 property string text_multiform_opt_unfreeze {
1520 des = "Text for the comment unfreezing action";
1522 set text_multiform_opt_unfreeze = "Unfreeze";
1524 property string text_multiform_opt_freeze {
1525 des = "Text for the comment freezing action";
1527 set text_multiform_opt_freeze = "Freeze";
1529 property string text_multiform_opt_delete {
1530 des = "Text for the comment delete action";
1532 set text_multiform_opt_delete = "Delete";
1534 property string text_multiform_opt_deletespam {
1535 des = "Text for the comment delete and mark as spam action";
1537 set text_multiform_opt_deletespam = "Delete as Spam";
1539 property string text_multiform_conf_delete {
1540 des = "Text for the confirming mass-delete action";
1542 set text_multiform_conf_delete = "Delete selected comments?";
1544 property string text_multiform_no_comments {
1545 des = "Text if no comments for mass-action are selected";
1547 set text_multiform_no_comments = "You have not selected any comments";
1549 property string text_multiform_no_action {
1550 des = "Text if no mass-action selected";
1552 set text_multiform_no_action = "You have not selected one of the actions";
1554 property string text_multiform_opt_track {
1555 des = "Text for the comment tracking action";
1557 set text_multiform_opt_track = "Track This";
1559 property string text_multiform_opt_untrack {
1560 des = "Text for the comment untracking action";
1562 set text_multiform_opt_untrack = "Untrack This";
1564 property string text_multiform_opt_edit {
1565 des = "Text for the comment editing action";
1567 set text_multiform_opt_edit = "Edit";
1569 property string text_multiform_opt_selected {
1570 des = "Text for drop-down: Sub-header for action on selected comments";
1572 set text_multiform_opt_selected = "Selected";
1574 property string text_multiform_opt_all {
1575 des = "Text for drop-down: Sub-header for action on all comments";
1577 set text_multiform_opt_all = "All";
1579 property string text_multiform_opt_please {
1580 des = "Text for drop-down: Invitation to choosing mass action on comments";
1582 set text_multiform_opt_please = "(Select action)";
1584 property string text_comment_posted {
1585 des = "Text to display when a comment has just been posted by the user";
1587 set text_comment_posted = "Comment successfully posted.";
1589 property string text_tags {
1590 des = "Text for 'Tags' header for an entry";
1591 note = "Use a # where you want the tag list inserted.";
1592 example = "Tags: #";
1594 set text_tags = "Tags: #";
1596 property string text_tags_section_header {
1597 des = "Text for the 'Tags' heading in the navigation area";
1600 example = "My tags";
1602 set text_tags_section_header = "Tags";
1604 property string font_base {
1605 des = "Preferred Font";
1609 note = "Leave blank if you don't care.";
1611 set font_base = ""; # In core, default is not to care. Layouts will probably specify fonts the author likes instead.
1613 property string font_fallback {
1614 des = "Alternative font style";
1615 values = "sans-serif|Sans-serif|serif|Serif|cursive|Cursive|monospace|Monospaced|none|Use browser's default";
1616 note = "This general style will serve as a fallback if your preferred font is unavailable.";
1618 set font_fallback = "none"; # Default in core is to let the browser handle it.
1620 property string reg_firstdayofweek {
1621 des = "The day of the week the calendar weeks starts on.";
1622 doc = "The day of the week the calendar weeks starts on. Either 'sunday' or 'monday'.";
1623 doc_flags = "[construct]";
1624 values = "sunday|Sunday|monday|Monday";
1626 set reg_firstdayofweek = "sunday";
1628 property string text_day_prev {
1629 des = "Text to link to the previous day";
1630 example = "Previous Day";
1633 property string text_day_next {
1634 des = "Text to link to the next day";
1635 example = "Next Day";
1638 set text_day_prev = "Previous Day";
1639 set text_day_next = "Next Day";
1641 property string text_comment_from {
1642 des = "Text of the 'from' header in comments";
1646 property string text_comment_date {
1647 des = "Text of the 'date' header in comments";
1651 property string text_comment_ipaddr {
1652 des = "Text of the 'IP Address' header in comments";
1653 example = "IP Address:";
1656 property string text_comment_edittime {
1657 des = "Text of the 'Edited at' string at the bottom of edited comments";
1658 example = "Edited at:";
1661 set text_comment_from = "From:";
1662 set text_comment_date = "Date:";
1663 set text_comment_ipaddr = "IP Address:";
1664 set text_comment_edittime = "Edited at";
1666 property string text_comment_reply {
1667 des = "Text to link to reply for comment";
1668 example = "Reply to this";
1671 property string text_comment_frozen {
1672 des = "Text to replace reply link with if comment is frozen";
1673 example = "Replies frozen";
1676 property string text_comment_deleted {
1677 des = "Text to replace comment body, if it is deleted";
1678 example = "(Deleted)";
1681 property string text_comment_screened {
1682 des = "Text to replace comment body, if it is screened";
1683 example = "(Screened)";
1686 property string text_comment_parent {
1687 des = "Text to link to parent comment of current comment";
1691 property string text_comment_thread {
1692 des = "Text to link to the thread stemming from the comment";
1696 property string text_comment_expand {
1697 des = "Text to expand a collapsed comment thread";
1701 property string text_comment_collapse {
1702 des = "Text to collapse a expanded comment thread";
1703 example = "Collapse";
1706 set text_comment_reply = "Reply";
1707 set text_comment_frozen = "Frozen";
1708 set text_comment_deleted = "(Deleted comment)";
1709 set text_comment_screened = "(Screened comment)";
1710 set text_comment_parent = "Parent";
1711 set text_comment_thread = "Thread";
1712 set text_comment_expand = "Expand";
1713 set text_comment_collapse = "Collapse";
1715 property string text_poster_anonymous {
1716 des = "The placeholder used when something is posted by an anonymous user";
1717 example = "(Anonymous)";
1719 set text_poster_anonymous = "(Anonymous)";
1721 property string text_reply_back {
1722 des = "Text to link back to the single entry view from the read comments page";
1723 example = "Read Comments";
1726 set text_reply_back = "Read Comments";
1728 property string text_reply_nocomments_header {
1729 des = "Heading text that explains that comments are disabled";
1730 example = "Comments Disabled:";
1733 set text_reply_nocomments_header = "Comments Disabled:";
1735 property string text_reply_nocomments {
1736 des = "Text that explains that comments are not allowed for this post.";
1737 example = "Comments have been disabled for this post.";
1740 set text_reply_nocomments = "Comments have been disabled for this post.";
1742 property string text_website_default_name {
1743 des = "If an account's website is specified, but there's no website name, use this text instead";
1746 set text_website_default_name = "My Website";
1748 property string text_icon_alt_protected {
1749 des = "Alternative text for icons of friends-only entries";
1752 property string text_icon_alt_private {
1753 des = "Alternative text for icons of private entries";
1756 property string text_icon_alt_groups {
1757 des = "Alternative text for icons of custom friends group entries";
1760 set text_icon_alt_protected = "[protected post]";
1761 set text_icon_alt_private = "[private post]";
1762 set text_icon_alt_groups = "[custom friends groups post]";
1764 property string comment_form_text_hint {
1765 des = "Text hint for comment message";
1768 property bool use_shared_pic {
1769 des = "Use community userpics instead of poster's userpic.";
1771 set use_shared_pic = false;
1773 property bool view_entry_disabled {
1774 des = "Disable customized comment pages for your journal";
1776 set view_entry_disabled = false;
1778 property bool tags_aware {
1779 des = "When enabled, style is responsible for handling tags. When disabled, tags are automatically inserted into entry bodies.";
1782 set tags_aware = false;
1784 property Color color_comment_bar {
1785 des = "Color of comment bar header";
1787 set color_comment_bar = "#d0d0ff";
1789 property string comment_userpic_style {
1790 des = "Userpic display style for comments";
1791 doc = "Userpic display style for comments. Either '' for full, 'small' for small, or 'off' for none.";
1792 doc_flags = "[construct]";
1793 values = "|Full|small|Small|off|Off";
1795 set comment_userpic_style = "";
1797 property bool linklist_support {
1798 des = "Display link list";
1800 set linklist_support = true;
1802 property bool external_stylesheet {
1803 des = "Use linked stylesheet";
1804 note = "If true, a stylesheet link element will point to a file containing the layout's CSS data.";
1807 set external_stylesheet = false;
1809 property bool include_default_stylesheet {
1810 des = "Use layout's stylesheet(s)";
1811 note = "Disable this only if you want to re-style this layout completely from scratch using a custom stylesheet.";
1813 set include_default_stylesheet = true;
1815 property string linked_stylesheet {
1816 des = "Custom external stylesheet URL";
1817 note = "If you have a custom external stylesheet that you'd like to use, enter its URL here.";
1819 set linked_stylesheet = "";
1821 property string custom_css {
1822 des = "Custom stylesheet";
1823 note = "If you'd like to add custom CSS to this style, enter it here.";
1826 string_mode = "css";
1828 set custom_css = "";
1830 property string custom_control_strip_colors {
1831 des = "Navigation strip colors";
1832 values = "off|Do not use custom colors|on_gradient|Use custom colors with a background gradient|on_no_gradient|Use custom colors without a background gradient";
1833 note = "Custom colors can be set in the \"Colors\" section.";
1835 set custom_control_strip_colors = "off";
1837 property Color control_strip_bgcolor {
1838 des = "Background color of navigation strip";
1839 note = "If you don't enable custom navigation strip colors in the \"Presentation\" section, this won't have any effect.";
1841 set control_strip_bgcolor = "";
1843 property Color control_strip_fgcolor {
1844 des = "Text color of navigation strip";
1845 note = "If you don't enable custom navigation strip colors in the \"Presentation\" section, this won't have any effect.";
1847 set control_strip_fgcolor = "";
1849 property Color control_strip_bordercolor {
1850 des = "Border color of navigation strip";
1851 note = "If you don't enable custom navigation strip colors in the \"Presentation\" section, this won't have any effect.";
1853 set control_strip_bordercolor = "";
1855 property Color control_strip_linkcolor {
1856 des = "Link color of navigation strip";
1857 note = "If you don't enable custom navigation strip colors in the \"Presentation\" section, this won't have any effect.";
1859 set control_strip_linkcolor = "";
1861 property Color theme_bgcolor {
1862 des = "Background color set by theme";
1865 set theme_bgcolor = "";
1867 property Color theme_fgcolor {
1868 des = "Text color set by theme";
1871 set theme_bgcolor = "";
1873 property Color theme_bordercolor {
1874 des = "Border color set by theme";
1877 set theme_bordercolor = "";
1879 property Color theme_linkcolor {
1880 des = "Link color set by theme";
1883 set theme_linkcolor = "";
1886 property string text_we_like_this {
1887 des="Hint for “View all” link";
1890 set text_we_like_this = "View people who like it";
1892 property string text_i_like_this {
1893 des="Hint for “+1” link";
1896 set text_i_like_this = "Please click Track this if you want to receive all comments to this entry";
1898 ###[ global function implementations ]
1900 function prop_init ()
1901 "This function is the first thing called and is the place to set properties based on the values of other properties. It's called before the style system looks at its builtin properties, so if you need to conditionally setup something based on your own custom properties, do it here. You can't print from this function."
1903 # do nothing, just exist.
1906 function print_stylesheet ()
1907 "Prints a stylesheet, the URL of which can be referenced by [member[Page.stylesheet_url]]. This is another S2 entry point, in addition to [method[Page.print()]]." {
1910 function print_custom_control_strip_css ()
1911 "Prints the CSS for custom control strip colors, if the option is enabled. This should be called by print_stylesheet()."
1913 if ($*custom_control_strip_colors != "off") {
1914 var bool bgcolor = $*control_strip_bgcolor.as_string != "";
1915 var bool fgcolor = $*control_strip_fgcolor.as_string != "";
1916 var bool bordercolor = $*control_strip_bordercolor.as_string != "";
1917 var bool linkcolor = $*control_strip_linkcolor.as_string != "";
1918 var string bgimage = "";
1920 if ($*custom_control_strip_colors == "on_gradient" and $bgcolor and $fgcolor) {
1921 var Color blended_color = $*control_strip_bgcolor->blend($*control_strip_fgcolor, 25); # Make the background color 25% like the text color
1922 $bgimage = palimg_tint("controlstrip/bg.gif", $*control_strip_bgcolor, $blended_color);
1929 background-color: $*control_strip_bgcolor;
1931 if ($bgimage == "") {
1932 """ background-image: none;""";
1934 """ background-image: url($bgimage);""";
1940 if ($fgcolor or $bordercolor) {
1943 #lj_controlstrip td {
1946 """ color: $*control_strip_fgcolor;""";
1948 if ($fgcolor and $bordercolor) {
1952 """ border-bottom: 1px solid $*control_strip_bordercolor;""";
1961 #lj_controlstrip_statustext {
1962 color: $*control_strip_fgcolor;
1969 #lj_controlstrip a {
1970 color: $*control_strip_linkcolor;
1977 #lj_controlstrip_user,
1978 #lj_controlstrip_actionlinks,
1979 #lj_controlstrip_search,
1980 #lj_controlstrip_login,
1981 #lj_controlstrip_loggedout_userpic {
1982 border-right: 1px solid $*control_strip_bordercolor;
1985 #lj_controlstrip_login td {
1989 #lj_controlstrip td td {
1994 if ($bgcolor and $fgcolor) {
1995 print control_strip_logged_out_userpic_css();
1996 print control_strip_logged_out_full_userpic_css();
2001 function builtin htmlattr(string name, string value) : string
2002 "If the value isn't blank, return in HTML attribute format with a leading space. HTML of name is not escaped.";
2004 function builtin htmlattr(string name, int value) : string
2005 "If the value isn't blank, return in HTML attribute format with a leading space. HTML of name is not escaped.";
2009 function lang_map_plural (int n) : int {
2010 if ($n == 1) { return 0; } # singular
2014 function lang_page_of_pages (int pg, int pgs) [notags] : string {
2015 return "Page $pg of $pgs";
2018 function lang_user_wrote(UserLite u) : string "Returns text describing that the user wrote something. i18nc layers should override this." {
2020 return $u->as_string()+" wrote";
2023 return "An anonymous user wrote";
2027 function lang_at_datetime(DateTime d) : string "Returns a string saying \"at {the data and time given}\". Used in the core implementation of EntryPage and ReplyPage. i18nc layers should override this." {
2028 return "on " + $d->date_format("long") + " at " + $d->time_format();
2031 function lang_ordinal(int num) [notags] : string
2032 "Make an ordinal number from a cardinal number"
2034 if ($num % 100 >= 4 and $num % 100 <= 20) { return $num+"th"; }
2035 if ($num % 10 == 1) { return $num+"st"; }
2036 if ($num % 10 == 2) { return $num+"nd"; }
2037 if ($num % 10 == 3) { return $num+"rd"; }
2041 function lang_ordinal(string num) [notags, fixed] : string
2042 "Make an ordinal number from a cardinal number. Don't override this, since the core layer implementation just calls [function[lang_ordinal(int)]], which i18nc layers should override."
2044 return lang_ordinal(int($num));
2048 function lang_viewname(string viewid) [notags] : string
2049 "Get some words representing a view"
2051 if ($viewid == "recent") { return $*text_view_recent; }
2052 if ($viewid == "archive") { return $*text_view_archive; }
2053 if ($viewid == "friends") { return $*text_view_friends; }
2054 if ($viewid == "day") { return "Day"; }
2055 if ($viewid == "month") { return "Month"; }
2056 if ($viewid == "userinfo") { return $*text_view_userinfo; }
2057 if ($viewid == "usergames") { return $*text_view_usergames; }
2058 if ($viewid == "entry") { return "Read Comments"; }
2059 if ($viewid == "reply") { return "Post Comment"; }
2060 if ($viewid == "tags") { return "Tags"; }
2061 return "Unknown View";
2064 function builtin get_remote_lang() : string
2065 "Returns remote's language";
2067 function lang_metadata_title(string which) [fixed] : string
2068 "Get a human-readable caption for a metadata key. Layers shouldn't override this, but should instead set the relevant string properties."
2070 if ($which == "music") {
2071 return $*text_meta_music;
2073 elseif ($which == "mood") {
2074 return $*text_meta_mood;
2076 elseif ($which == "location") {
2077 return $*text_meta_location;
2079 elseif ($which == "groups") {
2080 return $*text_meta_groups;
2090 ### Image Manipulation
2092 function Image::as_string(string{} opts) [fixed] : string {
2093 var string img = "";
2094 if ($opts{"href"} != "") { $img = $img + "<a href=\"" + eurl($opts{"href"}) + "\" $opts{"a_attr"}>"; }
2095 $img = $img + $this->as_string($opts{"alt"});
2096 if ($opts{"href"} != "") { $img = $img + "</a>"; }
2101 function Image::as_string(string alttext) [fixed] : string {
2102 return $this->as_string_ex($alttext, "");
2105 function Image::as_string_ex(string alttext, string attributes) [fixed] : string {
2106 var string extraParams = "";
2108 foreach var string extraKey ($.extra) {
2109 $extraParams = $extraParams + """$extraKey="$.extra{$extraKey}" """;
2112 if ($.height) { $extraParams = $extraParams + """height="$.height" """; }
2113 if ($.width) { $extraParams = $extraParams + """width="$.width" """; }
2115 $extraParams = $extraParams + $attributes;
2117 return "<img src=\"$.url\" title=\"\" alt=\"" + ehtml($alttext) + "\"" +
2118 $extraParams + " />";
2121 function Image::as_string() [fixed] : string {
2122 return $this->as_string($this.alttext);
2125 function Image::print (string{} opts)
2127 # must do safe here because opts could have the 'a_attr' key set
2128 print safe $this->as_string($opts);
2131 function Image::print (string alttext)
2133 print $this->as_string($alttext);
2136 function Image::print
2138 print $this->as_string($this.alttext);
2141 function userinfoicon(UserLite user) : Image {
2144 $uimage.height = 16;
2146 if ($user.journal_type == "C") {
2147 $uimage->set_url("$*IMGDIR/community.gif");
2148 } elseif ($user.journal_type == "Y") {
2149 $uimage->set_url("$*IMGDIR/syndicated.gif");
2150 } elseif ($user.journal_type == "N") {
2151 $uimage->set_url("$*IMGDIR/newsinfo.gif");
2152 } elseif ($user.journal_type == "I") {
2153 $uimage->set_url("$*IMGDIR/openid-profile.gif");
2155 $uimage->set_url("$*IMGDIR/userinfo.gif");
2157 $uimage.height = 17;
2162 ### UserLite functions
2164 function UserLite::base_url() [fixed] : string {
2165 return userlite_base_url($this);
2168 function UserLite::tag_manage_url() [fixed] : string {
2169 return "$*SITEROOT/manage/tags.bml?authas=$.username";
2172 function UserLite::as_string() [fixed] : string {
2173 return $this->ljuser();
2176 function UserLite::print() {
2177 print $this->as_string();
2180 function UserLite::print_linkbar() {
2182 foreach var string k ($.link_keyseq) {
2183 $link = $this->get_link($k);
2188 function Friend::print() {
2189 print $this->as_string();
2192 ### Generic Page Functions
2194 function Page::print_stylesheets() {
2195 if ($*include_default_stylesheet) {
2196 if ($*external_stylesheet) {
2197 println safe """<link rel="stylesheet" href="$.stylesheet_url" type="text/css" />""";
2200 println """<style type="text/css">""";
2204 println """</style>""";
2208 if ($*linked_stylesheet != "") {
2209 println safe """<link rel="stylesheet" href="$*linked_stylesheet" type="text/css" />""";
2212 if ($*custom_css != "") {
2213 println """<style type="text/css">""";
2215 println safe $*custom_css;
2217 println """</style>""";
2221 function Page::view_title() [notags] : string {
2222 return lang_viewname($.view);
2224 function FriendsPage::view_title() : string {
2225 if ($.friends_mode == "") {
2226 if ($.filter_active) {
2227 if ($.filter_name != "") {
2228 if ($.friends_title != "") {
2229 return $.friends_title+" ("+$.filter_name+")";
2231 return $*text_view_friends+" ("+$.filter_name+")";
2234 return $*text_view_friends_filter;
2237 if ($.friends_title != "") {
2238 return $.friends_title;
2239 } elseif ($.journal.journal_type == "C") {
2240 return $*text_view_friends_comm;
2242 return $*text_view_friends;
2246 elseif ($.friends_mode == "friendsfriends") {
2247 if ($.filter_active) {
2248 if ($.filter_name != "") {
2249 return $*text_view_friendsfriends+" ("+$.filter_name+")";
2252 return $*text_view_friendsfriends_filter;
2256 return $*text_view_friendsfriends;
2260 return "Unknown Friends View";
2263 function DayPage::view_title : string {
2264 return $.date->date_format("long");
2266 function YearPage::view_title() : string {
2267 return string($.year);
2269 function EntryPage::view_title() : string {
2270 return $.entry.subject ? $.entry->get_plain_subject() : "";
2272 function ReplyPage::view_title() : string {
2273 return "Post a comment";
2275 function Page::title() [notags] : string {
2276 var string title = $.global_title;
2278 $title = $.journal.name;
2280 if ($.view != "recent") {
2281 $title = $title + " - " + $this->view_title();
2283 if ($.view == "friends") {
2284 $title = $this->view_title();
2289 function server_sig() {
2290 """Powered by <a href="$*SITEROOT/">$*SITENAME</a>""";
2293 function Page::print() {
2295 """<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7; IE=EmulateIE9" /> """;
2296 $this->print_head();
2297 $this->print_stylesheets();
2298 "<title>"+$this->title()+"</title>\n";
2300 if ($*font_base != "" or $*font_fallback != "none") {
2301 """<style type="text/css">""";
2305 body, td, th, table, p, div {
2307 if ($*font_base != "") {
2309 if ($*font_fallback != "none") {
2313 if ($*font_fallback != "none") {
2314 print $*font_fallback;
2321 "</head>\n<body>\n";
2322 $this->print_control_strip();
2323 if (defined $.journal.default_pic and
2324 $.view != "entry" and
2325 $.view != "reply") {
2326 $.journal.default_pic->print();
2328 print "<h1>" + $this->title() + "</h1>\n";
2330 $this->print_body();
2331 """\n<hr><address>""";
2333 """</address>\n</body></html>""";
2336 function Page::print_body() {
2337 """<h2>No Default Renderer</h2><p>There is no body renderer for viewtype <tt>$.view</tt> defined.</p>""";
2340 function Page::print_head() {
2341 print $.head_content;
2342 $this->print_custom_head();
2345 function Page::print_custom_head() {
2349 function Page::print_linklist() {
2350 if (size $.linklist <= 0) {
2352 } elseif (not $*linklist_support) {
2356 foreach var UserLink l ($.linklist) {
2358 if ($l.is_heading) {
2361 "<a href='$l.url'>$l.title</a>";
2368 function Page::print_entry_poster(Entry e) {
2370 if ($.view == "friends" and not $e.poster->equals($e.journal)) {
2372 $e.journal->print();
2375 function Page::print_entry(Entry e) {
2376 ## For most styles, this will be overridden by FriendsPage::print_entry and such.
2377 """<div class="entry" id="$e.dom_id">\n""";
2378 "<h3>$e.security_icon $e.subject</h3>\n";
2379 if ($.view == "friends" or $e.poster.username != $e.journal.username) {
2380 "<div>"; $this->print_entry_poster($e); "</div>";
2382 """<div class="entrytext">""";
2385 $e->print_metadata();
2386 if ($e.comments.enabled) {
2387 $e.comments->print();
2391 function FriendsPage::print_entry(Entry e) {
2392 ## For most styles, this will be overridden by FriendsPage::print_entry and such.
2393 """<div class="entry" id="$e.dom_id">\n""";
2396 $bg = $.friends{$e.journal.username}.bgcolor;
2397 $fg = $.friends{$e.journal.username}.fgcolor;
2399 $this->print_entry_poster($e);
2400 "$e.security_icon $e.subject";
2402 """<div style="color: """ + $fg + "; background: " + $bg + """ none;">"""; $this->print_entry_poster($e); "</div>";
2403 """<div class="entrytext">"""; $e->print_text(); """</div>""";
2404 $e->print_metadata();
2405 if ($e.comments.enabled) {
2406 $e.comments->print();
2411 function Comment::print_edit_text() {
2413 print "<br /><br /><span class='ljedittime'><em>$*text_comment_edittime " + $this->edittime_display() + "</em></span>";
2417 function EntryLite::print_text() [fixed] {
2420 if ($this isa Comment) {
2421 var Comment c = $this as Comment;
2422 $c->print_edit_text();
2426 function Entry::print_metadata() {
2427 if (size $.metadata) {
2428 """<div class="metadata">\n""";
2429 foreach var string m ($.metadata) {
2430 "<div><strong>$m</strong>: ";
2434 print $.metadata{$m}; "</div>\n";
2440 function EntryLite::print_linkbar() {}
2441 function Comment::print_linkbar() {
2443 foreach var string k ($.link_keyseq) {
2444 $link = $this->get_link($k);
2448 function Entry::print_link_next() {
2449 var Link link = $this->get_link("nav_next");
2452 function Entry::print_link_prev() {
2453 var Link link = $this->get_link("nav_prev");
2456 function Entry::print_linkbar() {
2457 ## There's no point in showing previous/next links on pages which show
2458 ## multiple entries anyway, so we only print them on EntryPage and ReplyPage.
2460 var Page p = get_page();
2461 var bool show_interentry = ($p.view == "entry" or $p.view == "reply");
2462 if ($show_interentry) {
2463 $this->print_link_prev();
2466 foreach var string k ($.link_keyseq) {
2467 $link = $this->get_link($k);
2471 if ($show_interentry) {
2472 $this->print_link_next();
2476 ### RecentPage and related functions
2478 function RecentPage::print_body {
2479 # Creator for both the Recent and Friends views, since they are similar
2480 # If someone wants to do the two views differently, they can create
2481 # FriendsPage::print_body since FriendsPage extends RecentPage.
2483 foreach var Entry e ($.entries) {
2488 """<div class="day" id="day"""; print $e.time->date_format("%%yyyy%%%%mm%%%%dd%%"); """">\n<h2>""";
2489 print $e.time->date_format("long_day");
2493 $this->print_entry($e);
2496 if ($.nav.backward_url != "" or $.nav.forward_url != "") {
2497 if ($.nav.backward_url != "") {
2498 print safe "<a href=\"" + $.nav.backward_url + "\">" + get_plural_phrase($.nav.backward_count, "text_skiplinks_back") + "</a>";
2500 if ($.nav.backward_url != "" and $.nav.forward_url != "") {
2503 if ($.nav.forward_url != "") {
2504 print safe "<a href=\"" + $.nav.forward_url + "\">" + get_plural_phrase($.nav.forward_count, "text_skiplinks_forward") + "</a>";
2510 function secs_to_string (int sec) : string {
2512 return string($sec) + " seconds";
2515 return string($sec / 60) + " minutes";
2518 return string($sec / 3600) + " hours";
2520 return string($sec / 86400) + " days";
2523 function EntryLite::time_display(string datefmt, string timefmt) : string {
2524 if ($datefmt == "") {
2527 if ($timefmt == "") {
2532 if ($datefmt != "none") { $ret = $ret + $this.time->date_format($datefmt); }
2533 if ($datefmt != "none" and $timefmt != "none") { $ret = $ret + " "; }
2534 if ($timefmt != "none") { $ret = $ret + $this.time->time_format($timefmt); }
2539 # edittime argument is true if we want the get the edit time of the comment
2540 function Comment::time_display (string datefmt, string timefmt, bool edittime) : string {
2541 var DateTime time = ($edittime ? $this.edittime : $this.time);
2542 var DateTime time_remote = ($edittime ? $this.edittime_remote : $this.time_remote);
2543 var DateTime time_poster = ($edittime ? $this.edittime_poster : $this.time_poster);
2545 if ($datefmt == "") {
2548 if ($timefmt == "") {
2552 var string tooltip = "";
2553 if ($edittime == false) {
2554 var string etime = secs_to_string($this.seconds_since_entry);
2555 $tooltip = $etime + " after journal entry";
2560 var string display_date;
2561 var string display_time;
2564 $display_date = $time_remote->date_format($datefmt);
2565 if ($timefmt == "none") { $display_date = $display_date + " (local)"; }
2566 $display_time = $time_remote->time_format($timefmt) + " (local)";
2568 $display_date = $time->date_format($datefmt);
2569 if ($timefmt == "none") { $display_date = $display_date + " (UTC)"; }
2570 $display_time = $time->time_format($timefmt) + " (UTC)";
2573 if (defined $time_poster and defined $this.poster)
2575 var string poster_date = $time_poster->date_format($datefmt);
2576 if ($edittime == false) {
2577 $tooltip = $tooltip + ", ";
2580 if ($poster_date == $display_date and $timefmt != "none") { $poster_date = ""; }
2581 else { $poster_date = $poster_date + " "; }
2583 if ($timefmt != "none") {
2584 $tooltip = $tooltip + $poster_date + $time_poster->time_format($timefmt) + " (" + $this.poster.username + "'s time)";
2586 $tooltip = $tooltip + $poster_date + "(" + $this.poster.username + "'s time)";
2590 if ($datefmt != "none") { $main = $main + $display_date; }
2591 if ($datefmt != "none" and $timefmt != "none") { $main = $main + " "; }
2592 if ($timefmt != "none") { $main = $main + $display_time; }
2594 return "<span title=\"" + ehtml($tooltip) + "\">" + ehtml($main) + "</span>";
2597 function Comment::time_display (string datefmt, string timefmt) : string {
2598 return $this->time_display($datefmt, $timefmt, false);
2601 function EntryLite::time_display() : string {
2602 # Let the real function decide on some nice defaults
2603 return $this->time_display("", "");
2606 function Comment::edittime_display() : string {
2607 return $this->time_display("", "", true);
2610 function Comment::edittime_display (string datefmt, string timefmt) : string {
2611 return $this->time_display($datefmt, $timefmt, true);
2616 function YearPage::print_body {
2617 $this->print_year_links();
2618 foreach var YearMonth m ($.months) {
2619 $this->print_month($m);
2622 function YearPage::print_year_links() {
2624 foreach var YearYear y ($.years) {
2626 """<li class="active">$y.year</li>\n""";
2628 """<li><a href="$y.url">$y.year</a></li>\n""";
2633 function YearPage::print_month(YearMonth m) {
2634 if (not $m.has_entries) { return; }
2635 """<table style="margin-left: 25%; margin-right: 25%; margin-top: 1em; margin-bottom: 1em;
2636 border-collapse: collapse; border: 1px solid;" border="1">\n
2637 <tr><th colspan="7" style="text-align: center; border: 1px solid;">""";
2638 print $m->month_format();
2639 """</th></tr>\n<tr>\n""";
2640 foreach var int d (weekdays()) {
2641 "<th>"+$*lang_dayname_short[$d]+"</th>\n";
2644 foreach var YearWeek w ($m.weeks) {
2647 print safe """<tr><td colspan="7" style="text-align: center; border: 1px solid;">
2648 <a href="$m.url">$*text_view_month</a></td></tr>\n""";
2652 function YearWeek::print() {
2653 """<tr valign="top" style="height: 2em;">\n""";
2654 if ($.pre_empty > 0) {
2655 """<td class="emptyday" colspan="$.pre_empty"> </td>\n""";
2657 foreach var YearDay d ($.days) {
2658 """<td style="border: 1px solid;">\n""";
2659 """<div style="text-align: right;">$d.day</div>\n""";
2660 if ($d.num_entries > 0) {
2661 """<div style="text-align: center;"><a href="$d.url">$d.num_entries</a></div>\n""";
2665 if ($.post_empty > 0) {
2666 """<td colspan="$.post_empty"> </td>\n""";
2671 function MonthPage::view_title : string {
2672 return $.date->date_format($*lang_fmt_month_long);
2675 function MonthPage::print_body {
2676 "<form method='post' action='$.redir.url'><center>";
2677 $.redir->print_hiddens();
2678 if ($.prev_url != "") { "[<a href='$.prev_url'><<<</a>]\n"; }
2679 if (size $.months > 1) {
2680 "<select name='redir_key'>\n";
2681 foreach var MonthEntryInfo mei ($.months) {
2683 if ($mei.date.year == $.date.year and $mei.date.month == $.date.month) {
2684 $sel = " selected='selected'";
2686 "<option value='$mei.redir_key'$sel>" + $mei.date->date_format($*lang_fmt_month_long) + "</option>";
2688 "</select>\n<input type='submit' value='View' />";
2690 if ($.next_url != "") { "\n[<a href='$.next_url'>>>></a>]\n"; }
2691 "</center></form>\n<dl>";
2692 foreach var MonthDay d ($.days) {
2693 if ($d.has_entries) {
2694 "<dt><a href=\"$d.url\"><b>";
2695 print lang_ordinal($d.day);
2696 "</b></a></dt>\n<dd>";
2697 $d->print_subjectlist();
2704 function MonthDay::print_subjectlist() {
2705 # Too many tables...
2706 foreach var Entry e ($.entries) {
2707 print $e.time->time_format("short") + ": ";
2708 if ($e.poster.username != $e.journal.username) {
2709 $e.poster->print(); " ";
2712 if ($e.subject != "") {
2713 " <a href=\"$e.permalink_url\">$e.subject</a>";
2715 print safe " <a href=\"$e.permalink_url\" style=\"font-style: italic;\">$*text_nosubject</a>";
2717 if ($e.comments.count > 0) {
2718 print safe " - " + get_plural_phrase($e.comments.count, "text_read_comments");
2720 if ($e.comments.screened) {
2721 print safe " <b>$*text_month_screened_comments</b>";
2729 function DayPage::print_body() {
2730 if ($.has_entries) {
2731 "<div class=\"day\" id=\"day"; print $.date->date_format("%%yyyy%%%%mm%%%%dd%%"); "\">\n<h2>";
2732 print $.date->date_format("long");
2735 foreach var Entry e ($.entries) {
2736 $this->print_entry($e);
2741 print safe "<p>$*text_noentries_day</p>";
2744 "<div class=\"skiplinks\">\n";
2745 print safe "<a href=\"$.prev_url\">$*text_day_prev</a> | ";
2746 print safe "<a href=\"$.next_url\">$*text_day_next</a>\n</div>";
2750 ### CommentInfo functions
2752 function CommentInfo::print_readlink {
2753 var Page p = get_page();
2754 print safe "<a href=\"$.read_url\">"+
2755 get_plural_phrase($.count, $p.view == "friends" ?
2756 "text_read_comments_friends" : "text_read_comments")+
2759 function CommentInfo::print_postlink() {
2760 var Page p = get_page();
2761 if ($.maxcomments) {
2762 print safe "$*text_max_comments";
2764 print safe "<a href=\"$.post_url\">"+($p.view == "friends" ? $*text_post_comment_friends : $*text_post_comment)+"</a>";
2767 function CommentInfo::print() {
2768 if ($.show_readlink or $.show_postlink) {
2769 """<div style="text-align: right;">\n(""";
2770 if ($.show_readlink) {
2771 $this->print_readlink();
2773 if ($.show_postlink and $.show_readlink) {
2776 if ($.show_postlink) {
2777 $this->print_postlink();
2784 ### Link object functions
2786 function Link::print_button() [fixed] {
2787 print $this->as_string();
2790 function Link::as_string() [fixed] : string {
2792 if ($.url == "") { return ""; }
2793 var string ealt = ehtml($.caption);
2794 var string{} extra = $.icon.extra;
2795 var string extraParams = "";
2797 foreach var string extraKey ($extra) {
2798 $extraParams = $extraParams + """$extraKey="$extra{$extraKey}" """;
2801 return """<a href="$.url"><img border='0' width="$.icon.width" height="$.icon.height" alt="$ealt" title="$ealt" src="$.icon.url" $extraParams /></a>""";
2806 function Redirector::start_form ()
2808 "<form method='post' action='$.url' style='display: inline'>";
2809 $this->print_hiddens();
2811 function Redirector::print_hiddens ()
2813 "<input type='hidden' name='redir_user' value='$.user' />\n";
2814 "<input type='hidden' name='redir_vhost' value='$.vhost' />\n";
2815 "<input type='hidden' name='redir_type' value='$.type' />\n";
2817 function Redirector::end_form ()
2822 ### EntryPage functions
2824 function EntryPage::print_comments (Comment[] cs) {
2825 if (size $cs == 0) { return; }
2826 var Page p = get_page();
2827 foreach var Comment c ($cs) {
2830 "<div id='$c.dom_id' style='margin-left: 0px; margin-top: 5px'>\n";
2831 $this->print_comment($c);
2835 var int indent = ($c.depth - 1) * 25;
2836 "<div id='$c.dom_id' style='margin-left: ${indent}px; margin-top: 5px'>\n";
2838 if (size $c.replies > 0) {
2841 } elseif ($c.full) {
2842 $this->print_comment($c);
2844 $this->print_comment_partial($c);
2847 $this->print_comments($c.replies);
2852 function EntryPage::print_comment (Comment c) {
2853 var Color barlight = $*color_comment_bar->clone();
2854 $barlight->lightness(($barlight->lightness() + 255) / 2);
2855 var Color barc = $c.depth % 2 ? $*color_comment_bar : $barlight;
2856 var string poster = defined $c.poster ? $c.poster->as_string() : "<i>$*text_poster_anonymous</i>";
2858 "<a name='$c.anchor'></a><div style='background-color: $barc; margin-top: 10px; width: 100%'>";
2859 "<table cellpadding='2' cellspacing='0' summary='0' style='width: 100%'><tr valign='top'>";
2860 if (defined $c.userpic and $*comment_userpic_style != "off") {
2861 var int w = $c.userpic.width;
2862 var int h = $c.userpic.height;
2863 # WARNING: this will later be done by the system (it'll be a
2864 # constructional property), so don't copy this hack into your
2865 # layout layers or you'll be messed up later.
2866 if ($*comment_userpic_style == "small") {
2870 print "<td style='width: 102px'><img src='$c.userpic.url' width='$w' height='$h' alt='' /></td>";
2872 "<td><table style='width: 100%'><tr>";
2874 "<td align='left' style='width: 50%'>";
2876 print safe "<tr><th align='right'>$*text_comment_from</th><td>$poster</td></tr>\n";
2877 print safe "<tr><th align='right'>$*text_comment_date</th><td style='white-space: nowrap'>";
2878 print $c->time_display() + "</td></tr>";
2879 if ($c.metadata{"poster_ip"}) { print safe "<tr><th align='right'>$*text_comment_ipaddr</th><td>(" + $c.metadata{"poster_ip"} + ")</td></tr>"; }
2882 print "<td align='right' style='width: 50%'>";
2883 if ($this.multiform_on) {
2884 print safe " <label for='ljcomsel_$c.talkid'>$*text_multiform_check</label> ";
2885 $c->print_multiform_check();
2887 $c->print_linkbar();
2890 print "<tr valign='top'><td style='width: 50%'>";
2891 if (defined $c.subject_icon or $c.subject != "") { "<h3>$c.subject_icon $c.subject</h3>\n"; }
2894 print safe "<td style='width:50%;' align='right'><strong>(<a href='$c.permalink_url'>$*text_permalink</a>)</strong></td></tr>\n";
2895 print "</table></td></tr></table></div>";
2897 print "<div style='margin-left: 5px'>"; $c->print_text(); "</div>\n";
2898 print "<div style='margin-top: 3px; font-size: smaller'>";
2900 print safe "($*text_comment_frozen) ";
2902 "("; $c->print_reply_link({"linktext" => $*text_comment_reply}); ") ";
2904 if ($c.parent_url != "") { print safe "(<a href='$c.parent_url'>$*text_comment_parent</a>) "; }
2905 if ($c.thread_url != "") {
2906 print safe "(<a href='$c.thread_url'>$*text_comment_thread</a>) ";
2907 var Link expand_link = $c->get_link("expand_comments");
2908 if (defined $expand_link) {
2909 "("; $c->print_expand_link(); ") ";
2913 $c->print_reply_container();
2916 function EntryPage::print_comment_full (Comment c) {
2919 function EntryPage::print_comment_partial (Comment c) {
2920 var string poster = defined $c.poster ? $c.poster->as_string() : "<i>$*text_poster_anonymous</i>";
2921 var string subj = $c.subject != "" ? $c.subject : $*text_nosubject;
2922 print safe "<a href='$c.permalink_url'>$subj</a> - $poster";
2923 var Link expand_link = $c->get_link("expand_comments");
2924 if ($c.thread_url != "" and defined $expand_link) {
2925 " "; $c->print_expand_link();
2929 function ItemRange::print() {
2930 if ($.all_subitems_displayed) { return; }
2931 print "<table align='center' border='0' cellpadding='3'>";
2932 print "<tr><td align='center' colspan='3'><b>" +
2933 lang_page_of_pages($.current, $.total) + "</b>";
2935 var string url_prev = $this->url_of($.current - 1);
2936 if ($.current != 1) {
2937 print "<tr><td align='center'><a href='$url_prev#comments'><<</a></td>";
2939 print "<tr><td align='center'><<</td>";
2941 print "<td align='center'>";
2942 foreach var int i (1..$.total) {
2943 if ($i == $.current) { "<b>[$i]</b> "; }
2945 var string url_of = $this->url_of($i);
2946 "<a href='$url_of#comments'><b>[$i]</b></a> ";
2950 var string url_next = $this->url_of($.current + 1);
2951 if ($.current != $.total) {
2952 print "<td align='center'><a href='$url_next#comments'>>></a></td>";
2954 print "<td align='center'>>></td>";
2956 print "</tr></table>";
2959 function EntryPage::print_body
2961 var Entry e = $.entry;
2962 """<div class="entry" id="$e.dom_id">\n""";
2964 "<table><tr valign='middle'>";
2965 if (defined $e.userpic) {
2966 print "<td>$e.userpic</td>";
2968 print "<td>"+lang_user_wrote($e.poster);
2969 print "<br />"+lang_at_datetime($e.time);
2970 "</td></tr></table>\n";
2972 print "<div style='text-align: center'>";
2973 $e->print_linkbar();
2976 "<h2>$e.security_icon $e.subject</h2>\n";
2978 if (not $.viewing_thread) {
2979 "<div class='entrytext'>";
2982 $e->print_metadata();
2986 if ($.entry.comments.enabled) {
2987 "<hr /><a name='comments'></a>";
2988 "("; $this->print_reply_link({ "linktext" => $*text_post_comment, "target" => "topcomment" }); ")";
2989 $this->print_reply_container({ "target" => "topcomment" });
2990 if ($.comment_pages.total_subitems > 0) {
2992 $.comment_pages->print();
2993 $this->print_multiform_start();
2994 $this->print_comments($.comments);
2996 "("; $this->print_reply_link({ "linktext" => $*text_post_comment, "target" => "bottomcomment" }); ")";
2997 $this->print_reply_container({"target" => "bottomcomment"});
2998 if ($.comment_pages.all_subitems_displayed) { print "<hr />"; }
2999 $this->print_multiform_actionline();
3000 $this->print_multiform_end();
3001 $.comment_pages->print();
3006 function ReplyPage::print_body
3008 if (not $.entry.comments.enabled) {
3009 print safe "<h2>$*text_reply_nocomments_header</h2><p>$*text_reply_nocomments</p>";
3014 if ($.replyto isa Entry) {
3015 var Entry en = $.replyto as Entry;
3017 $security = $en.security_icon;
3020 "<table><tr valign='middle'>";
3021 if (defined $.replyto.userpic) {
3022 print "<td>$.replyto.userpic</td>";
3024 print "<td>"+lang_user_wrote($.replyto.poster);
3025 print "<br />"+lang_at_datetime($.replyto.time);
3026 "</td></tr></table>\n";
3028 print "<h2>$security $.replyto.subject</h2>";
3029 print "<div>"; $.replyto->print_text(); "</div>";
3032 print safe """(<a href="$.entry.permalink_url">$*text_reply_back</a>)""";
3036 ### TagsPage functions
3038 function TagsPage::print_body
3040 print safe "<h2>$*text_tags_page_header</h2><ul class='ljtaglist'>";
3042 foreach var TagDetail td ($.tags) {
3043 var string uses = get_plural_phrase($td.use_count, "text_tag_uses");
3044 print safe """<li><a href="$td.url">$td.name</a> - $uses</li>""";
3050 ### MessagePage functions
3052 function MessagePage::view_title() : string {
3056 function MessagePage::print_body() {
3057 $this->print_links();
3058 $this->print_message();
3061 function MessagePage::print_message() {
3065 function MessagePage::print_links() {
3066 println """<div style='text-align: center;'>""";
3067 foreach var string k ($.link_keyseq) {
3068 println """ $.links{$k} """;
3070 println """</div>""";