Committer: dnikolaev
LJSUP-7813: New thread expander in S2, minimalismU trunk/bin/upgrading/s2layers/core1.s2 U trunk/cgi-bin/LJ/S2/EntryPage.pm U trunk/cgi-bin/LJ/S2.pm U trunk/cgi-bin/LJ/Talk.pm U trunk/htdocs/js/commentmanage.js U trunk/htdocs/js/livejournal.js U trunk/htdocs/js/thread_expander.ex.js U trunk/htdocs/talkread.bml U trunk/htdocs/tools/endpoints/get_thread.bml
Modified: trunk/bin/upgrading/s2layers/core1.s2 =================================================================== --- trunk/bin/upgrading/s2layers/core1.s2 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/bin/upgrading/s2layers/core1.s2 2011-03-30 01:43:48 UTC (rev 18732) @@ -416,6 +416,8 @@ 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."; 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)."; + function builtin print_expand_collapse_links () "Prints links to expand and to collapse this comment."; + 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."; 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."; function edittime_display (string datefmt, string timefmt) : string "edittime_display, with customized date/time formats."; @@ -766,13 +768,13 @@ function print_comments(Comment[] comments) "Prints comments"; function print_comment(Comment comment) "Prints a full comment"; + function print_comment_full(Comment comment) "Prints a expanded comment"; function print_comment_partial(Comment comment) "Prints a collapsed comment"; 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."; function builtin print_multiform_start "Prints start of form tag and hidden elements to do a multi-comment action (multiple delete, screen, unscreen, etc...)"; function builtin print_multiform_end "Prints end of form tag to do a multi-comment action."; 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."; - } class ReplyForm @@ -1671,6 +1673,16 @@ example = "Replies frozen"; maxlength = "50"; } +property string text_comment_deleted { + des = "Text to replace comment body, if it is deleted"; + example = "(Deleted)"; + maxlength = "50"; +} +property string text_comment_screened { + des = "Text to replace comment body, if it is screened"; + example = "(Screened)"; + maxlength = "50"; +} property string text_comment_parent { des = "Text to link to parent comment of current comment"; example = "Parent"; @@ -1686,11 +1698,19 @@ example = "Expand"; maxlength = "50"; } +property string text_comment_collapse { + des = "Text to collapse a expanded comment thread"; + example = "Collapse"; + maxlength = "50"; +} set text_comment_reply = "Reply"; set text_comment_frozen = "Frozen"; +set text_comment_deleted = "(Deleted comment)"; +set text_comment_screened = "(Screened comment)"; set text_comment_parent = "Parent"; set text_comment_thread = "Thread"; set text_comment_expand = "Expand"; +set text_comment_collapse = "Collapse"; property string text_poster_anonymous { des = "The placeholder used when something is posted by an anonymous user"; @@ -2893,6 +2913,9 @@ $c->print_reply_container(); } +function EntryPage::print_comment_full (Comment c) { +} + function EntryPage::print_comment_partial (Comment c) { var string poster = defined $c.poster ? $c.poster->as_string() : "<i>$*text_poster_anonymous</i>"; var string subj = $c.subject != "" ? $c.subject : $*text_nosubject; Modified: trunk/cgi-bin/LJ/S2/EntryPage.pm =================================================================== --- trunk/cgi-bin/LJ/S2/EntryPage.pm 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/cgi-bin/LJ/S2/EntryPage.pm 2011-03-30 01:43:48 UTC (rev 18732) @@ -232,6 +232,7 @@ 'edittime' => $edittime, 'tags' => [], 'full' => $com->{'_loaded'} ? 1 : 0, + 'show' => $com->{'_show'} ? 1 : 0, 'depth' => $depth, 'parent_url' => $par_url, 'spam' => $com->{'state'} eq "B" ? 1 : 0, @@ -300,7 +301,7 @@ } }; $p->{'comments'} = []; - $convert_comments->($convert_comments, $p->{'comments'}, \@comments, 1); + $convert_comments->($convert_comments, $p->{'comments'}, \@comments, ($get->{'depth'} || 0) + 1); # prepare the javascript data structure to put in the top of the page # if the remote user is a manager of the comments @@ -326,7 +327,7 @@ }; my $recurse = sub { - my ($self, $array) = @_; + my ($self, $array, $depth) = @_; foreach my $i (@$array) { my $cmt = LJ::Comment->new($u, dtalkid => $i->{talkid}); @@ -341,12 +342,13 @@ username => $i->{'poster'} ? $i->{'poster'}->{'_u'}->{'user'} : '', parent => $parent && $parent->valid ? $parent->dtalkid : undef, full => ($i->{full}), + depth => $depth, }; - $self->($self, $i->{'replies'}) if $has_threads; + $self->($self, $i->{'replies'}, $depth + 1) if $has_threads; } }; - $recurse->($recurse, $p->{'comments'}); + $recurse->($recurse, $p->{'comments'}, 0); my $js = "<script>\n// don't crawl this. read http://www.livejournal.com/developer/exporting.bml\n"; $js .= "var LJ_cmtinfo = " . LJ::js_dumper($cmtinfo) . "\n"; Modified: trunk/cgi-bin/LJ/S2.pm =================================================================== --- trunk/cgi-bin/LJ/S2.pm 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/cgi-bin/LJ/S2.pm 2011-03-30 01:43:48 UTC (rev 18732) @@ -160,7 +160,7 @@ LJ::run_hooks('head_content', \$page->{head_content}); s2_run($r, $ctx, $opts, $entry, $page); - + if (ref $opts->{'errors'} eq "ARRAY" && @{$opts->{'errors'}}) { return join('', "Errors occurred processing this page:<ul>", @@ -183,7 +183,7 @@ sub s2_run { - my ($r, $ctx, $opts, $entry, $page) = @_; + my ($r, $ctx, $opts, $entry, $page, @args) = @_; $opts ||= {}; local $LJ::S2::CURR_CTX = $ctx; @@ -253,7 +253,7 @@ S2::Builtin::LJ::start_css($ctx) if $css_mode; eval { - S2::run_code($ctx, $entry, $page); + S2::run_code($ctx, $entry, $page, @args); }; S2::Builtin::LJ::end_css($ctx) if $css_mode; @@ -3199,26 +3199,38 @@ $ctx->[S2::PROPS]->{"text_multiform_opt_edit"}, LJ::S2::Image("$LJ::IMGPREFIX/btn_edit.gif", 24, 24)); } - if ($key eq "expand_comments") { + + if ($key eq "expand_comments" or $key eq "collapse_comments") { return $null_link unless LJ::run_hook('show_thread_expander'); - ## show "Expand" link only if + ## show "Expand" or "Collapse" link only if ## 1) the comment is collapsed ## 2) any of comment's children are collapsed - my $show_expand_link; + my $show_link; if (!$this->{full} and !$this->{deleted}) { - $show_expand_link = 1; + $show_link = 1; } else { foreach my $c (@{ $this->{replies} }) { if (!$c->{full} and !$c->{deleted}) { - $show_expand_link = 1; + $show_link = 1; last; } } } - return $null_link unless $show_expand_link; - return LJ::S2::Link("#", ## actual link is javascript: onclick='....' - $ctx->[S2::PROPS]->{"text_comment_expand"}); + return $null_link unless $show_link; + + if ($key eq "expand_comments") { + return LJ::S2::Link( + "#", ## actual link is javascript: onclick='....' + $ctx->[S2::PROPS]->{"text_comment_expand"} + ); + } + else { # $key eq "collapse_comments" + return LJ::S2::Link( + "#", + $ctx->[S2::PROPS]->{"text_comment_collapse"} + ); + } } } @@ -3462,6 +3474,45 @@ $S2::pout->(Comment__expand_link(@_)); } +sub Comment__print_expand_collapse_links +{ + my ($ctx, $this) = @_; + + my $text_expand = LJ::ehtml($ctx->[S2::PROPS]->{"text_comment_expand"}); + my $text_collapse = LJ::ehtml($ctx->[S2::PROPS]->{"text_comment_collapse"}); + + my $print_expand_link = sub { + $S2::pout->( + " <span id='expand_$this->{talkid}'>" . + "(<a href='$this->{thread_url}' onClick=\"ExpanderEx.make(this,'$this->{thread_url}','$this->{talkid}',true);return false;\">$text_expand</a>)" . + "</span>" + ); + }; + + my $print_collapse_link = sub { + $S2::pout->( + " <span id='collapse_$this->{talkid}'>" . + "(<a href='$this->{thread_url}' onClick=\"ExpanderEx.collapse(this,'$this->{thread_url}','$this->{talkid}',true);return false;\">$text_collapse</a>)" . + "</span>" + ); + }; + + my $show_expand_link = sub { + return 1 if !$this->{full} and !$this->{deleted}; + foreach my $c (@{ $this->{replies} }) { + return 1 if !$c->{full} and !$c->{deleted}; + } + return 0; + }; + + if ($show_expand_link->()) { + $print_expand_link->(); + } + elsif ($this->{_show_collapse_link}) { + $print_collapse_link->(); + } +} + sub Page__print_trusted { my ($ctx, $this, $key) = @_; @@ -4526,5 +4577,4 @@ return $lang; } - -1; +1; Modified: trunk/cgi-bin/LJ/Talk.pm =================================================================== --- trunk/cgi-bin/LJ/Talk.pm 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/cgi-bin/LJ/Talk.pm 2011-03-30 01:43:48 UTC (rev 18732) @@ -1273,7 +1273,7 @@ $post->{'state'} eq "S" && ! ($remote && ($remote->{'userid'} == $u->{'userid'} || $remote->{'userid'} == $uposterid || $remote->{'userid'} == $post->{'posterid'} || - $remote->can_manage($u) || + $remote->can_manage($u) || $remote->can_sweep($u))); } if (LJ::is_enabled('spam_button') && !$opts->{showspam}) { @@ -2313,7 +2313,7 @@ # style : 'mine' # showmultiform # nohtml -# show_link_all : if true, show both (Expand) and (Collapse) links; +# show_collapse_link : BOOLEAN - if true, all comments have either "Expand" or "Collapse" link. Otherwise only "Expand" link, if collapsed or has collapsed children; # get_root_only : retrieve only root of requested thread subtree; # depth : initial depth of requested thread (0, if not specified); # talkid @@ -2363,6 +2363,7 @@ init_comobj => 0, showspam => LJ::is_enabled('spam_button') && $input->{mode} eq 'showspam' && !$input->{from_rpc} && $remote && ($remote->can_manage($u) || $remote->can_moderate($u)), + expand_all => 0, }; ## Expand all comments on page @@ -2396,7 +2397,6 @@ my $fmt_time_short = "%%hh%%:%%min%% %%a%%m"; my $jarg = "journal=$u->{'user'}&"; my $jargent ="journal=$u->{'user'}&"; - my $thread_expander_func = LJ::run_hook('show_thread_expander', { is_s1 => 1 }); my $allow_commenting = $entry->posting_comments_allowed; my $pics = LJ::Talk::get_subjecticons(); my $talkurl = LJ::journal_base($u) . "/" . $entry->ditemid() . ".html"; @@ -2412,6 +2412,7 @@ my $tid = $post->{'talkid'}; my $dtid = $tid * 256 + $anum; + my $thread_url = LJ::Talk::talkargs($talkurl, "thread=$dtid", $stylemine, $formatlight) . "#t$dtid"; my $LJci = $LJ_cmtinfo->{$dtid} = { rc => [], u => '', full => $post->{_loaded}, depth => $depth }; my $s2_datetime = $tz_remote ? @@ -2463,7 +2464,7 @@ my $html = {}; my $state; - + if ($post->{'state'} eq "D") ## LJSUP-6433 { $state = 'deleted'; @@ -2522,6 +2523,24 @@ my $icon = LJ::Talk::show_image($pics, $post->{'props'}->{'subjecticon'}); + my $get_expand_link = sub { + return + "<span id='expand_$dtid'>" . + "(<a href='$thread_url' onClick=\"ExpanderEx.make(this,'$thread_url','$dtid',true);return false;\">" . + BML::ml('talk.expandlink') . + "</a>)" . + "</span>"; + }; + + my $get_collapse_link = sub { + return + "<span id='collapse_$dtid'>" . + "(<a href='$thread_url' onClick=\"ExpanderEx.collapse(this,'$thread_url','$dtid',true);return false;\">" . + BML::ml('talk.collapselink') . + "</a>)" . + "</span>"; + }; + if ($post->{'_loaded'}) { $state = 'expanded'; @@ -2743,34 +2762,26 @@ $text .= "(<a href='" . LJ::Talk::talkargs($talkurl, "thread=$dpid", $stylemine, $formatlight) . "#t$dpid'>" . BML::ml('talk.parentlink') . "</a>) "; } - my $thread_url = LJ::Talk::talkargs($talkurl, "thread=$dtid", $stylemine, $formatlight) . "#t$dtid"; my $has_closed_children = 0; if ($post->{'children'} && @{$post->{'children'}}) { $text .= "(<a href='$thread_url'>" . BML::ml('talk.threadlink') . "</a>) "; - if ($thread_expander_func && - (grep {! $_->{_loaded} and !($_->{state} eq "D")} @{$post->{'children'}})) { + if (grep {! $_->{_loaded} and !($_->{state} eq "D")} @{$post->{'children'}}) { $has_closed_children = 1; } } - $LJci->{has_link} = ($has_closed_children ? 1 : 0); + # $LJci->{has_link} = ($has_closed_children ? 1 : 0); - my $link = undef; - if (exists $input->{show_link_all}) { - $link = 'all'; + if (LJ::run_hook('show_thread_expander', { is_s1 => 1 })) { + if ($has_closed_children) { + $text .= ' ' . $get_expand_link->(); + } + elsif ($input->{'show_collapse_link'}) { + $text .= ' ' . $get_collapse_link->(); + } } - elsif ($has_closed_children) { - $link = 'expand'; - } - $text .= $thread_expander_func->({ - thread_id => $dtid, - thread_url => $thread_url, - thread_loaded => 1, - thread_show_link => $link, - }) if $thread_expander_func; - $text .= "</font></p>"; $text .= LJ::make_qr_target($dtid) if $remote; $text .= "</div>"; @@ -2786,16 +2797,11 @@ $html->{header} = $comment_header->(); $html->{footer} = $comment_footer->(); - my $thread_url = LJ::Talk::talkargs($talkurl, "thread=$dtid", $stylemine, $formatlight) . "#t$dtid"; - my $text = "<a href='$thread_url'>" . LJ::ehtml($post->{'subject'} || BML::ml('.nosubject')) . "</a> - $user, <i>$datepost</i> "; - $text .= $thread_expander_func->({ - thread_id => $dtid, - thread_url => $thread_url, - thread_loaded => 0, - has_closed_children => undef, - }) if $thread_expander_func; + if (LJ::run_hook('show_thread_expander', { is_s1 => 1 })) { + $text .= ' ' . $get_expand_link->(); + } # Comment Posted Notice $text .= " - <b>" . BML::ml('.posted') . "</b>" @@ -2808,7 +2814,7 @@ push @$comments, { thread => $dtid, depth => $depth, - html => $html, + html => $html->{header} . $html->{text} . $html->{footer}, state => $state, }; @@ -2826,3 +2832,4 @@ } 1; + Modified: trunk/htdocs/js/commentmanage.js =================================================================== --- trunk/htdocs/js/commentmanage.js 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/htdocs/js/commentmanage.js 2011-03-30 01:43:48 UTC (rev 18732) @@ -100,7 +100,7 @@ return [v,p,q]; } -function deleteComment (ditemid, isS1, action) { +function deleteComment (ditemid, action) { action = action || 'delete'; var curJournal = (Site.currentJournal !== "") ? (Site.currentJournal) : (LJ_cmtinfo.journal); @@ -160,11 +160,11 @@ todel.style.border = ""; // and let timer expire } else if (is_deleted) { - removeComment(ditemid, opt_delthread, isS1); + removeComment(ditemid, opt_delthread); if (opt_delauthor) { for (var item in LJ_cmtinfo) { if (LJ_cmtinfo[item].u == LJ_cmtinfo[ditemid].u) { - removeComment(item, false, isS1); + removeComment(item, false); } } } @@ -176,37 +176,38 @@ window.setTimeout(flash, 5); } -function removeComment (ditemid, killChildren, isS1) { - if(isS1){ +function removeComment (ditemid, killChildren) { + if( LiveJournal.CommentManager.getState() !== 'iframe'){ var threadId = ditemid; - getThreadJSON(threadId, function(result) { - for( var i = 0; i < result.length; ++i ){ - jQuery("#ljcmtxt" + result[i].thread).html( result[i].html ); - if( result[i].thread in ExpanderEx.Collection) - ExpanderEx.Collection[ result[i].thread ] = result[i].html; - } - }); - } - else { - var todel = document.getElementById("ljcmt" + ditemid); - if (todel) { - todel.style.display = 'none'; + LiveJournal.CommentManager.getThreadJSON(threadId, function(result) { + LiveJournal.CommentManager.processThreadJSON( result, function( dtid, html, comment) { + LiveJournal.CommentManager.updateCell( dtid, html ); + if( comment.is_deleted && ( dtid in ExpanderEx.Collection ) ) { + delete ExpanderEx.Collection[ dtid ]; + } + } ); + } ); + } + else { + var todel = document.getElementById("ljcmt" + ditemid); + if (todel) { + todel.style.display = 'none'; - var userhook = window["userhook_delete_comment_ARG"]; - if (userhook) - userhook(ditemid); - } - } - if (killChildren) { - var com = LJ_cmtinfo[ditemid]; - for (var i = 0; i < com.rc.length; i++) { - removeComment(com.rc[i], true, isS1); - } - } + var userhook = window["userhook_delete_comment_ARG"]; + if (userhook) + userhook(ditemid); + } + } + if (killChildren) { + var com = LJ_cmtinfo[ditemid]; + for (var i = 0; i < com.rc.length; i++) { + removeComment(com.rc[i], true); + } + } } -function createDeleteFunction(ae, dItemid, isS1, action) { +function createDeleteFunction(ae, dItemid, action) { action = action || 'delete'; return function (e) { @@ -219,7 +220,7 @@ // immediately delete on shift key if (e.shiftKey) { doIT = 1; - deleteComment(dItemid, isS1, action); + deleteComment(dItemid, action); return true; } @@ -350,7 +351,7 @@ } var tsInProg = {} // dict of { ditemid => 1 } -function createModerationFunction(control, dItemid, isS1, action) { +function createModerationFunction(control, dItemid, action) { var action = action || 'screen', comUser = LJ_cmtinfo[dItemid].u; @@ -391,27 +392,27 @@ } } - if (isS1) { - handleS1(); + if( LiveJournal.CommentManager.getState() !== 'iframe' ) { + handleNew(); } else { - var ids = checkRcForNoCommentsPage(json); - handleS2(ids); - } - }); + var ids = checkRcForNoCommentsPage(); + handleIframe(ids); + } + }); } - - function handleS1() { + + function handleNew() { var newNode, showExpand, j, children, threadId = dItemid, threadExpanded = !!(LJ_cmtinfo[ threadId ].oldvars && LJ_cmtinfo[ threadId ].full); populateComments = function (result) { - for( var i = 0; i < result.length; ++i ){ - if( LJ_cmtinfo[ result[i].thread ].full ){ - showExpand = !( 'oldvars' in LJ_cmtinfo[ result[i].thread ]); + LiveJournal.CommentManager.processThreadJSON( result, function( dtid, html ) { + if( LJ_cmtinfo[ dtid ].full ){ + showExpand = !( 'oldvars' in LJ_cmtinfo[ dtid ]); //still show expand button if children comments are folded if( !showExpand ) { - children = LJ_cmtinfo[ result[i].thread ].rc; + children = LJ_cmtinfo[ dtid ].rc; for( j = 0; j < children.length; ++j ) { if( !( 'oldvars' in LJ_cmtinfo[ children[j] ] ) ) { @@ -420,40 +421,33 @@ } } - if (!result[i].html) { + if (!html) { removeEmptyMarkup(result[i].thread); } - newNode = ExpanderEx.prepareCommentBlock( - result[i].html || '', - result[i].thread || '', - showExpand - ); - - setupAjax( newNode[0], isS1 ); - - jQuery("#ljcmtxt" + result[i].thread).replaceWith( newNode ); + LiveJournal.CommentManager.updateCell( dtid, html ); } - } + } ); hourglass.hide(); poofAt(pos); }; - getThreadJSON(threadId, function (result) { + LiveJournal.CommentManager.getThreadJSON(threadId, function (result) { //if comment is expanded we need to fetch it's collapsed state additionally if( threadExpanded && LJ_cmtinfo[ threadId ].oldvars.full ) { - getThreadJSON( threadId, function (result2) { - ExpanderEx.Collection[ threadId ] = ExpanderEx.prepareCommentBlock( result2[0].html, threadId, true ).html(); + LiveJournal.CommentManager.getThreadJSON( threadId, function (result2) { + ExpanderEx.Collection[ threadId ] = result2[0].html; populateComments( result ); }, true, true ); } - else + else { populateComments( result ); - }, false, !threadExpanded); + } + }, false, !threadExpanded); } - function handleS2(ids) { + function handleIframe(ids) { // modified jQuery.fn.load jQuery.ajax({ url: location.href, @@ -469,28 +463,27 @@ .append(res.responseText.replace(/<script(.|\s)*?\/script>/gi, '')) // Locate the specified elements .find(ids) - .each(function () { - var id = this.id.replace(/[^0-9]/g, ''); - if (LJ_cmtinfo[id].expanded) { - var expand = this.innerHTML.match(/Expander\.make\(.+?\)/)[0]; - (function(){ - eval(expand); - }).apply(document.createElement('a')); - } else { - jQuery('#' + this.id).replaceWith(this); - setupAjax(this, isS1); - } - }); + .each(function () { + var id = this.id.replace(/[^0-9]/g, ''); + if (LJ_cmtinfo[id].expanded) { + var expand = this.innerHTML.match(/Expander\.make\(.+?\)/)[0]; + (function(){ + eval(expand); + }).apply(document.createElement('a')); + } else { + jQuery('#' + this.id).replaceWith(this); + } + }); hourglass.hide(); poofAt(pos); } } - }); + }); } - + function checkRcForNoCommentsPage() { var commsArray = [ dItemid ], ids; - + // check rc for no comments page if (LJ_cmtinfo[dItemid].rc) { if (/mode=(un)?freeze/.test(control.href)) { @@ -517,7 +510,7 @@ function mapComms(id) { var i = -1, newId; - while (newId == LJ_cmtinfo[id].rc[++i]) { + while (newId = LJ_cmtinfo[id].rc[++i]) { if (LJ_cmtinfo[newId].full) { commsArray.push(newId); mapComms(String(newId)); @@ -533,69 +526,132 @@ } function removeEmptyMarkup(threadId) { - jQuery('#ljcmt' + threadId).remove(); + jQuery('#ljcmt' + threadId).remove(); } -function setupAjax (node, isS1) { - var links = node ? node.getElementsByTagName('a') : document.links, - rex_id = /id=(\d+)/, - i = -1, ae; +(function( $, window ) { - isS1 = isS1 || false; - while (links[++i]) { - ae = links[i]; - if (ae.href.indexOf('talkscreen.bml') != -1) { - var reMatch = rex_id.exec(ae.href); - if (!reMatch) continue; + window.LiveJournal.CommentManager = function() { + this.bindLinks(); + } - var id = reMatch[1]; - if (!document.getElementById('ljcmt' + id)) continue; + LiveJournal.CommentManager.prototype.bindLinks = function() { + $( 'body' ).delegate( 'a', 'click', function( ev ) { + var rex_id = /id=(\d+)/, ae = this; - ae.onclick = createModerationFunction(ae, id, isS1); - } else if (ae.href.indexOf('delcomment.bml') != -1) { - if (LJ_cmtinfo && LJ_cmtinfo.disableInlineDelete) continue; + if (ae.href.indexOf('talkscreen.bml') != -1) { + var reMatch = rex_id.exec(ae.href); + if (!reMatch) return; - var reMatch = rex_id.exec(ae.href); - if (!reMatch) continue; + var id = reMatch[1]; + if (!document.getElementById('ljcmt' + id)) return; - var id = reMatch[1]; - if (!document.getElementById('ljcmt' + id)) continue; - + createModerationFunction(ae, id)( ev ); + } else if (ae.href.indexOf('delcomment.bml') != -1) { + if (LJ_cmtinfo && LJ_cmtinfo.disableInlineDelete) return; + + var reMatch = rex_id.exec(ae.href); + if (!reMatch) return; + + var id = reMatch[1]; + if (!document.getElementById('ljcmt' + id)) return; + var action = (ae.href.indexOf('spam=1') != -1) ? 'markAsSpam' : 'delete'; - ae.onclick = createDeleteFunction(ae, id, isS1, action); + createDeleteFunction(ae, id, action)( ev ); // unspam } else if (ae.href.indexOf('spamcomment.bml') != -1) { - var reMatch = rex_id.exec(ae.href); - if (!reMatch) continue; + var reMatch = rex_id.exec(ae.href); + if (!reMatch) return; - var id = reMatch[1]; - if (!document.getElementById('ljcmt' + id)) continue; - - ae.onclick = createModerationFunction(ae, id, isS1, 'unspam'); + var id = reMatch[1]; + if (!document.getElementById('ljcmt' + id)) return; + createModerationFunction(ae, id, 'unspam')( ev ); + } + + ev.preventDefault(); + ev.stopPropagation(); + } ); + } + + var manager = window.LiveJournal.CommentManager; + + window.LiveJournal.CommentManager.getState = function() { + if( LJ_cmtinfo.use_old_thread_expander ) { + return "iframe"; + } else { + return "old"; } - } -} + } -function getThreadJSON(threadId, success, getSingle) -{ - var postid = location.href.match(/\/(\d+).html/)[1], - modeParam = LiveJournal.parseGetArgs(location.href).mode, - params = [ - 'journal=' + Site.currentJournal, - 'itemid=' + postid, - 'thread=' + threadId, - 'depth=' + LJ_cmtinfo[ threadId ].depth - ]; - - if (getSingle) - params.push( 'single=1' ); - - if (modeParam) - params.push( 'mode=' + modeParam ) + /** + * @param {Number} threadId Id of thread to update + * @param {Node} node Collection of nodes with new content + * + * @return {String} Returns a string containing old content of the cell; + */ + LiveJournal.CommentManager.updateCell = function( threadId, node ) { + var cell = $( "#ljcmt" + threadId ), + old_html = $( '<div></div>' ). append( cell.clone() ); - var url = LiveJournal.getAjaxUrl('get_thread') + '?' + params.join( '&' ); - jQuery.get( url, success, 'json' ); + cell.replaceWith( $( node ).filter( "#ljcmt" + threadId ) ); + + return old_html.html(); + } + + LiveJournal.CommentManager.getCell = function( threadId ) { + return $( "#ljcmt" + threadId ); + } + + LiveJournal.CommentManager.getThreadJSON = function(threadId, success, getSingle) + { + var postid = location.href.match(/\/(\d+).html/)[1], + modeParam = LiveJournal.parseGetArgs(location.href).mode, + params = { + journal: Site.currentJournal, + itemid: postid, + thread: threadId, + depth: LJ_cmtinfo[ threadId ].depth + }; + + if( getSingle) { + params.single = '1'; + } + + if (modeParam) { + params.mode = modeParam; + } + + var endpoint = LiveJournal.getAjaxUrl( 'get_thread' ); + jQuery.get( LiveJournal.constructUrl( endpoint, params ), success, 'json' ); + } + + LiveJournal.CommentManager.processThreadJSON = function( result, callback ) { + var comment, dom; + for( var i = 0; i < result.length; ++i ){ + comment = {}; + comment.is_deleted = ( result[i].state === "deleted" ); + if( comment.is_deleted ) { + LJ_cmtinfo[ result[i].thread ].is_deleted = true; + } + dom = $( result[i].html ).filter( "#ljcmt" + result[i].thread ); + callback( result[i].thread, dom, comment ); + } + } + + $( function() { new LiveJournal.CommentManager(); } ); + +}( jQuery, window )) + +function LJ_Mul( a, b ) { return parseInt(a, 10) * parseInt(b, 10) } + +function LJ_JoinURL( url /* parts */ ) { + var add = [].slice.call( arguments, 1 ).join( '&' ); + + url += ( url.indexOf( '?' ) > -1 ) ? '&' : '?'; + return url + add; } -jQuery(function(){setupAjax( false, ("is_s1" in LJ_cmtinfo ) )}); +function LJ_Concat( /* parts */ ) { + return [].slice.call( arguments, 0 ).join( '' ); +} Modified: trunk/htdocs/js/livejournal.js =================================================================== --- trunk/htdocs/js/livejournal.js 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/htdocs/js/livejournal.js 2011-03-30 01:43:48 UTC (rev 18732) @@ -186,6 +186,25 @@ return getArgsHash; }; + +/** + * Construct an url from base string and params object. + * + * @param {String} base Base string. + * @param {Object} args Object with arguments, that have to be passed with the url. + * @return {String} + */ +LiveJournal.constructUrl = function( base, args ) { + var queryStr = base + ( base.indexOf( '?' ) === -1 ? '?' : '&' ), + queryArr = []; + + for( var i in args ) { + queryArr.push( i + '=' + args[i] ); + } + + return queryStr + queryArr.join( '&' ); +} + LiveJournal.closeSiteMessage = function(node, e, id) { jQuery.post(LiveJournal.getAjaxUrl('close_site_message'), { Modified: trunk/htdocs/js/thread_expander.ex.js =================================================================== --- trunk/htdocs/js/thread_expander.ex.js 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/htdocs/js/thread_expander.ex.js 2011-03-30 01:43:48 UTC (rev 18732) @@ -98,11 +98,11 @@ document.body.removeChild(this.iframe); } -ExpanderEx.prototype.isFullComment = function(comment){ +ExpanderEx.prototype.isFullComment = function( comment ) { return !!Number(comment.info.full); } -ExpanderEx.prototype.expandThread = function(json){ +ExpanderEx.prototype.expandThread = function( json ) { this.loadingStateOff(); //we show expand link if comment block has collapsed children @@ -126,14 +126,11 @@ } threadId = json[ i ].thread; - cell = jQuery( '#ljcmtxt' + threadId ); - if( threadId in ExpanderEx.Collection ) { - ExpanderEx.showExpandLink( threadId, cell, isChildCollapsed( i ) ); - continue; //this comment is already expanded - } - ExpanderEx.Collection[ threadId ] = cell.html(); - cell.replaceWith( ExpanderEx.prepareCommentBlock( json[ i ].html, threadId, isChildCollapsed( i ) ) ); + var oldHtml = LiveJournal.CommentManager.updateCell( threadId, json[ i ].html ); + if( !( threadId in ExpanderEx.Collection ) ) { + ExpanderEx.Collection[ threadId ] = oldHtml; + } } //duplicate cycle, because we do not know, that external scripts do with node @@ -159,18 +156,12 @@ ExpanderEx.prototype.collapseBlock = function( id ) { - var expander = this; - function updateBlock(id, html) - { - var el_ = jQuery( '#ljcmtxt' + id ) - .html( html )[0]; - expander.initCommentBlock( el_, id, true ); - } + if( id in ExpanderEx.Collection ) { + LiveJournal.CommentManager.updateCell( id, ExpanderEx.Collection[ id ] ); - if( id in ExpanderEx.Collection ){ - updateBlock( id, ExpanderEx.Collection[ id ] ); - delete ExpanderEx.Collection[ id ]; - } + this.initCommentBlock( LiveJournal.CommentManager.getCell( id )[0], id, true ); + delete ExpanderEx.Collection[ id ]; + } } ExpanderEx.prototype.initCommentBlock = function( el_, id, restoreInitState ) @@ -189,7 +180,7 @@ delete LJ_cmtinfo[ id ].oldvars; } window.ContextualPopup && ContextualPopup.searchAndAdd(el_); - window.setupAjax && setupAjax(el_, true); + //window.setupAjax && setupAjax(el_, true); window.ESN && ESN.initTrackBtns(el_); } @@ -206,55 +197,16 @@ } this.loadingStateOn(); - if( this.id in ExpanderEx.ReqCache ) { - this.expandThread( ExpanderEx.ReqCache[ this.id ] ); - } else { - var obj = this; - //set timeout to allow browser to display image before request - setTimeout( function(){ - getThreadJSON( obj.id, function(result) { - obj.expandThread(result); - ExpanderEx.ReqCache[ obj.id ] = result; - }, false, false, true ); - }, 0 ); - } + var obj = this; + //set timeout to allow browser to display image before request + setTimeout( function(){ + LiveJournal.CommentManager.getThreadJSON( obj.id, function(result) { + obj.expandThread(result); + ExpanderEx.ReqCache[ obj.id ] = result; + }, false, false, true ); + }, 0 ); return true; } -//toggle visibility of expand and collapse links, if server returns -//html with both of them ( with every ajax request) -ExpanderEx.prepareCommentBlock = function(html, id, showExpand){ - var block = jQuery("<td>" + html + "</td>").attr( { - id: 'ljcmtxt' + id, - width: '100%' - } ); - - this.showExpandLink( id, block, showExpand ); - return block; -} - -ExpanderEx.showExpandLink = function ( id, block, showExpand ) { - var expandSel = "#expand_" + id, - collapseSel = "#collapse_" + id, - selector, resetSelector; - - if( LJ_cmtinfo[ id ].has_link > 0 ) { - if( showExpand ) { - selector = collapseSel; - resetSelector = expandSel; - } else { - selector = expandSel; - resetSelector = collapseSel; - } - block.find( resetSelector ).css( 'display', '' ); - } - else { - selector = collapseSel + "," + expandSel; - } - - block.find( selector ) - .css( 'display', 'none' ); -} - ExpanderEx.preloadImg(); Modified: trunk/htdocs/talkread.bml =================================================================== --- trunk/htdocs/talkread.bml 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/htdocs/talkread.bml 2011-03-30 01:43:48 UTC (rev 18732) @@ -517,6 +517,7 @@ showmultiform => $showmultiform, talkid => $GET{talkid}, mode => $GET{mode}, + show_collapse_link => 0, }, $output ); @@ -656,8 +657,8 @@ # Print out each comment if (@$comments > 0) { - $ret .= $_->{html}->{header} . $_->{html}->{text} . $_->{html}->{footer} foreach @$comments; - + $ret .= $_->{html} foreach @$comments; + my $do_commentmanage_js = 1; if ($LJ::DISABLED{'commentmanage'}) { if (ref $LJ::DISABLED{'commentmanage'} eq "CODE") { Modified: trunk/htdocs/tools/endpoints/get_thread.bml =================================================================== --- trunk/htdocs/tools/endpoints/get_thread.bml 2011-03-29 10:24:56 UTC (rev 18731) +++ trunk/htdocs/tools/endpoints/get_thread.bml 2011-03-30 01:43:48 UTC (rev 18732) @@ -113,80 +113,217 @@ return error($errtxt) unless LJ::Talk::check_viewable($remote, $item, \%GET, \$errtxt); } - my $props = $item->{'props'}; - my $nocomments_old = $viewall ? - 0 : - $u->{'opt_showtalklinks'} eq "N" ? 1 : $props->{'opt_nocomments'}; - my $comments_shown = $viewall || $entry->comments_shown; - my $allow_commenting = $entry->posting_comments_allowed; + ### Load necessary props + my @needed_props = ("stylesys", "s2_style"); - LJ::run_hooks("need_res_for_journals", $u); - my $graphicpreviews_obj = LJ::graphicpreviews_obj(); - $graphicpreviews_obj->need_res($u); + LJ::load_user_props($u, @needed_props); - my $showmultiform = $remote && - ($remote->{'user'} eq $u->{'user'} || - $remote->{'user'} eq $up->{'user'} || - $remote->can_manage($u)); + ### Determine style system to preview with + my $get_styleinfo = sub { + my $forceflag = 0; + LJ::run_hooks("force_s1", $u, \$forceflag); + if ( !$forceflag && $u->{'stylesys'} == 2 ) { + return (2, $u->{'s2_style'}); + } + # no special case and not s2, fall through to s1 + return (1, 0); + }; - my $multiform_selects = 0; # are there select boxes? don't show form if not. + my ($stylesys, $styleid) = $get_styleinfo->(); - LJ::run_hook('notify_event_displayed', $entry); + BML::set_content_type('text/javascript; charset=utf-8'); + BML::finish(); + BML::noparse(); - my $LJ_cmtinfo = { # data structure to give to javascript for commentmanage - form_auth => LJ::form_auth(1), - journal => $u->{user}, - canAdmin => ($remote && $remote->can_manage($u)) ? 1 : 0, - remote => $remote ? $remote->{user} : "", - }; + my $use_s1 = 1; + my $ctx = undef; + if ($stylesys == 2) { + $ctx = LJ::S2::s2_context('UNUSED', $styleid); + $LJ::S2::CURR_CTX = $ctx; - my $output = {}; + $use_s1 = 0 unless $ctx->[S2::PROPS]->{"view_entry_disabled"}; + } - my $comments = LJ::Talk::get_thread_html( - $u, - $up, - $entry, - $thread, + if ($use_s1) + { + my $props = $item->{'props'}; + my $nocomments_old = $viewall ? + 0 : + $u->{'opt_showtalklinks'} eq "N" ? 1 : $props->{'opt_nocomments'}; + my $comments_shown = $viewall || $entry->comments_shown; + my $allow_commenting = $entry->posting_comments_allowed; + + LJ::run_hooks("need_res_for_journals", $u); + my $graphicpreviews_obj = LJ::graphicpreviews_obj(); + $graphicpreviews_obj->need_res($u); + + my $showmultiform = $remote && + ($remote->{'user'} eq $u->{'user'} || + $remote->{'user'} eq $up->{'user'} || + $remote->can_manage($u)); + + my $multiform_selects = 0; # are there select boxes? don't show form if not. + + LJ::run_hook('notify_event_displayed', $entry); + + my $LJ_cmtinfo = { # data structure to give to javascript for commentmanage + form_auth => LJ::form_auth(1), + journal => $u->{user}, + canAdmin => ($remote && $remote->can_manage($u)) ? 1 : 0, + remote => $remote ? $remote->{user} : "", + }; + + my $output = {}; + + my ($comments) = LJ::Talk::get_thread_html( + $u, + $up, + $entry, + $thread, + { + page => $GET{page}, + expand => $GET{expand}, + view => $GET{view}, + format => $GET{format}, + style => $init->{style}, + viewsome => $viewsome, + viewall => $viewall, + LJ_cmtinfo => $LJ_cmtinfo, + showmultiform => $showmultiform, + show_collapse_link => 1, + get_root_only => $GET{single} ? 1 : 0, + depth => $GET{depth} || 0, + mode => $GET{mode}, + from_rpc => 1, + }, + $output + ); + + return error($comments) unless ref $comments; + + unless ($comments_shown) { - page => $GET{page}, - expand => $GET{expand}, - view => $GET{view}, - format => $GET{format}, - style => $init->{style}, - viewsome => $viewsome, - viewall => $viewall, - LJ_cmtinfo => $LJ_cmtinfo, - showmultiform => $showmultiform, - show_collapselink => 1, - get_root_only => $GET{single} ? 1 : 0, - show_link_all => 1, - depth => $GET{depth} || 0, - mode => $GET{mode}, - from_rpc => 1, - }, - $output - ); + # TODO: think about it + $comments = []; + } - return error($comments) unless ref $comments; - - unless ($comments_shown) - { - # TODO: think about it - $comments = []; + return LJ::JSON->to_json( [ + map { { + thread => $_->{thread}, + html => $_->{html}, + depth => $_->{depth}, + state => $_->{state}, + } } @$comments + ] ); } + else + { # !$use_s1 + my $ret = ''; + $LJ::S2::ret_ref = \$ret; + + $u->{'_s2styleid'} = $styleid + 0; + $u->{'_journalbase'} = LJ::journal_base($u->{'user'}); - BML::set_content_type('text/javascript; charset=utf-8'); - BML::finish(); - BML::noparse(); + my $opts = { + r => 'UNUSED', + ctx => $ctx, + ljentry => $entry, + getargs => { + thread => $dthread, # $thread + depth => $GET{depth} || 0, + # viewall => ???, + # viewsome => ???, + # style => 'mine', + # defined $get->{'s2id'} ? "s2id=" . int( $get->{'s2id'} ) : "" + # $get->{'page'} - return LJ::JSON->to_json( [ - map { { - thread => $_->{thread}, - html => $_->{html}->{text}, - depth => $_->{depth}, - state => $_->{state}, - } } @$comments - ] ); + # my $view_arg = $get->{'view'} || ""; + # my $flat_mode = ($view_arg =~ /\bflat\b/); + # my $view_num = ($view_arg =~ /(\d+)/) ? $1 : undef; + # 'view' => $view_num, + # 'flat' => $flat_mode, + + # 'viewall' => $viewall, + # 'expand_all' => $opts->{expand_all}, + # 'init_comobj' => 0, + # 'showspam' => $p->{'showspam'} && !$get->{from_rpc}, + }, + }; + + # if (my $class = $view2class->{$view}) { + # $entry = "${class}::print()"; + # no strict 'refs'; + # # this will fail (bogus method), but in non-apache context will bring + # # in the right file because of Class::Autouse above + # eval { "LJ::S2::$class"->force_class_autouse; }; + # my $cv = *{"LJ::S2::$class"}{CODE}; + # die "No LJ::S2::$class function!" unless $cv; + # $page = $cv->($u, $remote, $opts); + # } + + my $page = LJ::S2::EntryPage($u, $remote, $opts); + + my $get_comment_text = sub { + my $comment = shift; + my $ret = ''; + $LJ::S2::ret_ref = \$ret; + + $comment->{_show_collapse_link} = 1; # all comments, retrieved by this endpoint should have expand or collapse link. + + LJ::S2::s2_run('UNUSED', $ctx, undef, "EntryPage::print_comment(Comment)", $page, $comment); + + return $ret; + }; + + my $comments = []; + + my $process_comments = sub { + my ($self, $replies) = @_; + + foreach my $c (@{$replies}) { + my $html = eval { $get_comment_text->($c); }; + return error($@) if $@; + + # my $state = ''; + # if ($c->{deleted}) { + # $state = 'deleted'; + # } elsif ($c->{screened} && !$c->{full} && !$c->{show}) { + # $state = 'screened'; + # # } elsif ($post->{'state'} ne 'B' && $opts->{'showspam'}) { + # # } elsif ($post->{'state'} eq 'B' && !$opts->{'showspam'}) { + # # $state = 'spamed'; + # } elsif ($pu && $pu->is_suspended && !$viewsome) { + # $state = 'suspended'; + # } elsif ($c->{full}) { + # $state = 'expanded'; + # } else { + # $state = 'collapsed'; + # } + + push @$comments, { + thread => $c->{talkid}, + html => $html, + depth => $c->{depth}, + state => ($c->{full} ? 'expanded' : 'collapsed'), # $state, + }; + $self->($self, $c->{replies}) if $c->{replies} && @{$c->{replies}}; + } + }; + + $process_comments->($process_comments, $page->{comments}); + + # $ret =~ s/<\?/<?/g; + # $ret =~ s/\?>/?>/g; + + return LJ::JSON->to_json( [ + map { { + thread => $_->{thread}, + html => $_->{html}, + depth => $_->{depth}, + state => $_->{state}, + } } @$comments + ] ); + } } _code?>