LJSUP-17669: Login.bml form refactoring
[livejournal.git] / cgi-bin / ljviews-s1-using-s2.pl
blob8e3b5da13414f7500a896c597ed09be801538ff2
1 #!/usr/bin/perl
2 use strict;
4 package LJ::S1w2;
6 use vars qw(@themecoltypes);
8 # this used to be in a table, but that was kinda useless
9 @themecoltypes = (
10 [ 'page_back', 'Page background' ],
11 [ 'page_text', 'Page text' ],
12 [ 'page_link', 'Page link' ],
13 [ 'page_vlink', 'Page visited link' ],
14 [ 'page_alink', 'Page active link' ],
15 [ 'page_text_em', 'Page emphasized text' ],
16 [ 'page_text_title', 'Page title' ],
17 [ 'weak_back', 'Weak accent' ],
18 [ 'weak_text', 'Text on weak accent' ],
19 [ 'strong_back', 'Strong accent' ],
20 [ 'strong_text', 'Text on strong accent' ],
21 [ 'stronger_back', 'Stronger accent' ],
22 [ 'stronger_text', 'Text on stronger accent' ],
25 %LJ::S1w2::viewcreator = (
26 lastn => \&LJ::S1w2::create_view_lastn,
27 friends => \&LJ::S1w2::create_view_friends,
28 calendar => \&LJ::S1w2::create_view_calendar,
29 day => \&LJ::S1w2::create_view_day,
32 # PROPERTY Flags:
34 # /a/:
35 # safe in styles as sole attributes, without any cleaning. for
36 # example: <a href="%%urlread%%"> is okay, # if we're in
37 # LASTN_TALK_READLINK, because the system generates # %%urlread%%.
38 # by default, if we don't declare things trusted here, # we'll
39 # double-check all attributes at the end for potential XSS #
40 # problems.
42 # /u/:
43 # is a URL. implies /a/.
46 # /d/:
47 # is a number. implies /a/.
49 # /t/:
50 # tainted! User controls via other some other variable.
52 # /s/:
53 # some system string... probably safe. but maybe possible to coerce it
54 # alongside something else.
56 my $commonprop = {
57 'dateformat' => {
58 'yy' => 'd', 'yyyy' => 'd',
59 'm' => 'd', 'mm' => 'd',
60 'd' => 'd', 'dd' => 'd',
61 'min' => 'd',
62 '12h' => 'd', '12hh' => 'd',
63 '24h' => 'd', '24hh' => 'd',
65 'talklinks' => {
66 'messagecount' => 'd',
67 'urlread' => 'u',
68 'urlpost' => 'u',
69 'itemid' => 'd',
71 'talkreadlink' => {
72 'messagecount' => 'd',
73 'urlread' => 'u',
75 'event' => {
76 'itemid' => 'd',
78 'pic' => {
79 'src' => 'u',
80 'width' => 'd',
81 'height' => 'd',
83 'newday' => {
84 yy => 'd', yyyy => 'd', m => 'd', mm => 'd',
85 d => 'd', dd => 'd',
87 'skip' => {
88 'numitems' => 'd',
89 'url' => 'u',
94 $LJ::S1::PROPS = {
95 'CALENDAR_DAY' => {
96 'd' => 'd',
97 'eventcount' => 'd',
98 'dayevent' => 't',
99 'daynoevent' => 't',
101 'CALENDAR_DAY_EVENT' => {
102 'eventcount' => 'd',
103 'dayurl' => 'u',
105 'CALENDAR_DAY_NOEVENT' => {
107 'CALENDAR_EMPTY_DAYS' => {
108 'numempty' => 'd',
110 'CALENDAR_MONTH' => {
111 'monlong' => 's',
112 'monshort' => 's',
113 'yy' => 'd',
114 'yyyy' => 'd',
115 'weeks' => 't',
116 'urlmonthview' => 'u',
118 'CALENDAR_NEW_YEAR' => {
119 'yy' => 'd',
120 'yyyy' => 'd',
122 'CALENDAR_PAGE' => {
123 'name' => 't',
124 "name-'s" => 's',
125 'yearlinks' => 't',
126 'months' => 't',
127 'username' => 's',
128 'website' => 't',
129 'head' => 't',
130 'urlfriends' => 'u',
131 'urllastn' => 'u',
133 'CALENDAR_WEBSITE' => {
134 'url' => 't',
135 'name' => 't',
137 'CALENDAR_WEEK' => {
138 'days' => 't',
139 'emptydays_beg' => 't',
140 'emptydays_end' => 't',
142 'CALENDAR_YEAR_DISPLAYED' => {
143 'yyyy' => 'd',
144 'yy' => 'd',
146 'CALENDAR_YEAR_LINK' => {
147 'yyyy' => 'd',
148 'yy' => 'd',
149 'url' => 'u',
151 'CALENDAR_YEAR_LINKS' => {
152 'years' => 't',
154 'CALENDAR_SKYSCRAPER_AD' => {
155 'ad' => 't',
157 'CALENDAR_5LINKUNIT_AD' => {
158 'ad' => 't',
161 # day
162 'DAY_DATE_FORMAT' => $commonprop->{'dateformat'},
163 'DAY_EVENT' => $commonprop->{'event'},
164 'DAY_EVENT_PRIVATE' => $commonprop->{'event'},
165 'DAY_EVENT_PROTECTED' => $commonprop->{'event'},
166 'DAY_PAGE' => {
167 'prevday_url' => 'u',
168 'nextday_url' => 'u',
169 'yy' => 'd', 'yyyy' => 'd',
170 'm' => 'd', 'mm' => 'd',
171 'd' => 'd', 'dd' => 'd',
172 'urllastn' => 'u',
173 'urlcalendar' => 'u',
174 'urlfriends' => 'u',
176 'DAY_TALK_LINKS' => $commonprop->{'talklinks'},
177 'DAY_TALK_READLINK' => $commonprop->{'talkreadlink'},
178 'DAY_SKYSCRAPER_AD' => {
179 'ad' => 't',
181 'DAY_5LINKUNIT_AD' => {
182 'ad' => 't',
185 # friends
186 'FRIENDS_DATE_FORMAT' => $commonprop->{'dateformat'},
187 'FRIENDS_EVENT' => $commonprop->{'event'},
188 'FRIENDS_EVENT_PRIVATE' => $commonprop->{'event'},
189 'FRIENDS_EVENT_PROTECTED' => $commonprop->{'event'},
190 'FRIENDS_FRIENDPIC' => $commonprop->{'pic'},
191 'FRIENDS_NEW_DAY' => $commonprop->{'newday'},
192 'FRIENDS_RANGE_HISTORY' => {
193 'numitems' => 'd',
194 'skip' => 'd',
196 'FRIENDS_RANGE_MOSTRECENT' => {
197 'numitems' => 'd',
199 'FRIENDS_SKIP_BACKWARD' => $commonprop->{'skip'},
200 'FRIENDS_SKIP_FORWARD' => $commonprop->{'skip'},
201 'FRIENDS_TALK_LINKS' => $commonprop->{'talklinks'},
202 'FRIENDS_TALK_READLINK' => $commonprop->{'talkreadlink'},
203 'FRIENDS_SKYSCRAPER_AD' => {
204 'ad' => 't',
206 'FRIENDS_5LINKUNIT_AD' => {
207 'ad' => 't',
210 # lastn
211 'LASTN_ALTPOSTER' => {
212 'poster' => 's',
213 'owner' => 's',
214 'pic' => 't',
216 'LASTN_ALTPOSTER_PIC' => $commonprop->{'pic'},
217 'LASTN_CURRENT' => {
218 'what' => 's',
219 'value' => 't',
221 'LASTN_CURRENTS' => {
222 'currents' => 't',
224 'LASTN_DATEFORMAT' => $commonprop->{'dateformat'},
225 'LASTN_EVENT' => $commonprop->{'event'},
226 'LASTN_EVENT_PRIVATE' => $commonprop->{'event'},
227 'LASTN_EVENT_PROTECTED' => $commonprop->{'event'},
228 'LASTN_NEW_DAY' => $commonprop->{'newday'},
229 'LASTN_PAGE' => {
230 'urlfriends' => 'u',
231 'urlcalendar' => 'u',
232 'skyscraper_ad' => 't',
234 'LASTN_RANGE_HISTORY' => {
235 'numitems' => 'd',
236 'skip' => 'd',
238 'LASTN_RANGE_MOSTRECENT' => {
239 'numitems' => 'd',
241 'LASTN_SKIP_BACKWARD' => $commonprop->{'skip'},
242 'LASTN_SKIP_FORWARD' => $commonprop->{'skip'},
243 'LASTN_TALK_LINKS' => $commonprop->{'talklinks'},
244 'LASTN_TALK_READLINK' => $commonprop->{'talkreadlink'},
245 'LASTN_USERPIC' => {
246 'src' => 'u',
247 'width' => 'd',
248 'height' => 'd',
250 'LASTN_SKYSCRAPER_AD' => {
251 'ad' => 't',
253 'LASTN_5LINKUNIT_AD' => {
254 'ad' => 't',
258 sub current_mood_str {
259 my ($pic, $moodname) = @_;
261 my $ret = "";
263 if ($pic) {
264 $ret .= qq{<img src="$pic->{url}" align="absmiddle" width="$pic->{width}" height="$pic->{height}" vspace="1" alt="" /> };
266 $ret .= $moodname;
268 return $ret;
271 sub prepare_event {
272 my ($item, $vars, $prefix, $eventnum, $s2p) = @_;
274 $s2p ||= {};
276 my %date_format = %{LJ::S1w2::date_s2_to_s1($item->{time})};
278 my %event = ();
279 $event{'eventnum'} = $eventnum;
280 $event{'itemid'} = $item->{itemid};
281 $event{'datetime'} = LJ::fill_var_props($vars, "${prefix}_DATE_FORMAT", \%date_format);
282 if ($item->{subject}) {
283 $event{'subject'} = LJ::fill_var_props($vars, "${prefix}_SUBJECT", {
284 "subject" => $item->{subject},
288 $event{'event'} = $item->{text};
289 $event{'user'} = $item->{journal}{username};
291 # Special case for friends view: userpic for friend
292 if ($vars->{"${prefix}_FRIENDPIC"} && $item->{userpic} && $item->{userpic}{url}) {
293 $event{friendpic} = LJ::fill_var_props($vars, "${prefix}_FRIENDPIC", {
294 "width" => $item->{userpic}{width},
295 "height" => $item->{userpic}{height},
296 "src" => $item->{userpic}{url},
300 # Special case for friends view: per-friend configured colors
301 if ($s2p && $s2p->{friends}) {
302 $event{fgcolor} = $s2p->{friends}{$item->{journal}{username}}{fgcolor}{as_string};
303 $event{bgcolor} = $s2p->{friends}{$item->{journal}{username}}{bgcolor}{as_string};
306 if ($item->{comments}{enabled}) {
307 my $itemargs = "journal=".$item->{journal}{username}."&ditemid=".$item->{itemid};
309 $event{'talklinks'} = LJ::fill_var_props($vars, "${prefix}_TALK_LINKS", {
310 'itemid' => $item->{itemid},
311 'itemargs' => $itemargs,
312 'urlpost' => $item->{comments}{post_url},
313 'urlread' => $item->{comments}{read_url},
314 'messagecount' => $item->{comments}{count},
315 'readlink' => $item->{comments}{show_readlink} ? LJ::fill_var_props($vars, "${prefix}_TALK_READLINK", {
316 'urlread' => $item->{comments}{read_url},
317 'messagecount' => $item->{comments}{count} == -1 ? "?" : $item->{comments}{count},
318 'mc-plural-s' => $item->{comments}{count} == 1 ? "" : "s",
319 'mc-plural-es' => $item->{comments}{count} == 1 ? "" : "es",
320 'mc-plural-ies' => $item->{comments}{count} == 1 ? "y" : "ies",
321 }) : "",
325 LJ::prepare_currents({
326 'entry' => $item,
327 'vars' => $vars,
328 'prefix' => $prefix,
329 'event' => \%event,
332 if ($item->{poster}{_u}{userid} != $item->{journal}{_u}{userid}) {
333 my %altposter = ();
335 $altposter{'poster'} = $item->{poster}{username};
336 $altposter{'owner'} = $item->{journal}{username};
337 $altposter{'fgcolor'} = $event{'fgcolor'}; # Only set for friends view
338 $altposter{'bgcolor'} = $event{'bgcolor'}; # Only set for friends view
340 if ($item->{userpic} && $item->{userpic}->{url} && $vars->{"${prefix}_ALTPOSTER_PIC"}) {
341 $altposter{'pic'} = LJ::fill_var_props($vars, "${prefix}_ALTPOSTER_PIC", {
342 "src" => $item->{userpic}{url},
343 "width" => $item->{userpic}{width},
344 "height" => $item->{userpic}{height},
347 $event{'altposter'} = LJ::fill_var_props($vars, "${prefix}_ALTPOSTER", \%altposter);
350 my $var = "${prefix}_EVENT";
351 if ($item->{security} eq "private" &&
352 $vars->{"${prefix}_EVENT_PRIVATE"}) { $var = "${prefix}_EVENT_PRIVATE"; }
353 if ($item->{security} eq "protected" &&
354 $vars->{"${prefix}_EVENT_PROTECTED"}) { $var = "${prefix}_EVENT_PROTECTED"; }
356 return LJ::fill_var_props($vars, $var, \%event);
360 # <LJFUNC>
361 # class: s1
362 # name: LJ::S1w2::prepare_currents
363 # des: do all the current music/mood/weather/whatever stuff. only used by ljviews.pl.
364 # args: dbarg, args
365 # des-args: hashref with keys: 'entry' (an S2 Entry object), 'vars' hashref with
366 # keys being S1 variables and 'prefix' string which is LASTN, DAY, etc.
367 # </LJFUNC>
368 sub prepare_currents
370 my $args = shift;
372 my $datakey = $args->{'datakey'} || $args->{'itemid'}; # new || old
374 my $entry = $args->{entry};
376 my %currents = ();
378 if (my $val = $entry->{metadata}{music}) {
379 $currents{'Music'} = $val;
382 $currents{'Mood'} = LJ::current_mood_str($entry->{mood_icon}, $entry->{metadata}{mood});
383 delete $currents{'Mood'} unless $currents{'Mood'};
385 if (%currents) {
386 if ($args->{'vars'}->{$args->{'prefix'}.'_CURRENTS'})
388 ### PREFIX_CURRENTS is defined, so use the correct style vars
390 my $fvp = { 'currents' => "" };
391 foreach (sort keys %currents) {
392 $fvp->{'currents'} .= LJ::fill_var_props($args->{'vars'}, $args->{'prefix'}.'_CURRENT', {
393 'what' => $_,
394 'value' => $currents{$_},
397 $args->{'event'}->{'currents'} =
398 LJ::fill_var_props($args->{'vars'}, $args->{'prefix'}.'_CURRENTS', $fvp);
399 } else
401 ### PREFIX_CURRENTS is not defined, so just add to %%events%%
402 $args->{'event'}->{'event'} .= "<br />&nbsp;";
403 foreach (sort keys %currents) {
404 $args->{'event'}->{'event'} .= "<br /><b>Current $_</b>: " . $currents{$_} . "\n";
410 # <LJFUNC>
411 # class: s1
412 # name: LJ::S1w2::date_s2_to_s1
413 # des: Convert an S2 Date or DateTime object into an S1 date hash.
414 # args: s2date
415 # des-s2date: the S2 date object to convert.
416 # </LJFUNC>
417 sub date_s2_to_s1
419 my ($s2d) = @_;
420 my $dayofweek = S2::Builtin::LJ::Date__day_of_week([], $s2d);
421 my $am = $s2d->{hour} < 12 ? 'am' : 'pm';
422 my $h12h = $s2d->{hour} > 12 ? $s2d->{hour} - 12 : $s2d->{hour};
423 $h12h ||= 12; # Fix up hour 0
424 return {
425 'dayshort' => LJ::Lang::day_short($dayofweek),
426 'daylong' => LJ::Lang::day_long($dayofweek),
427 'monshort' => LJ::Lang::month_short($s2d->{month}),
428 'monlong' => LJ::Lang::month_long($s2d->{month}),
429 'yy' => substr($s2d->{year}, -2),
430 'yyyy' => $s2d->{year},
431 'm' => $s2d->{month},
432 'mm' => sprintf("%02i", $s2d->{month}),
433 'd' => $s2d->{day},
434 'dd' => sprintf("%02i", $s2d->{day}),
435 'dth' => $s2d->{day}.LJ::Lang::day_ord($s2d->{day}),
436 'ap' => substr($am,1),
437 'AP' => substr(uc($am),1),
438 'ampm' => $am,
439 'AMPM' => uc($am),
440 'min' => sprintf("%02i", $s2d->{min}),
441 '12h' => $h12h,
442 '12hh' => sprintf("%02i", $h12h),
443 '24h' => $s2d->{hour},
444 '24hh' => sprintf("%02i", $s2d->{hour}),
448 sub prepare_adverts_and_control_strip {
449 my ($vars, $prefix, $page, $u) = @_;
451 my $show_ad = LJ::run_hook('should_show_ad', {
452 ctx => "journal",
453 user => $u->{user},
455 my $show_control_strip = LJ::run_hook('show_control_strip', {
456 user => $u->{user},
459 # FIXME: Do I need to add the ad and control stuff to <head> here,
460 # or has the S2 backend done it for me already?
462 # Note: unlike the rest of this, we're not using the S2 API to do the ads or control strip,
463 # but instead just hitting the respective APIs directly.
464 if ($LJ::USE_ADS && $show_ad) {
465 $page->{'skyscraper_ad'} = LJ::fill_var_props($vars, "${prefix}_SKYSCRAPER_AD",
466 { "ad" => LJ::ads( type => "journal",
467 orient => 'Journal-Badge',
468 pubtext => $LJ::REQ_GLOBAL{'text_of_first_public_post'},
469 user => $u->{user}) .
470 LJ::ads( type => "journal",
471 orient => 'Journal-Skyscraper',
472 pubtext => $LJ::REQ_GLOBAL{'text_of_first_public_post'},
473 user => $u->{user}), });
474 $page->{'open_skyscraper_ad'} = $vars->{"${prefix}_OPEN_SKYSCRAPER_AD"};
475 $page->{'close_skyscraper_ad'} = $vars->{"${prefix}_CLOSE_SKYSCRAPER_AD"};
477 if ($LJ::USE_CONTROL_STRIP && $show_control_strip) {
478 my $control_strip = LJ::control_strip(user => $u->{user});
479 $page->{'control_strip'} = $control_strip;
482 return 1;
485 package LJ::S1w2;
486 use strict;
487 use lib "$ENV{LJHOME}/cgi-bin";
488 use LJ::Config;
489 LJ::Config->load;
491 use LJ::Lang;
492 require "cleanhtml.pl";
494 # the creator for the 'lastn' view:
495 sub create_view_lastn
497 my ($ret, $u, $vars, $remote, $opts) = @_;
499 # Fake S2 context. Bit of a hack.
500 my $s2ctx = [];
501 $s2ctx->[S2::PROPS] = {
502 "page_recent_items" => ($vars->{'LASTN_OPT_ITEMS'}+0) || 20,
504 $opts->{ctx} = $s2ctx;
506 my $s2p = LJ::S2::RecentPage($u, $remote, $opts);
508 my %lastn_page = ();
509 $lastn_page{'name'} = $s2p->{journal}{name};
510 $lastn_page{'name-\'s'} = ($lastn_page{'name'} =~ /s$/i) ? "'" : "'s";
511 $lastn_page{'username'} = $s2p->{journal}{username};
512 $lastn_page{'title'} = LJ::ehtml($u->{'journaltitle'} ||
513 $lastn_page{'name'} . $lastn_page{'name-\'s'} . " Journal");
514 $lastn_page{'numitems'} = ($vars->{'LASTN_OPT_ITEMS'}) || 20;
516 $lastn_page{'urlfriends'} = $s2p->{view_url}{friends};
517 $lastn_page{'urlcalendar'} = $s2p->{view_url}{archive};
519 if ($s2p->{journal}{website_url}) {
520 $lastn_page{'website'} =
521 LJ::fill_var_props($vars, 'LASTN_WEBSITE', {
522 "url" => $s2p->{journal}{website_url},
523 "name" => $s2p->{journal}{website_name} || "My Website",
527 $lastn_page{'events'} = "";
528 $lastn_page{'head'} = $s2p->{head_content};
529 $lastn_page{'head'} .= LJ::res_includes();
530 $lastn_page{'head'} .= $vars->{'GLOBAL_HEAD'} . "\n" . $vars->{'LASTN_HEAD'};
532 my $events = \$lastn_page{'events'};
534 if ($s2p->{journal}{default_pic}{url}) {
535 my $pic = $s2p->{journal}{default_pic};
536 $lastn_page{'userpic'} =
537 LJ::fill_var_props($vars, 'LASTN_USERPIC', {
538 "src" => $pic->{url},
539 "width" => $pic->{width},
540 "height" => $pic->{height},
544 my $eventnum = 0;
545 my $firstday = 1;
546 foreach my $item (@{$s2p->{entries}}) {
547 if ($item->{new_day}) {
548 my %date_format = %{LJ::S1w2::date_s2_to_s1($item->{time})};
549 my %new_day = ();
550 foreach (qw(dayshort daylong monshort monlong m mm yy yyyy d dd dth)) {
551 $new_day{$_} = $date_format{$_};
553 unless ($firstday) {
554 $$events .= LJ::fill_var_props($vars, "LASTN_END_DAY", {});
556 $$events .= LJ::fill_var_props($vars, "LASTN_NEW_DAY", \%new_day);
558 $firstday = 0;
561 $$events .= LJ::S1w2::prepare_event($item, $vars, 'LASTN', $eventnum++);
564 $$events .= LJ::fill_var_props($vars, 'LASTN_END_DAY', {});
566 if ($s2p->{nav}{skip}) {
567 $lastn_page{'range'} =
568 LJ::fill_var_props($vars, 'LASTN_RANGE_HISTORY', {
569 "numitems" => $s2p->{nav}{count},
570 "skip" => $s2p->{nav}{skip},
572 } else {
573 $lastn_page{'range'} =
574 LJ::fill_var_props($vars, 'LASTN_RANGE_MOSTRECENT', {
575 "numitems" => $s2p->{nav}{count},
579 #### make the skip links
580 my ($skip_f, $skip_b) = (0, 0);
581 my %skiplinks;
583 if ($s2p->{nav}{forward_url}) {
584 $skip_f = 1;
586 $skiplinks{'skipforward'} =
587 LJ::fill_var_props($vars, 'LASTN_SKIP_FORWARD', {
588 "numitems" => $s2p->{nav}{forward_count},
589 "url" => $s2p->{nav}{forward_url},
593 my $maxskip = $LJ::MAX_SCROLLBACK_LASTN - $vars->{'LASTN_OPT_ITEMS'};
595 if ($s2p->{nav}{backward_url}) {
596 $skip_b = 1;
598 $skiplinks{'skipbackward'} =
599 LJ::fill_var_props($vars, 'LASTN_SKIP_BACKWARD', {
600 "numitems" => $s2p->{nav}{backward_count},
601 "url" => $s2p->{nav}{backward_url},
605 ### if they're both on, show a spacer
606 if ($skip_b && $skip_f) {
607 $skiplinks{'skipspacer'} = $vars->{'LASTN_SKIP_SPACER'};
610 ### if either are on, put skiplinks into lastn_page
611 if ($skip_b || $skip_f) {
612 $lastn_page{'skiplinks'} =
613 LJ::fill_var_props($vars, 'LASTN_SKIP_LINKS', \%skiplinks);
616 LJ::S1w2::prepare_adverts_and_control_strip($vars, "LASTN", \%lastn_page, $u);
618 $$ret = LJ::fill_var_props($vars, 'LASTN_PAGE', \%lastn_page);
620 return 1;
623 # the creator for the 'friends' view:
624 sub create_view_friends
626 my ($ret, $u, $vars, $remote, $opts) = @_;
627 my $sth;
629 $$ret = "";
631 # Fake S2 context. Bit of a hack.
632 my $s2ctx = [];
633 $s2ctx->[S2::PROPS] = {
634 "page_recent_items" => ($vars->{'FRIENDS_OPT_ITEMS'}+0) || 20,
636 $opts->{ctx} = $s2ctx;
638 my $s2p = LJ::S2::FriendsPage($u, $remote, $opts);
639 return $s2p if ref $s2p ne 'HASH';
641 my %friends_page = ();
642 $friends_page{'name'} = $s2p->{journal}{name};
643 $friends_page{'name-\'s'} = ($friends_page{'name'} =~ /s$/i) ? "'" : "'s";
644 $friends_page{'username'} = $s2p->{journal}{username};
645 $friends_page{'title'} = LJ::ehtml($u->{'friendspagetitle'} ||
646 $friends_page{'name'} . $friends_page{'name-\'s'} . " Friends");
647 $friends_page{'numitems'} = ($vars->{'FRIENDS_OPT_ITEMS'}+0) || 20;
649 $friends_page{'urllastn'} = $s2p->{view_url}{recent};
650 $friends_page{'urlcalendar'} = $s2p->{view_url}{archive};
652 if ($s2p->{journal}{website_url}) {
653 $friends_page{'website'} =
654 LJ::fill_var_props($vars, 'FRIENDS_WEBSITE', {
655 "url" => $s2p->{journal}{website_url},
656 "name" => $s2p->{journal}{website_name} || "My Website",
660 $friends_page{'events'} = "";
661 $friends_page{'head'} = $s2p->{head_content};
662 $friends_page{'head'} .= LJ::res_includes();
663 $friends_page{'head'} .= $vars->{'GLOBAL_HEAD'} . "\n" . $vars->{'LASTN_HEAD'};
665 if ($s2p->{nav}{skip}) {
666 $friends_page{'range'} =
667 LJ::fill_var_props($vars, 'FRIENDS_RANGE_HISTORY', {
668 "numitems" => $s2p->{nav}{count},
669 "skip" => $s2p->{nav}{skip},
671 } else {
672 $friends_page{'range'} =
673 LJ::fill_var_props($vars, 'FRIENDS_RANGE_MOSTRECENT', {
674 "numitems" => $s2p->{nav}{count},
678 #### make the skip links
679 my ($skip_f, $skip_b) = (0, 0);
680 my %skiplinks;
682 if ($s2p->{nav}{forward_url}) {
683 $skip_f = 1;
685 $skiplinks{'skipforward'} =
686 LJ::fill_var_props($vars, 'FRIENDS_SKIP_FORWARD', {
687 "numitems" => $s2p->{nav}{forward_count},
688 "url" => $s2p->{nav}{forward_url},
692 if ($s2p->{nav}{backward_url}) {
693 $skip_b = 1;
695 $skiplinks{'skipbackward'} =
696 LJ::fill_var_props($vars, 'FRIENDS_SKIP_BACKWARD', {
697 "numitems" => $s2p->{nav}{backward_count},
698 "url" => $s2p->{nav}{backward_url},
702 ### if they're both on, show a spacer
703 if ($skip_b && $skip_f) {
704 $skiplinks{'skipspacer'} = $vars->{'FRIENDS_SKIP_SPACER'};
707 ### if either are on, put skiplinks into lastn_page
708 if ($skip_b || $skip_f) {
709 $friends_page{'skiplinks'} =
710 LJ::fill_var_props($vars, 'FRIENDS_SKIP_LINKS', \%skiplinks);
713 unless (%{$s2p->{friends}}) {
714 $friends_page{'events'} = LJ::fill_var_props($vars, 'FRIENDS_NOFRIENDS', {
715 "name" => $friends_page{'name'},
716 "name-\'s" => $friends_page{'name-\'s'},
717 "username" => $friends_page{'username'},
720 $$ret .= LJ::fill_var_props($vars, 'FRIENDS_PAGE', \%friends_page);
721 return 1;
724 my %friends_events = ();
725 my $events = \$friends_events{'events'};
727 my $firstday = 1;
728 my $eventnum = 0;
730 foreach my $item (@{$s2p->{entries}}) {
731 if ($item->{new_day}) {
732 my %date_format = %{LJ::S1w2::date_s2_to_s1($item->{time})};
733 my %new_day = ();
734 foreach (qw(dayshort daylong monshort monlong m mm yy yyyy d dd dth)) {
735 $new_day{$_} = $date_format{$_};
737 unless ($firstday) {
738 $$events .= LJ::fill_var_props($vars, "FRIENDS_END_DAY", {});
740 $$events .= LJ::fill_var_props($vars, "FRIENDS_NEW_DAY", \%new_day);
742 $firstday = 0;
745 $$events .= LJ::S1w2::prepare_event($item, $vars, 'FRIENDS', $eventnum++, $s2p);
748 $$events .= LJ::fill_var_props($vars, 'FRIENDS_END_DAY', {});
749 $friends_page{'events'} = LJ::fill_var_props($vars, 'FRIENDS_EVENTS', \%friends_events);
751 LJ::S1w2::prepare_adverts_and_control_strip($vars, "FRIENDS", \%friends_page, $u);
753 $$ret .= LJ::fill_var_props($vars, 'FRIENDS_PAGE', \%friends_page);
755 return 1;
758 # the creator for the 'calendar' view:
759 sub create_view_calendar
761 my ($ret, $u, $vars, $remote, $opts) = @_;
763 # Fake S2 context. Bit of a hack.
764 my $s2ctx = [];
765 $s2ctx->[S2::PROPS] = {
766 "page_recent_items" => $vars->{'LASTN_OPT_ITEMS'}+0,
768 $opts->{ctx} = $s2ctx;
770 my $s2p = LJ::S2::YearPage($u, $remote, $opts);
772 my $user = $u->{'user'};
774 my %calendar_page = ();
775 $calendar_page{'name'} = $s2p->{journal}{name};
776 $calendar_page{'name-\'s'} = ($calendar_page{'name'} =~ /s$/i) ? "'" : "'s";
777 $calendar_page{'username'} = $user;
778 $calendar_page{'title'} = LJ::ehtml($u->{'journaltitle'} ||
779 $calendar_page{'name'} . $calendar_page{'name-\'s'} . " Journal");
781 $calendar_page{'urlfriends'} = $s2p->{view_url}{friends};
782 $calendar_page{'urllastn'} = $s2p->{view_url}{recent};
784 $calendar_page{'head'} = $s2p->{head_content};
785 $calendar_page{'head'} .= LJ::res_includes();
786 $calendar_page{'head'} .= $vars->{'GLOBAL_HEAD'} . "\n" . $vars->{'CALENDAR_HEAD'};
788 if ($s2p->{journal}{website_url}) {
789 $calendar_page{'website'} = LJ::fill_var_props($vars, 'CALENDAR_WEBSITE', {
790 "url" => $s2p->{journal}{website_url},
791 "name" => $s2p->{journal}{website_name} || "My Website",
795 $calendar_page{'months'} = "";
796 my $months = \$calendar_page{'months'};
798 if (scalar(@{$s2p->{years}}) > 1) {
799 my $yearlinks = "";
800 foreach my $year ($vars->{CALENDAR_SORT_MODE} eq 'reverse' ? reverse @{$s2p->{years}} : @{$s2p->{years}}) {
801 my $yy = sprintf("%02d", $year->{year} % 100);
802 my $url = $year->{url};
803 unless ($year->{displayed}) {
804 $yearlinks .= LJ::fill_var_props($vars, 'CALENDAR_YEAR_LINK', {
805 "url" => $url, "yyyy" => $year->{year}, "yy" => $yy });
806 } else {
807 $yearlinks .= LJ::fill_var_props($vars, 'CALENDAR_YEAR_DISPLAYED', {
808 "yyyy" => $year->{year}, "yy" => $yy });
811 $calendar_page{'yearlinks'} = LJ::fill_var_props($vars, 'CALENDAR_YEAR_LINKS', { "years" => $yearlinks });
814 $$months .= LJ::fill_var_props($vars, 'CALENDAR_NEW_YEAR', {
815 'yyyy' => $s2p->{year},
816 'yy' => substr($s2p->{year}, 2, 2),
819 foreach my $month ($vars->{CALENDAR_SORT_MODE} eq 'reverse' ? reverse @{$s2p->{months}} : @{$s2p->{months}}) {
820 next unless $month->{has_entries};
822 my %calendar_month = ();
823 $calendar_month{'monlong'} = LJ::Lang::month_long($month->{month});
824 $calendar_month{'monshort'} = LJ::Lang::month_short($month->{month});
825 $calendar_month{'yyyy'} = $month->{year};
826 $calendar_month{'yy'} = substr($calendar_month{'yyyy'}, 2, 2);
827 $calendar_month{'weeks'} = "";
828 $calendar_month{'urlmonthview'} = $month->{url};
829 my $weeks = \$calendar_month{'weeks'};
831 foreach my $week (@{$month->{weeks}}) {
832 my %calendar_week = ();
834 $calendar_week{emptydays_beg} = LJ::fill_var_props($vars, 'CALENDAR_EMPTY_DAYS', { "numempty" => $week->{pre_empty} }) if $week->{pre_empty};
835 $calendar_week{emptydays_end} = LJ::fill_var_props($vars, 'CALENDAR_EMPTY_DAYS', { "numempty" => $week->{post_empty} }) if $week->{post_empty};
836 $calendar_week{days} = "";
837 my $days = \$calendar_week{days};
839 foreach my $day (@{$week->{days}}) {
840 my %calendar_day = ();
842 $calendar_day{d} = $day->{date}{day};
843 $calendar_day{eventcount} = $day->{num_entries};
844 $calendar_day{dayevent} = LJ::fill_var_props($vars, 'CALENDAR_DAY_EVENT', {
845 eventcount => $day->{num_entries},
846 dayurl => $day->{url},
847 }) if $day->{num_entries};
848 $calendar_day{daynoevent} = LJ::fill_var_props($vars, 'CALENDAR_DAY_NOEVENT', {}) unless $day->{num_entries};
850 $$days .= LJ::fill_var_props($vars, 'CALENDAR_DAY', \%calendar_day);
853 $$weeks .= LJ::fill_var_props($vars, 'CALENDAR_WEEK', \%calendar_week);
855 $$months .= LJ::fill_var_props($vars, 'CALENDAR_MONTH', \%calendar_month);
858 LJ::S1w2::prepare_adverts_and_control_strip($vars, "CALENDAR", \%calendar_page, $u);
860 $$ret .= LJ::fill_var_props($vars, 'CALENDAR_PAGE', \%calendar_page);
862 return 1;
865 # the creator for the 'day' view:
866 sub create_view_day
868 my ($ret, $u, $vars, $remote, $opts) = @_;
869 my $sth;
871 # Fake S2 context. Bit of a hack.
872 my $s2ctx = [];
873 $s2ctx->[S2::PROPS] = {
874 "page_recent_items" => $vars->{'LASTN_OPT_ITEMS'}+0,
876 $opts->{ctx} = $s2ctx;
878 my $s2p = LJ::S2::DayPage($u, $remote, $opts);
880 my $user = $u->{'user'};
882 my %day_page = ();
883 $day_page{'name'} = $s2p->{journal}{name};
884 $day_page{'name-\'s'} = ($day_page{'name'} =~ /s$/i) ? "'" : "'s";
885 $day_page{'username'} = $user;
886 $day_page{'title'} = LJ::ehtml($u->{'journaltitle'} ||
887 $day_page{'name'} . $day_page{'name-\'s'} . " Journal");
889 $day_page{'urlfriends'} = $s2p->{view_url}{friends};
890 $day_page{'urllastn'} = $s2p->{view_url}{recent};
891 $day_page{'urlcalendar'} = $s2p->{view_url}{archive};
893 $day_page{'head'} = $s2p->{head_content};
894 $day_page{'head'} .= LJ::res_includes();
895 $day_page{'head'} .= $vars->{'GLOBAL_HEAD'} . "\n" . $vars->{'DAY_HEAD'};
897 if ($s2p->{journal}{website_url}) {
898 $day_page{'website'} = LJ::fill_var_props($vars, 'DAY_WEBSITE', {
899 "url" => $s2p->{journal}{website_url},
900 "name" => $s2p->{journal}{website_name} || "My Website",
904 my $date = LJ::S1w2::date_s2_to_s1($s2p->{date});
905 map { $day_page{$_} = $date->{$_} } qw(dayshort daylong monshort monlong yy yyyy m mm d dd dth);
907 $day_page{'prevday_url'} = $s2p->{prev_url};
908 $day_page{'nextday_url'} = $s2p->{next_url};
910 $day_page{'events'} = "";
911 my $events = \$day_page{'events'};
913 my $entries = $s2p->{entries};
914 if (@$entries) {
915 my $inevents = "";
916 foreach my $item ($vars->{DAY_SORT_MODE} eq 'reverse' ? reverse @$entries : @$entries) {
917 $inevents .= LJ::S1w2::prepare_event($item, $vars, 'DAY');
919 $$events = LJ::fill_var_props($vars, 'DAY_EVENTS', { events => $inevents });
921 else {
922 $$events = LJ::fill_var_props($vars, 'DAY_NOEVENTS', {});
925 LJ::S1w2::prepare_adverts_and_control_strip($vars, "DAY", \%day_page, $u);
927 $$ret .= LJ::fill_var_props($vars, 'DAY_PAGE', \%day_page);
928 return 1;
931 # Temporary utility function called by LJ::make_journal in LJ/User.pm
932 # to make a diff between pure S1 output and S1w2 output.
933 sub _make_diff {
934 my ($pure, $mine) = @_;
936 # This is really ghetto, hits the filesystem and
937 # won't work for two concurrent requests, but
938 # it works well enough for a single-user dev server.
939 my $tn1 = "/tmp/s1plain";
940 my $tn2 = "/tmp/s1w2";
941 open(S1PLAIN, '>', $tn1);
942 open(S1w2, '>', $tn2);
943 print S1PLAIN $pure;
944 print S1w2 $mine;
945 close(S1w2);
946 close(S1PLAIN);
947 my $diff = `diff -u $tn1 $tn2`;
948 unlink($tn1);
949 unlink($tn2);
950 return $diff;