You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2014/01/23 18:30:44 UTC

[2/9] git commit: [#4257] Refactors, added doc comments, fixed duplicate paging controls

[#4257] Refactors, added doc comments, fixed duplicate paging controls

Signed-off-by: Cory Johns <cj...@slashdotmedia.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/f1f4ff49
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/f1f4ff49
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/f1f4ff49

Branch: refs/heads/master
Commit: f1f4ff499c4abd3f6137fc6ac24cca71334f0b86
Parents: df82f28
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Sat Jan 18 16:15:43 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:03 2014 +0000

----------------------------------------------------------------------
 .../forgeactivity/nf/activity/css/activity.css  |   7 +-
 .../forgeactivity/nf/activity/js/activity.js    | 150 +++++++++++--------
 .../forgeactivity/templates/index.html          |   1 -
 3 files changed, 96 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f1f4ff49/ForgeActivity/forgeactivity/nf/activity/css/activity.css
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/nf/activity/css/activity.css b/ForgeActivity/forgeactivity/nf/activity/css/activity.css
index 66395ff..f3a5324 100644
--- a/ForgeActivity/forgeactivity/nf/activity/css/activity.css
+++ b/ForgeActivity/forgeactivity/nf/activity/css/activity.css
@@ -49,10 +49,13 @@
 .activity .page_list {
     margin-top: 5px;
 }
-.activity .show-more {
+.activity .no-more.newer {
+    display: none;
+}
+.activity .show-more, .activity .no-more {
     display: block;
     text-align: center;
 }
-.activity .show-more.older {
+.activity .show-more.older, .activity .no-more.older {
     margin-top: 10px;
 }

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f1f4ff49/ForgeActivity/forgeactivity/nf/activity/js/activity.js
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/nf/activity/js/activity.js b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
index e8c0346..a1313c6 100644
--- a/ForgeActivity/forgeactivity/nf/activity/js/activity.js
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -17,8 +17,8 @@
        under the License.
 */
 
-ActivityBrowseOptions = {
-    maintainScrollState: true,
+ASOptions = {
+    maintainScrollHistory: true,
     usePjax: true,
     useHash: true,
     forceAdvancedScroll: false,
@@ -27,18 +27,20 @@ ActivityBrowseOptions = {
 }
 
 $(function() {
-    var hasAPI = window.history && window.history.pushState && window.history.replaceState;
-    var iOS4 = navigator.userAgent.match(/iP(od|one|ad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork/);
-    if (!hasAPI || iOS4) {
-        ActivityBrowseOptions.usePjax = false;
-    }
-    if (!ActivityBrowseOptions.usePjax) {
-        if (!ActivityBrowseOptions.useHash) {
-            ActivityBrowseOptions.maintainScrollState = false;
+    function detectFeatures() {
+        var hasAPI = window.history && window.history.pushState && window.history.replaceState;
+        var iOS4 = navigator.userAgent.match(/iP(od|one|ad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork/);
+        if (!hasAPI || iOS4) {
+            ASOptions.usePjax = false;
         }
-        if (!ActivityBrowseOptions.forceAdvancedScroll) {
-            ActivityBrowseOptions.useShowMore = false;
-            ActivityBrowseOptions.useInfiniteScroll = false;
+        if (!ASOptions.usePjax) {
+            if (!ASOptions.useHash) {
+                ASOptions.maintainScrollHistory = false;
+            }
+            if (!ASOptions.forceAdvancedScroll) {
+                ASOptions.useShowMore = false;
+                ASOptions.useInfiniteScroll = false;
+            }
         }
     }
 
@@ -46,12 +48,20 @@ $(function() {
     var oldScrollTop = null;
     var oldTop = null;
     function saveScrollPosition() {
+        // Save the relative position of the first visible element of
+        // interest for later restore to keep the important visible content
+        // at the same viewport position before / after DOM changes.
+        // TODO: This could be made more generic by making the "interesting
+        // elements" selector configurable.
         var $firstVisible = $('.timeline li:in-viewport:first');
         firstVisibleId = $firstVisible.attr('id');
         oldScrollTop = $(window).scrollTop();
         oldTop = $firstVisible.offset().top;
     }
+
     function restoreScrollPosition() {
+        // Restore the relative position of "interesting" content previously
+        // saved by saveScrollPosition.
         var $window = $(window);
         var $firstVisible = $('#'+firstVisibleId);
         if (!$firstVisible.length) {
@@ -66,7 +76,10 @@ $(function() {
         $(window).trigger('scroll');
     }
 
-    function maintainScrollState_pjax() {
+    function maintainScrollHistory_pjax() {
+        // Use the HTML5 history API to record page and scroll position.
+        // TODO: Page changes should pushState while just scroll changes
+        // should replaceState.
         var $firstVisibleActivity = $('.timeline li:in-viewport:first');
         var page = $firstVisibleActivity.data('page');
         var limit = $('.timeline').data('limit');
@@ -76,7 +89,11 @@ $(function() {
         }
     }
 
-    function maintainScrollState_hash() {
+    function maintainScrollHistory_hash() {
+        // Use the location.hash to record the scroll position.
+        // TODO/FIXME: This doesn't record the page for forceAdvancedPaging, and since
+        // the hash history is additive (confirm?), it can require clicking Back
+        // through all of your scrolling.
         var $firstVisibleActivity = $('.timeline li:in-viewport:first');
         saveScrollPosition();
         window.location.hash = $firstVisibleActivity.attr('id');  // causes jump...
@@ -86,48 +103,63 @@ $(function() {
     var delayed = null;
     function scrollHandler(event) {
         clearTimeout(delayed);
-        delayed = setTimeout(ActivityBrowseOptions.usePjax
-            ? maintainScrollState_pjax
-            : maintainScrollState_hash, 100);
-    }
-
-    function maintainScrollState() {
-        if (!ActivityBrowseOptions.maintainScrollState) {
+        var method = ASOptions.usePjax
+            ? maintainScrollHistory_pjax
+            : maintainScrollHistory_hash;
+        var delay = ASOptions.usePjax
+            ? 100   // scrolls replace history and don't affect scrolling, so more is ok
+            : 750;  // scrolls add history and affect scrolling, so make sure they're done
+        delayed = setTimeout(method, delay);
+    }
+
+    function enableScrollHistory() {
+        // Attempt to record the scroll position in the browser history
+        // using either the HTML5 history API (aka PJAX) or via the location
+        // hash.  Otherwise, when the user clicks a link and then comes back,
+        // they will lose their scroll position and, in the case of advanced
+        // paging, which page they were on.  See: http://xkcd.com/1309/
+        if (!ASOptions.maintainScrollHistory) {
             return;
         }
         $(window).scroll(scrollHandler);
     }
 
     function pageOut(newer) {
+        // Remove a single page of either newer or older content.
         var $timeline = $('.timeline li');
-        var limit = $('.timeline').data('limit') || 100;
+        var limit = $('.timeline').data('limit');
         var range = newer ? [0, limit] : [-limit, undefined];
         $timeline.slice(range[0], range[1]).remove();
-        if (!newer && $('.show-more.older').hasClass('no-more')) {
-            $('.no-more').removeClass('no-more');
-            updateShowMore();
-        }
+        $('.no-more.'+(newer ? 'newer' : 'older')).remove();
     }
-    window.pageOut = pageOut;
 
     function pageIn(newer, url) {
+        // Load a single page of either newer or older content from the URL.
+        // If the added page causes too many to be on screen, calls pageOut
+        // to keep memory usage in check.  Also uses save/restoreScrollPosition
+        // to try to keep the same content in view at the same place.
         $.get(url, function(html) {
+            var $html = $(html);
+            var $timeline = $('.timeline');
+            var limit = $('.timeline').data('limit');
             saveScrollPosition();
-            if (newer) {
-                $('.timeline').prepend(html);
-            } else {
-                if (html.match(/^\s*$/)) {
-                    $('.show-more.older').addClass('no-more');
-                } else {
-                    $('.timeline').append(html);
-                }
+            if ($html.length < limit) {
+                var method = newer ? 'before' : 'after';
+                var cls = newer ? 'newer' : 'older';
+                $timeline[method]('<div class="no-more '+cls+'">No more activities</div>');
             }
+            var method = newer ? 'prepend' : 'append';
+            $timeline[method]($html);
             var firstPage = $('.timeline li:first').data('page');
             var lastPage = $('.timeline li:last').data('page');
             if (lastPage - firstPage >= 3) {
                 pageOut(!newer);
             }
-            if (ActivityBrowseOptions.useShowMore) {
+            if (ASOptions.useShowMore) {
+                // this has to be here instead of showMoreLink handler to
+                // ensure that scroll changes between added / removed content
+                // and Show More links combine properly and don't cause a jump
+                // due to hitting the edge of the page
                 updateShowMore();
             }
             restoreScrollPosition();
@@ -136,56 +168,56 @@ $(function() {
         });
     }
 
-    function makeShowMoreHandler(newer) {
-        // has to be factory to prevent closure memory leak
-        // see: https://www.meteor.com/blog/2013/08/13/an-interesting-kind-of-javascript-memory-leak
-        return function(event) {
-            event.preventDefault();
-            pageIn(newer, this.href);
-        };
-    }
-
     function makeShowMoreLink(newer, targetPage, limit) {
-        var $link = $('<a class="show-more">Show more</a>');
+        var $link = $('<a class="show-more">Show More</a>');
         $link.addClass(newer ? 'newer' : 'older');
         $link.attr('href', 'pjax?page='+targetPage+'&limit='+limit);
-        $link.click(makeShowMoreHandler(newer));  // has to be factory to prevent closure memory leak
+        $link.click(function(event) {
+            event.preventDefault();
+            pageIn(newer, this.href);
+        });
         return $link;
     }
 
     function updateShowMore() {
+        // Update the state of the Show More links when using "Show More"-style
+        // advanced paging.
         var $timeline = $('.timeline');
         if (!$timeline.length) {
             return;
         }
-        var noMoreActivities = $('.show-more.older').hasClass('no-more');
-        $('.page_list, .show-more').remove();
         var limit = $('.timeline').data('limit');
         var firstPage = $('.timeline li:first').data('page');
         var lastPage = $('.timeline li:last').data('page');
-        if (firstPage > 0) {
+        var noMoreNewer = firstPage == 0 || $('.no-more.newer').length;
+        var noMoreOlder = $('.no-more.older').length;
+        $('.show-more').remove();  // TODO: could update HREFs instead of always re-creating links
+        if (!noMoreNewer) {
             $timeline.before(makeShowMoreLink(true, firstPage-1, limit));
         }
-        if (noMoreActivities) {
-            $timeline.after('<div class="show-more older no-more">No more activities</div>');
-        } else {
+        if (!noMoreOlder) {
             $timeline.after(makeShowMoreLink(false, lastPage+1, limit));
         }
     }
-    window.updateShowMore = updateShowMore;
+
+    function enableShowMore() {
+        $('.page_list').remove();
+        updateShowMore();
+    }
 
     function enableInfiniteScroll() {
     }
 
     function enableAdvancedPaging() {
-        if (ActivityBrowseOptions.useInfiniteScroll) {
+        if (ASOptions.useInfiniteScroll) {
             enableInfiniteScroll();
-        } else if (ActivityBrowseOptions.useShowMore) {
-            updateShowMore();
+        } else if (ASOptions.useShowMore) {
+            enableShowMore();
         }
     }
 
-    maintainScrollState();  // http://xkcd.com/1309/
+    detectFeatures();
+    enableScrollHistory();
     enableAdvancedPaging();
 });
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/f1f4ff49/ForgeActivity/forgeactivity/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/index.html b/ForgeActivity/forgeactivity/templates/index.html
index 4b8c162..5b222f7 100644
--- a/ForgeActivity/forgeactivity/templates/index.html
+++ b/ForgeActivity/forgeactivity/templates/index.html
@@ -47,7 +47,6 @@
   {% else %}
     <ul class="timeline" data-limit="{{limit}}">
         {% include 'forgeactivity:templates/timeline.html' %}
-        {{c.page_list.display(limit=1, page=page, count=page+1, show_label=False, show_if_single_page=True, force_next=True)}}
     </ul>
     {{c.page_list.display(limit=1, page=page, count=page+1, show_label=False, show_if_single_page=True, force_next=True)}}
   {% endif %}