Allow to expand cut tags directly from the page you're viewing them 
from, using an image before the cut.  (The actual link in the cut text will 
still take you to directly to the entry)

        Patch by allen. 

diffs (467 lines):

diff -r 96da559656f8 -r 276a9e18856e bin/upgrading/en.dat
--- a/bin/upgrading/en.dat      Wed Jun 02 10:10:45 2010 +0800
+++ b/bin/upgrading/en.dat      Wed Jun 02 10:50:41 2010 +0800
@@ -1218,6 +1218,8 @@ error.nojournal=Unknown Journal
 error.nojournal=Unknown Journal
 
 error.nojournal.openid=This user is an OpenID account and does not maintain a 
journal here. You might be able to see their content at <a [[aopts]]>[[id]]</a>.
+
+error.nopermission=You do not have permission to view this entry.
 
 error.noschwartz=TheSchwartz not installed or not configured properly.
 
@@ -4231,6 +4233,10 @@ widget.customizetheme.nav.style=Style
 
 widget.customizetheme.title=Customize Your Theme
 
+widget.cuttag.expanded=Collapse
+
+widget.cuttag.collapsed=Expand
+
 widget.feeds.btn.add=Add
 
 widget.feeds.enterrss=enter RSS url
diff -r 96da559656f8 -r 276a9e18856e cgi-bin/DW/Controller/CutExpander.pm
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cgi-bin/DW/Controller/CutExpander.pm      Wed Jun 02 10:50:41 2010 +0800
@@ -0,0 +1,115 @@
+#!/usr/bin/perl
+#
+# DW::Controller::CutExpander
+#
+# AJAX endpoint that returns the expanded text for a cut tag.
+#
+# Author:
+#      Allen Petersen
+#
+# Copyright (c) 2009-2010 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+#
+
+package DW::Controller::CutExpander;
+
+use strict;
+use warnings;
+use DW::Routing;
+use JSON;
+
+DW::Routing->register_string( "/__rpc_cuttag", \&cutexpander_handler, app => 
1, user => 1 );
+
+my $formats = {
+    'json' => [ "application/json; charset=utf-8", sub { $_[0]->print( 
objToJson( $_[1] ) ); } ],
+};
+
+sub cutexpander_handler {
+    my $opts = shift;
+
+    # gets the request and args
+    my $r = DW::Request->get;
+    my $args = $r->get_args;
+
+    my $remote = LJ::get_remote();
+
+    my $format = $formats->{json};
+
+    # error handler
+    my $error_out = sub {
+       my ( $code, $message ) = @_;
+       $r->status( $code );
+       $format->[1]->( $r, { error => $message } );
+
+       return $r->OK;
+    };
+
+    if ( $args->{ditemid} && $args->{journal} && $args->{cutid} ) {
+        # all parameters are included; get the entry.
+        my $ditemid = $args->{ditemid};
+        my $uid = LJ::get_userid( $args->{journal} );
+        my $entry = LJ::Entry->new( $uid, ditemid => $ditemid ) if $uid;
+
+        return $error_out->( 200, BML::ml( "error.nopermission" ) ) unless 
$entry;
+        
+        # make sure the user can read the entry
+        if ( $entry->visible_to( $remote ) ) {
+            my $text = load_cuttext( $entry, $remote, $args->{cutid} );
+            $r->print( objToJson( { text => $text } ) );
+            return $r->OK;
+        }
+    }
+
+    # we have to return as 200 rather than, say, 403 because the httpreq
+    # library won't let us do custom error messages without returning OK.
+    return $error_out->( 200, BML::ml( "error.nopermission" ) );
+}
+
+# loads the cutttext for the given entry
+sub load_cuttext {
+    my ( $entry_obj, $remote, $cutid ) = @_;
+
+    # most of this is taken from S2->Entry_from_entryobj, modified for this
+    # more limited purpose.
+    my $get = {};
+    my $subject = "";
+
+    my $anum = $entry_obj->anum;
+    my $jitemid = $entry_obj->jitemid;
+    my $ditemid = $entry_obj->ditemid;
+
+    # $journal: journal posted to
+    my $journalid = $entry_obj->journalid;
+    my $journal = LJ::load_userid( $journalid );
+
+    # is style=mine used?  or if remote has it on and this entry is not part of
+    # their journal.  if either are yes, it needs to be added to comment links
+    my %opt_stylemine = $remote && $remote->prop( 'opt_stylemine' ) && 
$remote->id != $journalid ? ( style => 'mine' ) : ();
+    my $style_args = LJ::viewing_style_args( %$get, %opt_stylemine );
+    
+    #load and prepare text of entry
+    my $text = LJ::CleanHTML::quote_html( $entry_obj->event_raw, 
$get->{nohtml} );
+    LJ::item_toutf8( $journal, \$subject, \$text ) if $LJ::UNICODE && 
$entry_obj->props->{unknown8bit};
+
+    my $suspend_msg = $entry_obj && $entry_obj->should_show_suspend_msg_to( 
$remote ) ? 1 : 0;
+    # cleaning the entry text: cuts and such
+    my $cleanhtml_opts = { cuturl => LJ::item_link( $journal, $jitemid, $anum, 
$style_args ),
+        journal => $journal->username,
+        ditemid => $ditemid,
+        suspend_msg => $suspend_msg,
+        unsuspend_supportid => $suspend_msg ? $entry_obj->prop( 
'unsuspend_supportid' ) : 0,
+        preformatted => $entry_obj->prop( "opt_preformatted" ),
+        cut_retrieve => $cutid, 
+    };
+
+    LJ::CleanHTML::clean_event( \$text, $cleanhtml_opts );
+
+    LJ::expand_embedded( $journal, $jitemid, $remote, \$text );
+    
+    return $text;
+}
+
+1;
diff -r 96da559656f8 -r 276a9e18856e cgi-bin/LJ/CleanHTML.pm
--- a/cgi-bin/LJ/CleanHTML.pm   Wed Jun 02 10:10:45 2010 +0800
+++ b/cgi-bin/LJ/CleanHTML.pm   Wed Jun 02 10:50:41 2010 +0800
@@ -142,6 +142,10 @@ sub clean
     my $to_external_site = $opts->{to_external_site} || 0;
     my $remove_positioning = $opts->{'remove_positioning'} || 0;
     my $errref = $opts->{errref};
+    # for ajax cut tag parsing
+    my $cut_retrieve =  $opts->{cut_retrieve} || 0;
+    my $journal = $opts->{journal} || "";
+    my $ditemid = $opts->{ditemid} || "";
 
     my @canonical_urls; # extracted links
     my %action = ();
@@ -269,6 +273,12 @@ sub clean
         }->{$_[0]} || $_[0];
     };
 
+    
+    # if we're retrieving a cut tag, then we want to eat everything 
+    # until we hit the first cut tag.
+    my @cuttag_stack = ();
+    my $eatall = $cut_retrieve ? 1 : 0;
+    
   TOKEN:
     while (my $token = $p->get_token)
     {
@@ -288,9 +298,19 @@ sub clean
 
             if (@eatuntil) {
                 push @capture, $token if $capturing_during_eat;
+                # have to keep the cut counts consistent even if they're nested
+                if ( $tag eq "lj-cut" ) {
+                    $cutcount++;
+                }
                 if ($tag eq $eatuntil[-1]) {
                     push @eatuntil, $tag;
                 }
+                next TOKEN;
+            }
+
+            # if we're looking for cut tags, ignore everything that's
+            # not a cut tag.
+            if ( $eatall && ! $tag eq "lj-cut" ) {
                 next TOKEN;
             }
 
@@ -433,6 +453,18 @@ sub clean
             if (($tag eq "lj-cut" || $ljcut_div)) {
                 next TOKEN if $ljcut_disable;
                 $cutcount++;
+
+                # if this is the cut tag we're looking for, then push it
+                # onto the stack (in case there are nested cut tags) and
+                # start including the content.
+                if ( $eatall ) {
+                    if ( $cutcount == $cut_retrieve ) {
+                        $eatall = 0;
+                        push @cuttag_stack, $tag;
+                    }
+                    next TOKEN;
+                }
+
                 my $link_text = sub {
                     my $text = "Read more...";
                     if ($attr->{'text'}) {
@@ -449,12 +481,20 @@ sub clean
                     my $etext = $link_text->();
                     my $url = LJ::ehtml($cut);
                     $newdata .= "<div>" if $tag eq "div";
+
+                    # include empty span and div to be filled in on page
+                    # load if javascript is enabled
+                    $newdata .= "<span style=\"display: none;\" 
id=\"span-cuttag_" . $journal . "_" . $ditemid . "_" . $cutcount. "\" 
class=\"cuttag\"></span>";
                     $newdata .= "<b>(&nbsp;<a 
href=\"$url#cutid$cutcount\">$etext</a>&nbsp;)</b>";
+                    $newdata .= "<div style=\"display: none;\" 
id=\"div-cuttag_" . $journal . "_" . $ditemid . "_" . $cutcount ."\" 
aria-live=\"assertive\">";
+                    $newdata .="</div>";
                     $newdata .= "</div>" if $tag eq "div";
+
                     unless ($opts->{'cutpreview'}) {
                         push @eatuntil, $tag;
                         next TOKEN;
                     }
+
                 } else {
                     $newdata .= "<a name=\"cutid$cutcount\"></a>" unless 
$opts->{'textonly'};
                     if ($tag eq "div" && !$opts->{'textonly'}) {
@@ -849,6 +889,21 @@ sub clean
 
                 next TOKEN if @eatuntil;
             }
+            
+            # if we're just getting the contents of a cut tag, then pop the
+            # tag off the stack.  if this is the last tag on the stack, then
+            # go back to eating the rest of the content.
+            if ( @cuttag_stack ) {
+                if ( $cuttag_stack[-1] eq $tag ) {
+                    pop @cuttag_stack;
+                    
+                    $eatall = 1 unless ( @cuttag_stack );
+                }
+            }
+            
+            if ( $eatall ) {
+                next TOKEN;
+            }
 
             if ( $eating_ljuser_span ) {
                 if ( $tag eq "span" ) {
@@ -940,6 +995,10 @@ sub clean
 
             if (@eatuntil) {
                 push @capture, $token if $capturing_during_eat;
+                next TOKEN;
+            }
+
+            if ( $eatall ) {
                 next TOKEN;
             }
 
@@ -1332,6 +1391,9 @@ sub clean_event
         'suspend_msg' => $opts->{'suspend_msg'} ? 1 : 0,
         'unsuspend_supportid' => $opts->{'unsuspend_supportid'},
         to_external_site => $opts->{to_external_site} ? 1 : 0,
+        cut_retrieve => $opts->{cut_retrieve},
+        journal => $opts->{journal},
+        ditemid => $opts->{ditemid},
         errref => $opts->{errref},
     });
 }
diff -r 96da559656f8 -r 276a9e18856e cgi-bin/LJ/S2.pm
--- a/cgi-bin/LJ/S2.pm  Wed Jun 02 10:10:45 2010 +0800
+++ b/cgi-bin/LJ/S2.pm  Wed Jun 02 10:50:41 2010 +0800
@@ -1936,6 +1936,8 @@ sub Entry_from_entryobj
         my $cut_disable = $opts->{cut_disable};
         my $cleanhtml_opts = { cuturl => LJ::item_link( $journal, $jitemid, 
$anum, $style_args ),
             ljcut_disable => $cut_disable,
+            journal => $journal->username,
+            ditemid => $ditemid,
             suspend_msg => $suspend_msg,
             unsuspend_supportid => $suspend_msg ? $entry_obj->prop( 
'unsuspend_supportid' ) : 0,
             preformatted => $entry_obj->prop( "opt_preformatted" ),
diff -r 96da559656f8 -r 276a9e18856e cgi-bin/LJ/S2/DayPage.pm
--- a/cgi-bin/LJ/S2/DayPage.pm  Wed Jun 02 10:10:45 2010 +0800
+++ b/cgi-bin/LJ/S2/DayPage.pm  Wed Jun 02 10:50:41 2010 +0800
@@ -32,6 +32,17 @@ sub DayPage
     if ($u->should_block_robots) {
         $p->{'head_content'} .= LJ::robot_meta_tags();
     }
+
+    # load for ajax cuttag
+    LJ::need_res( 'js/cuttag-ajax.js' );
+    my $collapsed = BML::ml( 'widget.cuttag.collapsed' );
+    my $expanded = BML::ml( 'widget.cuttag.expanded' );
+    $p->{'head_content'} .= qq[
+  <script type='text/javascript'>
+  expanded = '$expanded';
+  collapsed = '$collapsed';
+  </script>
+    ];
 
     my $get = $opts->{'getargs'};
 
diff -r 96da559656f8 -r 276a9e18856e cgi-bin/LJ/S2/FriendsPage.pm
--- a/cgi-bin/LJ/S2/FriendsPage.pm      Wed Jun 02 10:10:45 2010 +0800
+++ b/cgi-bin/LJ/S2/FriendsPage.pm      Wed Jun 02 10:50:41 2010 +0800
@@ -35,6 +35,17 @@ sub FriendsPage
 
     # Add a friends-specific XRDS reference
     $p->{'head_content'} .= qq{<meta http-equiv="X-XRDS-Location" 
content="}.LJ::ehtml($u->journal_base).qq{/data/yadis/friends" />\n};
+
+    # load for ajax cuttag
+    LJ::need_res( 'js/cuttag-ajax.js' );
+    my $collapsed = BML::ml( 'widget.cuttag.collapsed' );
+    my $expanded = BML::ml( 'widget.cuttag.expanded' );
+    $p->{'head_content'} .= qq[
+  <script type='text/javascript'>
+  expanded = '$expanded';
+  collapsed = '$collapsed';
+  </script>
+    ];
 
     my $sth;
     my $user = $u->{'user'};
diff -r 96da559656f8 -r 276a9e18856e cgi-bin/LJ/S2/RecentPage.pm
--- a/cgi-bin/LJ/S2/RecentPage.pm       Wed Jun 02 10:10:45 2010 +0800
+++ b/cgi-bin/LJ/S2/RecentPage.pm       Wed Jun 02 10:50:41 2010 +0800
@@ -81,6 +81,17 @@ sub RecentPage
     if (my $icbm = $u->prop("icbm")) {
         $p->{'head_content'} .= qq{<meta name="ICBM" content="$icbm" />\n};
     }
+
+    # load for ajax cuttag
+    LJ::need_res( 'js/cuttag-ajax.js' );
+    my $collapsed = BML::ml( 'widget.cuttag.collapsed' );
+    my $expanded = BML::ml( 'widget.cuttag.expanded' );
+    $p->{'head_content'} .= qq[
+  <script type='text/javascript'>
+  expanded = '$expanded';
+  collapsed = '$collapsed';
+  </script>
+    ];
 
     my $itemshow = S2::get_property_value($opts->{'ctx'}, 
"num_items_recent")+0;
     if ($itemshow < 1) { $itemshow = 20; }
diff -r 96da559656f8 -r 276a9e18856e htdocs/js/cuttag-ajax.js
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/js/cuttag-ajax.js  Wed Jun 02 10:50:41 2010 +0800
@@ -0,0 +1,116 @@
+// functions for ajaxifying cut tags
+
+CutTagHandler = new Class(Object, {
+    // initializes a new CutTagHandler for the cuttag defined by the
+    // given journal, ditemid, and cutid
+    init: function(journal, ditemid, cutid) {
+      this.identifier = 'cuttag_' + journal + '_' + ditemid + '_' + cutid;
+      this.ajaxUrl = "/__rpc_cuttag?journal=" + journal + "&ditemid=" + 
ditemid + "&cutid=" + cutid;
+    },
+
+    // returns if the div controlled by this handler is open
+    isOpen: function() {
+      return ( DOM.hasClassName( $("div-" + this.identifier), "cuttag-open" ) 
);
+    },
+
+    // opens or closes the controlled div, as appropriate
+    toggle: function() {
+      if ( this.isOpen() ) {
+        this.close();
+      } else {
+        this.open();
+      }
+    },
+
+    // closes the controlled div
+    close: function() {
+      $("img-" + this.identifier).src= Site.imgprefix + "/collapse.gif";
+      $("div-" + this.identifier).innerHTML="";
+      $("div-" + this.identifier).style.display = "none";
+      DOM.removeClassName($("div-" + this.identifier), "cuttag-open");
+      $('img-' + this.identifier).alt=collapsed;
+      $('img-' + this.identifier).title=collapsed;
+    },
+
+    // opens the cut tag inline
+    open: function() {
+      var opts = {
+        "async": true,
+        "method": "GET",
+        "url": this.ajaxUrl,
+        "onData": this.replaceCutTag.bindEventListener(this),
+        "onError": this.handleError.bindEventListener(this)
+      };
+
+      // ajax call.
+      window.parent.HTTPReq.getJSON(opts);
+    },
+
+    // callback for the getJSON call.  just throws up the error as an alert.
+    handleError: function(err) {
+      alert(err);
+    },
+
+    // callback for the getJSON call.  if the response is an error, calls
+    // handlerObj.handleError(responseObject.error).  otherwise replaces the
+    // cut tag with the contents of the cut.
+    replaceCutTag: function(resObj) {
+      if (resObj.error) {
+        this.handleError(resObj.error);
+      } else {
+        var replaceDiv = $('div-' + this.identifier);
+        replaceDiv.innerHTML=resObj.text;
+        replaceDiv.style.display="block";
+        DOM.addClassName(replaceDiv, "cuttag-open");
+        $('img-' + this.identifier).alt=expanded;
+        $('img-' + this.identifier).title=expanded;
+        $("img-" + this.identifier).src= Site.imgprefix + "/expand.gif";
+        CutTagHandler.initLinks(replaceDiv);
+      }
+    }
+  });
+
+// called by the onclick handler of the anchor tag
+CutTagHandler.toggleCutTag = function(journal, ditemid, cutid) {
+  try {
+    var ctHandler = new CutTagHandler(journal, ditemid, cutid);
+
+    ctHandler.toggle();
+
+    return false;
+  } catch (ex) {
+    return true;
+  }
+}
+
+// fills the given tag (a span) with the appropriate <a> and <img> tags
+// for the expand/collapse button
+CutTagHandler.writeExpandTag = function(tag, journal, ditemid, cutid) {
+  var identifier = journal + '_' + ditemid + '_' + cutid;
+  tag.style.display = 'inline'
+  tag.innerHTML = '<a href="#" onclick="return CutTagHandler.toggleCutTag(\'' 
+ journal + '\', \'' + ditemid + '\', \'' + cutid + '\');" id="cuttag_' + 
identifier +'" ><img style="border: 0;" id="img-cuttag_' + identifier + '" 
src="' + Site.imgprefix + '/collapse.gif" aria-controls="div-cuttag_' + 
identifier + '" alt="' + collapsed + '" title="' + collapsed + '"/></a>';
+}
+
+
+// initializes all <span> tags with the 'cuttag' class that are contained
+// by the given parentTag
+CutTagHandler.initLinks = function(parentTag) {
+  var domObjects = parentTag.getElementsByTagName("span");
+  var items = DOM.filterElementsByClassName(domObjects, "cuttag") || [];
+
+  for (var i = 0; i < items.length; i++) {
+    var spanid = items[i].id;
+    var journal = spanid.replace( /^span-cuttag_(.*)_[0-9]+_[0-9]+/, "$1");
+    var ditemid = spanid.replace( /^.*_([0-9]+)_[0-9]+/, "$1");
+    var cutid = spanid.replace( /^.*_([0-9]+)/, "$1");
+    CutTagHandler.writeExpandTag(items[i], journal, ditemid, cutid);
+  }
+}
+
+// called at page load to initialize all <span> tags with the 'cuttag' class.
+CutTagHandler.initAllLinks = function() {
+  CutTagHandler.initLinks(document);
+}
+
+// calls CutTagHandler.initAllLinks on page load.
+LiveJournal.register_hook("page_load", CutTagHandler.initAllLinks);
_______________________________________________
dw-changelog mailing list
[email protected]
http://lists.dwscoalition.org/mailman/listinfo/dw-changelog

Reply via email to