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:36:29 UTC

[01/10] git commit: [#4257] Added basic paging to Activity page

Updated Branches:
  refs/heads/cj/4395 5870b080e -> a0b991277 (forced update)


[#4257] Added basic paging to Activity page

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/28f74b11
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/28f74b11
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/28f74b11

Branch: refs/heads/cj/4395
Commit: 28f74b117b018468a80558824601a085afd2cb90
Parents: 88b2500
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Sat Jan 18 00:46:57 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:26:26 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/widgets/form_fields.py         | 14 +++++++++++++-
 Allura/allura/templates/widgets/page_list.html   |  6 ++++--
 ForgeActivity/forgeactivity/main.py              | 13 +++++++++++--
 ForgeActivity/forgeactivity/templates/index.html |  1 +
 4 files changed, 29 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/28f74b11/Allura/allura/lib/widgets/form_fields.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/form_fields.py b/Allura/allura/lib/widgets/form_fields.py
index 2249372..e3060dc 100644
--- a/Allura/allura/lib/widgets/form_fields.py
+++ b/Allura/allura/lib/widgets/form_fields.py
@@ -285,7 +285,9 @@ class PageList(ew_core.Widget):
         limit=None,
         count=0,
         page=0,
-        show_label=False)
+        show_label=True,
+        show_if_single_page=False,
+        force_next=False)
 
     def paginator(self, count, page, limit, zero_based_pages=True):
         page_offset = 1 if zero_based_pages else 0
@@ -298,6 +300,16 @@ class PageList(ew_core.Widget):
         return paginate.Page(range(count), page + page_offset, int(limit),
                              url=page_url)
 
+    def prepare_context(self, context):
+        context = super(PageList, self).prepare_context(context)
+        count = context['count']
+        page = context['page']
+        limit = context['limit']
+        context['paginator'] = self.paginator(count, page, limit)
+        if context['force_next']:
+            context['paginator'].next_page = context['paginator'].page + 1
+        return context
+
     def resources(self):
         yield ew.CSSLink('css/page_list.css')
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/28f74b11/Allura/allura/templates/widgets/page_list.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/page_list.html b/Allura/allura/templates/widgets/page_list.html
index a5f39b2..64ff18f 100644
--- a/Allura/allura/templates/widgets/page_list.html
+++ b/Allura/allura/templates/widgets/page_list.html
@@ -18,8 +18,10 @@
 -#}
 <div>
   <div class="page_list">
-    {% set paginator = widget.paginator(count, page, limit) %}
-    {{paginator.pager('$link_first $link_previous ~2~ $link_next $link_last (Page $page of $page_count)')}}
+    {{paginator.pager(
+            format='$link_first $link_previous ~2~ $link_next $link_last' + (show_label and ' (Page $page of $page_count)' or ''),
+            show_if_single_page=show_if_single_page
+        )}}
   </div>
   <div class="clear"></div>
 </div>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/28f74b11/ForgeActivity/forgeactivity/main.py
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/main.py b/ForgeActivity/forgeactivity/main.py
index da81307..991bb61 100644
--- a/ForgeActivity/forgeactivity/main.py
+++ b/ForgeActivity/forgeactivity/main.py
@@ -22,7 +22,7 @@ from pylons import tmpl_context as c, app_globals as g
 from pylons import request, response
 from tg import expose, validate, config
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from paste.deploy.converters import asbool
+from paste.deploy.converters import asbool, asint
 from webob import exc
 from webhelpers import feedgenerator as FG
 
@@ -33,6 +33,7 @@ from allura.lib.security import require_authenticated
 from allura.model.timeline import perm_check
 from allura.lib import helpers as h
 from allura.lib.decorators import require_post
+from allura.lib.widgets.form_fields import PageList
 from allura.ext.user_profile import ProfileSectionBase
 
 from .widgets.follow import FollowToggle
@@ -65,6 +66,7 @@ class ForgeActivityApp(Application):
 
 class W:
     follow_toggle = FollowToggle()
+    page_list = PageList()
 
 
 class ForgeActivityController(BaseController):
@@ -91,6 +93,7 @@ class ForgeActivityController(BaseController):
             raise exc.HTTPNotFound()
 
         c.follow_toggle = W.follow_toggle
+        c.page_list = W.page_list
         if c.project.is_user_project:
             followee = c.project.user_project_of
             actor_only = followee != c.user
@@ -103,7 +106,13 @@ class ForgeActivityController(BaseController):
                                            limit=kw.get('limit', 100),
                                            actor_only=actor_only,
                                            filter_func=perm_check(c.user))
-        return dict(followee=followee, following=following, timeline=timeline)
+        return dict(
+                followee=followee,
+                following=following,
+                timeline=timeline,
+                page=asint(kw.get('page', 0)),
+                limit=asint(kw.get('limit', 100)),
+            )
 
     @expose('jinja:forgeactivity:templates/index.html')
     @with_trailing_slash

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/28f74b11/ForgeActivity/forgeactivity/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/index.html b/ForgeActivity/forgeactivity/templates/index.html
index 435fc82..e63c904 100644
--- a/ForgeActivity/forgeactivity/templates/index.html
+++ b/ForgeActivity/forgeactivity/templates/index.html
@@ -57,6 +57,7 @@
           {% endif %}
         </li>
         {% endfor %}
+        {{c.page_list.display(limit=1, page=page, count=page+1, show_label=False, show_if_single_page=True, force_next=True)}}
     </ul>
   {% endif %}
 </div>


[04/10] git commit: [#4257] Disable hash-based scroll management as it's not worth it

Posted by jo...@apache.org.
[#4257] Disable hash-based scroll management as it's not worth it

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/de4f5b71
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/de4f5b71
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/de4f5b71

Branch: refs/heads/cj/4395
Commit: de4f5b715c58a9d04945f14259351c886cf962a0
Parents: a3c5bf7
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Jan 22 17:12:35 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:04 2014 +0000

----------------------------------------------------------------------
 ForgeActivity/forgeactivity/nf/activity/js/activity.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/de4f5b71/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 80b79d8..0ed3b0e 100644
--- a/ForgeActivity/forgeactivity/nf/activity/js/activity.js
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -21,7 +21,7 @@ ASOptions = {
     maxPages: 3,
     maintainScrollHistory: true,
     usePjax: true,
-    useHash: true,
+    useHash: false, // not worth the jitter
     forceAdvancedScroll: false,
     useShowMore: false,
     useInfiniteScroll: true


[05/10] git commit: [#4257] Fixed page back to start, and more refactors

Posted by jo...@apache.org.
[#4257] Fixed page back to start, and more refactors

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/3d9ff04e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/3d9ff04e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/3d9ff04e

Branch: refs/heads/cj/4395
Commit: 3d9ff04e51d3a5ef3e1a4871954b3253f00a5b70
Parents: f1f4ff4
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Sun Jan 19 01:14:51 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:04 2014 +0000

----------------------------------------------------------------------
 .../forgeactivity/nf/activity/js/activity.js    | 66 ++++++++++++--------
 1 file changed, 41 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3d9ff04e/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 a1313c6..48b699f 100644
--- a/ForgeActivity/forgeactivity/nf/activity/js/activity.js
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -18,6 +18,7 @@
 */
 
 ASOptions = {
+    maxPages: 3,
     maintainScrollHistory: true,
     usePjax: true,
     useHash: true,
@@ -27,6 +28,17 @@ ASOptions = {
 }
 
 $(function() {
+    if (!$('.timeline li').length) {
+        return;  // no timeline, no paging
+    }
+
+    $.expr[':']['timeline-page'] = $.expr.createPseudo(function(page) {
+        // Select timeline elements by their page.  NB: only works on activity LIs.
+        return function(elem) {
+            return $(elem).data('page') == page;
+        }
+    });
+
     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/);
@@ -72,7 +84,6 @@ $(function() {
         var elemAdjustment = newTop - oldTop;
         var viewportAdjustment = scrollTop - oldScrollTop;
         $window.scrollTop(scrollTop + elemAdjustment - viewportAdjustment);
-        //console.log('restoreSP', oldTop, newTop, elemAdjustment, viewportAdjustment, scrollTop, $window.scrollTop());
         $(window).trigger('scroll');
     }
 
@@ -125,36 +136,35 @@ $(function() {
     }
 
     function pageOut(newer) {
-        // Remove a single page of either newer or older content.
+        // Remove newest or oldest page to keep memory usage in check.
         var $timeline = $('.timeline li');
-        var limit = $('.timeline').data('limit');
-        var range = newer ? [0, limit] : [-limit, undefined];
-        $timeline.slice(range[0], range[1]).remove();
+        var firstPage = $timeline.first().data('page');
+        var lastPage = $timeline.last().data('page');
+        var numPages = lastPage - firstPage + 1;
+        if (numPages <= ASOptions.maxPages) {
+            return;
+        }
+        var pageToRemove = newer ? firstPage : lastPage;
+        $('.timeline li:timeline-page('+pageToRemove+')').remove();
         $('.no-more.'+(newer ? 'newer' : 'older')).remove();
     }
 
     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
+        // Then calls pageOut to ensure that not too many are loaded at once,
         // 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 newPage = $html.data('page');
             var limit = $('.timeline').data('limit');
             saveScrollPosition();
-            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 ($html.length < limit || newPage == 0) {
+                makeNoMore(newer);
             }
+            $timeline[newer ? 'prepend' : 'append']($html);
+            pageOut(!newer);
             if (ASOptions.useShowMore) {
                 // this has to be here instead of showMoreLink handler to
                 // ensure that scroll changes between added / removed content
@@ -168,6 +178,13 @@ $(function() {
         });
     }
 
+    function makeNoMore(newer) {
+        var $timeline = $('.timeline');
+        var method = newer ? 'before' : 'after';
+        var cls = newer ? 'newer' : 'older';
+        $timeline[method]('<div class="no-more '+cls+'">No more activities</div>');
+    }
+
     function makeShowMoreLink(newer, targetPage, limit) {
         var $link = $('<a class="show-more">Show More</a>');
         $link.addClass(newer ? 'newer' : 'older');
@@ -176,32 +193,31 @@ $(function() {
             event.preventDefault();
             pageIn(newer, this.href);
         });
-        return $link;
+        $('.timeline')[newer ? 'before' : 'after']($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 limit = $('.timeline').data('limit');
         var firstPage = $('.timeline li:first').data('page');
         var lastPage = $('.timeline li:last').data('page');
-        var noMoreNewer = firstPage == 0 || $('.no-more.newer').length;
+        var noMoreNewer = $('.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));
+            makeShowMoreLink(true, firstPage-1, limit);
         }
         if (!noMoreOlder) {
-            $timeline.after(makeShowMoreLink(false, lastPage+1, limit));
+            makeShowMoreLink(false, lastPage+1, limit);
         }
     }
 
     function enableShowMore() {
         $('.page_list').remove();
+        if ($('.timeline li:first').data('page') == 0) {
+            makeNoMore(true);
+        }
         updateShowMore();
     }
 


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

Posted by jo...@apache.org.
[#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/cj/4395
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 %}


[06/10] git commit: [#4257] Added infinite scroll

Posted by jo...@apache.org.
[#4257] Added infinite scroll

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/23ad4247
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/23ad4247
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/23ad4247

Branch: refs/heads/cj/4395
Commit: 23ad4247bb7b7f9461d8f79c715f2954f5d5b4ec
Parents: 3d9ff04
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Sun Jan 19 18:58:10 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:04 2014 +0000

----------------------------------------------------------------------
 .../forgeactivity/nf/activity/js/activity.js    | 65 +++++++++++++++++---
 1 file changed, 55 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/23ad4247/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 48b699f..f6807d7 100644
--- a/ForgeActivity/forgeactivity/nf/activity/js/activity.js
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -23,8 +23,8 @@ ASOptions = {
     usePjax: true,
     useHash: true,
     forceAdvancedScroll: false,
-    useShowMore: true,
-    useInfiniteScroll: false
+    useShowMore: false,
+    useInfiniteScroll: true
 }
 
 $(function() {
@@ -111,16 +111,16 @@ $(function() {
         restoreScrollPosition();
     }
 
-    var delayed = null;
+    var scrollHandlerDelayed = null;
     function scrollHandler(event) {
-        clearTimeout(delayed);
+        clearTimeout(scrollHandlerDelayed);
         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);
+        scrollHandlerDelayed = setTimeout(method, delay);
     }
 
     function enableScrollHistory() {
@@ -149,11 +149,20 @@ $(function() {
         $('.no-more.'+(newer ? 'newer' : 'older')).remove();
     }
 
+    var pageInQueue = [];
     function pageIn(newer, url) {
         // Load a single page of either newer or older content from the URL.
         // Then calls pageOut to ensure that not too many are loaded at once,
         // to keep memory usage in check.  Also uses save/restoreScrollPosition
         // to try to keep the same content in view at the same place.
+        if ($('.no-more.'+(newer ? 'newer' : 'older')).length) {
+            return;
+        }
+        pageInQueue.push({newer: newer, url: url});
+        if (pageInQueue.length > 1) {
+            return;
+        }
+        var newerText = newer ? 'newer' : 'older';
         $.get(url, function(html) {
             var $html = $(html);
             var $timeline = $('.timeline');
@@ -173,6 +182,11 @@ $(function() {
                 updateShowMore();
             }
             restoreScrollPosition();
+            pageInQueue.shift();
+            if (pageInQueue.length) {
+                var next = pageInQueue.shift();
+                pageIn(next.newer, next.url);
+            }
         }).fail(function() {
             flash('Error loading activities', 'error');
         });
@@ -185,10 +199,15 @@ $(function() {
         $timeline[method]('<div class="no-more '+cls+'">No more activities</div>');
     }
 
-    function makeShowMoreLink(newer, targetPage, limit) {
+    function makePageUrl(targetPage) {
+        var limit = $('.timeline').data('limit');
+        return 'pjax?page='+targetPage+'&limit='+limit;
+    }
+
+    function makeShowMoreLink(newer, targetPage) {
         var $link = $('<a class="show-more">Show More</a>');
         $link.addClass(newer ? 'newer' : 'older');
-        $link.attr('href', 'pjax?page='+targetPage+'&limit='+limit);
+        $link.attr('href', makePageUrl(targetPage));
         $link.click(function(event) {
             event.preventDefault();
             pageIn(newer, this.href);
@@ -199,17 +218,16 @@ $(function() {
     function updateShowMore() {
         // Update the state of the Show More links when using "Show More"-style
         // advanced paging.
-        var limit = $('.timeline').data('limit');
         var firstPage = $('.timeline li:first').data('page');
         var lastPage = $('.timeline li:last').data('page');
         var noMoreNewer = $('.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) {
-            makeShowMoreLink(true, firstPage-1, limit);
+            makeShowMoreLink(true, firstPage-1);
         }
         if (!noMoreOlder) {
-            makeShowMoreLink(false, lastPage+1, limit);
+            makeShowMoreLink(false, lastPage+1);
         }
     }
 
@@ -221,7 +239,34 @@ $(function() {
         updateShowMore();
     }
 
+    var currentPage = null;
+    function handleInfiniteScroll(event) {
+        var newPage = $('.timeline li:in-viewport:first').data('page');
+        if (newPage == currentPage) {
+            return;
+        }
+        var firstPage = $('.timeline li:first').data('page');
+        var lastPage = $('.timeline li:last').data('page');
+        var noMoreNewer = $('.no-more.newer').length;
+        var noMoreOlder = $('.no-more.older').length;
+        if (newPage < currentPage && !noMoreNewer) {
+            pageIn(true, makePageUrl(firstPage-1));
+        } else if (newPage > currentPage && !noMoreOlder) {
+            pageIn(false, makePageUrl(lastPage+1));
+        }
+        currentPage = newPage;
+    }
+
     function enableInfiniteScroll() {
+        $('.page_list').remove();
+        currentPage = $('.timeline li:first').data('page');
+        if (currentPage == 0) {
+            makeNoMore(true);
+        } else {
+            pageIn(true, makePageUrl(currentPage-1));
+        }
+        pageIn(false, makePageUrl(currentPage+1));
+        $(window).scroll(handleInfiniteScroll);
     }
 
     function enableAdvancedPaging() {


[08/10] git commit: [#4257] More IE hacks to avoid Access Denied

Posted by jo...@apache.org.
[#4257] More IE hacks to avoid Access Denied

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/e276acfa
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/e276acfa
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/e276acfa

Branch: refs/heads/cj/4395
Commit: e276acfa3a48acb28862af6213c8284ba4331d44
Parents: de4f5b7
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Jan 22 21:34:56 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:04 2014 +0000

----------------------------------------------------------------------
 ForgeActivity/forgeactivity/nf/activity/js/activity.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/e276acfa/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 0ed3b0e..ad835d2 100644
--- a/ForgeActivity/forgeactivity/nf/activity/js/activity.js
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -210,14 +210,14 @@ $(function() {
     }
 
     function makeShowMoreLink(newer, targetPage) {
-        var $link = $('<a class="show-more">Show More</a>');
-        $link.addClass(newer ? 'newer' : 'older');
-        $link.attr('href', makePageUrl(targetPage));
-        $link.click(function(event) {
+        var cls = newer ? 'newer' : 'older';
+        var url = makePageUrl(targetPage);
+        var link = '<a class="show-more '+cls+'" href="'+url+'">Show More</a>';
+        $('.timeline')[newer ? 'before' : 'after'](link);
+        $('.show-more.'+cls).click(function(event) {
             event.preventDefault();
             pageIn(newer, this.href);
         });
-        $('.timeline')[newer ? 'before' : 'after']($link);
     }
 
     function updateShowMore() {


[07/10] git commit: [#4257] Fixed page controls not showing on last page of activity stream

Posted by jo...@apache.org.
[#4257] Fixed page controls not showing on last page of activity stream

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/c77b366c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/c77b366c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/c77b366c

Branch: refs/heads/cj/4395
Commit: c77b366cf65c146f7fad3582504a9e5c5575c3bb
Parents: 23ad424
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Tue Jan 21 23:25:57 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:04 2014 +0000

----------------------------------------------------------------------
 ForgeActivity/forgeactivity/main.py              | 14 ++++++++------
 ForgeActivity/forgeactivity/templates/index.html |  4 ++--
 2 files changed, 10 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c77b366c/ForgeActivity/forgeactivity/main.py
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/main.py b/ForgeActivity/forgeactivity/main.py
index 09d0c62..f269336 100644
--- a/ForgeActivity/forgeactivity/main.py
+++ b/ForgeActivity/forgeactivity/main.py
@@ -106,13 +106,15 @@ class ForgeActivityController(BaseController):
                                            limit=kw.get('limit', 100),
                                            actor_only=actor_only,
                                            filter_func=perm_check(c.user))
+        page = asint(kw.get('page', 0))
+        limit = asint(kw.get('limit', 100))
         return dict(
-                followee=followee,
-                following=following,
-                timeline=timeline,
-                page=asint(kw.get('page', 0)),
-                limit=asint(kw.get('limit', 100)),
-            )
+            followee=followee,
+            following=following,
+            timeline=timeline,
+            page=page,
+            limit=limit,
+            has_more=len(timeline) == limit)
 
     @expose('jinja:forgeactivity:templates/index.html')
     @with_trailing_slash

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/c77b366c/ForgeActivity/forgeactivity/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/index.html b/ForgeActivity/forgeactivity/templates/index.html
index 5b222f7..fef165a 100644
--- a/ForgeActivity/forgeactivity/templates/index.html
+++ b/ForgeActivity/forgeactivity/templates/index.html
@@ -43,12 +43,12 @@
 
 <div class="activity">
   {% if not timeline %}
-    No activity to display.
+    No {% if page > 0 %} more {% endif %} activity to display.
   {% else %}
     <ul class="timeline" data-limit="{{limit}}">
         {% include 'forgeactivity:templates/timeline.html' %}
     </ul>
-    {{c.page_list.display(limit=1, page=page, count=page+1, show_label=False, show_if_single_page=True, force_next=True)}}
   {% endif %}
+  {{c.page_list.display(limit=1, page=page, count=page+1, show_label=False, show_if_single_page=True, force_next=has_more)}}
 </div>
 {% endblock %}


[10/10] git commit: [#4395] Add feed action to activity stream page & widget

Posted by jo...@apache.org.
[#4395] Add feed action to activity stream page & widget

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/a0b99127
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/a0b99127
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/a0b99127

Branch: refs/heads/cj/4395
Commit: a0b9912775d6f9760bac7917023d6006f1f1f4f1
Parents: e276acf
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu Jan 23 16:30:15 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:36:17 2014 +0000

----------------------------------------------------------------------
 Allura/allura/ext/user_profile/user_main.py                        | 2 +-
 Allura/allura/nf/allura/css/site_style.css                         | 1 +
 ForgeActivity/forgeactivity/templates/index.html                   | 1 +
 ForgeActivity/forgeactivity/templates/widgets/profile_section.html | 1 +
 4 files changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a0b99127/Allura/allura/ext/user_profile/user_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index a9758e1..52c9985 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -255,5 +255,5 @@ class ProfileSectionBase(object):
         if not self.check_display():
             return ''
         tmpl = g.jinja2_env.get_template(self.template)
-        context = self.prepare_context({'h': h, 'c': c})
+        context = self.prepare_context({'h': h, 'c': c, 'g': g})
         return Markup(tmpl.render(context))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a0b99127/Allura/allura/nf/allura/css/site_style.css
----------------------------------------------------------------------
diff --git a/Allura/allura/nf/allura/css/site_style.css b/Allura/allura/nf/allura/css/site_style.css
index 6c6ff02..94f5d09 100644
--- a/Allura/allura/nf/allura/css/site_style.css
+++ b/Allura/allura/nf/allura/css/site_style.css
@@ -3261,6 +3261,7 @@ ul.dropdown ul li a:hover {
 }
 .user-activity h3 a {
     float: right;
+    margin-left: 8px;
 }
 .user-activity h3 b.ico {
     background-image: url('../images/neo-icon-set-ffffff-256x350.png');

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a0b99127/ForgeActivity/forgeactivity/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/index.html b/ForgeActivity/forgeactivity/templates/index.html
index fef165a..1cadb3f 100644
--- a/ForgeActivity/forgeactivity/templates/index.html
+++ b/ForgeActivity/forgeactivity/templates/index.html
@@ -32,6 +32,7 @@
 {% endblock %}
 
 {% block actions %}
+    <a href="feed.rss" title="RSS"><b data-icon="{{g.icons['feed'].char}}" class="ico {{g.icons['feed'].css}}" title="Feed"></b></a>
     {% if c.user and c.user != c.user.anonymous() and followee != c.user %}
         {{c.follow_toggle.display(following=following)}}
     {% endif %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a0b99127/ForgeActivity/forgeactivity/templates/widgets/profile_section.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/widgets/profile_section.html b/ForgeActivity/forgeactivity/templates/widgets/profile_section.html
index a9e473f..4e1bec2 100644
--- a/ForgeActivity/forgeactivity/templates/widgets/profile_section.html
+++ b/ForgeActivity/forgeactivity/templates/widgets/profile_section.html
@@ -26,6 +26,7 @@
         {% if c.user and not c.user.is_anonymous() and c.user != user %}
             {{follow_toggle.display(following=following, action=activity_app.url+'follow')}}
         {% endif %}
+        <a href="feed.rss" title="RSS"><b data-icon="{{g.icons['feed'].char}}" class="ico {{g.icons['feed'].css}}" title="Feed"></b></a>
     </h3>
     {% if not timeline %}
         <p class="empty">No activity to display.</p>


[03/10] git commit: [#4257] Added PJAX Show More paging with scroll state saving

Posted by jo...@apache.org.
[#4257] Added PJAX Show More paging with scroll state saving

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/df82f288
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/df82f288
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/df82f288

Branch: refs/heads/cj/4395
Commit: df82f2887de3791b8070b12402791a98da454d0c
Parents: 28f74b1
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Sat Jan 18 00:50:38 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:03 2014 +0000

----------------------------------------------------------------------
 Allura/LICENSE                                  |   2 +
 Allura/allura/public/nf/js/jquery.viewport.js   |  58 +++++
 ForgeActivity/forgeactivity/main.py             |   4 +
 .../forgeactivity/nf/activity/css/activity.css  |  10 +
 .../forgeactivity/nf/activity/js/activity.js    | 209 +++++++++++++++++++
 .../forgeactivity/templates/index.html          |  21 +-
 .../forgeactivity/templates/timeline.html       |  35 ++++
 7 files changed, 324 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/Allura/LICENSE
----------------------------------------------------------------------
diff --git a/Allura/LICENSE b/Allura/LICENSE
index 7e0be3d..36c9038 100644
--- a/Allura/LICENSE
+++ b/Allura/LICENSE
@@ -232,6 +232,8 @@ under the MIT license.  For details, see the individual files:
     allura/lib/widgets/resources/js/jquery.tools.min.js
     allura/public/nf/js/jquery.flot.js
     allura/public/nf/js/jquery.maxlength.min.js
+    allura/public/nf/js/jquery.viewport.js
+    allura/public/nf/js/jquery.pjax.js
 
 Blueprint, which is available under the MIT license.
 For details, see allura/public/nf/css/blueprint/

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/Allura/allura/public/nf/js/jquery.viewport.js
----------------------------------------------------------------------
diff --git a/Allura/allura/public/nf/js/jquery.viewport.js b/Allura/allura/public/nf/js/jquery.viewport.js
new file mode 100644
index 0000000..7826000
--- /dev/null
+++ b/Allura/allura/public/nf/js/jquery.viewport.js
@@ -0,0 +1,58 @@
+/*
+ * Viewport - jQuery selectors for finding elements in viewport
+ *
+ * Copyright (c) 2008-2009 Mika Tuupola
+ *
+ * Licensed under the MIT license:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *
+ * Project home:
+ *  http://www.appelsiini.net/projects/viewport
+ *
+ */
+(function($) {
+    
+    $.belowthefold = function(element, settings) {
+        var fold = $(window).height() + $(window).scrollTop();
+        return fold <= $(element).offset().top - settings.threshold;
+    };
+
+    $.abovethetop = function(element, settings) {
+        var top = $(window).scrollTop();
+        return top >= $(element).offset().top + $(element).height() - settings.threshold;
+    };
+    
+    $.rightofscreen = function(element, settings) {
+        var fold = $(window).width() + $(window).scrollLeft();
+        return fold <= $(element).offset().left - settings.threshold;
+    };
+    
+    $.leftofscreen = function(element, settings) {
+        var left = $(window).scrollLeft();
+        return left >= $(element).offset().left + $(element).width() - settings.threshold;
+    };
+    
+    $.inviewport = function(element, settings) {
+        return !$.rightofscreen(element, settings) && !$.leftofscreen(element, settings) && !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
+    };
+    
+    $.extend($.expr[':'], {
+        "below-the-fold": function(a, i, m) {
+            return $.belowthefold(a, {threshold : 0});
+        },
+        "above-the-top": function(a, i, m) {
+            return $.abovethetop(a, {threshold : 0});
+        },
+        "left-of-screen": function(a, i, m) {
+            return $.leftofscreen(a, {threshold : 0});
+        },
+        "right-of-screen": function(a, i, m) {
+            return $.rightofscreen(a, {threshold : 0});
+        },
+        "in-viewport": function(a, i, m) {
+            return $.inviewport(a, {threshold : 0});
+        }
+    });
+
+    
+})(jQuery);

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/ForgeActivity/forgeactivity/main.py
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/main.py b/ForgeActivity/forgeactivity/main.py
index 991bb61..09d0c62 100644
--- a/ForgeActivity/forgeactivity/main.py
+++ b/ForgeActivity/forgeactivity/main.py
@@ -119,6 +119,10 @@ class ForgeActivityController(BaseController):
     def index(self, **kw):
         return self._get_activities_data(**kw)
 
+    @expose('jinja:forgeactivity:templates/timeline.html')
+    def pjax(self, **kw):
+        return self._get_activities_data(**kw)
+
     @without_trailing_slash
     @expose()
     def feed(self, **kw):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/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 dc71608..66395ff 100644
--- a/ForgeActivity/forgeactivity/nf/activity/css/activity.css
+++ b/ForgeActivity/forgeactivity/nf/activity/css/activity.css
@@ -46,3 +46,13 @@
   float: left;
   margin: 10px 10px 0 0;
 }
+.activity .page_list {
+    margin-top: 5px;
+}
+.activity .show-more {
+    display: block;
+    text-align: center;
+}
+.activity .show-more.older {
+    margin-top: 10px;
+}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/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
new file mode 100644
index 0000000..e8c0346
--- /dev/null
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -0,0 +1,209 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+ActivityBrowseOptions = {
+    maintainScrollState: true,
+    usePjax: true,
+    useHash: true,
+    forceAdvancedScroll: false,
+    useShowMore: true,
+    useInfiniteScroll: false
+}
+
+$(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;
+        }
+        if (!ActivityBrowseOptions.forceAdvancedScroll) {
+            ActivityBrowseOptions.useShowMore = false;
+            ActivityBrowseOptions.useInfiniteScroll = false;
+        }
+    }
+
+    var firstVisibleId = null;
+    var oldScrollTop = null;
+    var oldTop = null;
+    function saveScrollPosition() {
+        var $firstVisible = $('.timeline li:in-viewport:first');
+        firstVisibleId = $firstVisible.attr('id');
+        oldScrollTop = $(window).scrollTop();
+        oldTop = $firstVisible.offset().top;
+    }
+    function restoreScrollPosition() {
+        var $window = $(window);
+        var $firstVisible = $('#'+firstVisibleId);
+        if (!$firstVisible.length) {
+            return;
+        }
+        var newTop = $firstVisible.offset().top;
+        var scrollTop = $window.scrollTop();
+        var elemAdjustment = newTop - oldTop;
+        var viewportAdjustment = scrollTop - oldScrollTop;
+        $window.scrollTop(scrollTop + elemAdjustment - viewportAdjustment);
+        //console.log('restoreSP', oldTop, newTop, elemAdjustment, viewportAdjustment, scrollTop, $window.scrollTop());
+        $(window).trigger('scroll');
+    }
+
+    function maintainScrollState_pjax() {
+        var $firstVisibleActivity = $('.timeline li:in-viewport:first');
+        var page = $firstVisibleActivity.data('page');
+        var limit = $('.timeline').data('limit');
+        var hash = $firstVisibleActivity.attr('id');
+        if (page != null && limit != null && hash != null) {
+            history.replaceState(null, null, '?page='+page+'&limit='+limit+'#'+hash);
+        }
+    }
+
+    function maintainScrollState_hash() {
+        var $firstVisibleActivity = $('.timeline li:in-viewport:first');
+        saveScrollPosition();
+        window.location.hash = $firstVisibleActivity.attr('id');  // causes jump...
+        restoreScrollPosition();
+    }
+
+    var delayed = null;
+    function scrollHandler(event) {
+        clearTimeout(delayed);
+        delayed = setTimeout(ActivityBrowseOptions.usePjax
+            ? maintainScrollState_pjax
+            : maintainScrollState_hash, 100);
+    }
+
+    function maintainScrollState() {
+        if (!ActivityBrowseOptions.maintainScrollState) {
+            return;
+        }
+        $(window).scroll(scrollHandler);
+    }
+
+    function pageOut(newer) {
+        var $timeline = $('.timeline li');
+        var limit = $('.timeline').data('limit') || 100;
+        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();
+        }
+    }
+    window.pageOut = pageOut;
+
+    function pageIn(newer, url) {
+        $.get(url, function(html) {
+            saveScrollPosition();
+            if (newer) {
+                $('.timeline').prepend(html);
+            } else {
+                if (html.match(/^\s*$/)) {
+                    $('.show-more.older').addClass('no-more');
+                } else {
+                    $('.timeline').append(html);
+                }
+            }
+            var firstPage = $('.timeline li:first').data('page');
+            var lastPage = $('.timeline li:last').data('page');
+            if (lastPage - firstPage >= 3) {
+                pageOut(!newer);
+            }
+            if (ActivityBrowseOptions.useShowMore) {
+                updateShowMore();
+            }
+            restoreScrollPosition();
+        }).fail(function() {
+            flash('Error loading activities', 'error');
+        });
+    }
+
+    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>');
+        $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
+        return $link;
+    }
+
+    function updateShowMore() {
+        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) {
+            $timeline.before(makeShowMoreLink(true, firstPage-1, limit));
+        }
+        if (noMoreActivities) {
+            $timeline.after('<div class="show-more older no-more">No more activities</div>');
+        } else {
+            $timeline.after(makeShowMoreLink(false, lastPage+1, limit));
+        }
+    }
+    window.updateShowMore = updateShowMore;
+
+    function enableInfiniteScroll() {
+    }
+
+    function enableAdvancedPaging() {
+        if (ActivityBrowseOptions.useInfiniteScroll) {
+            enableInfiniteScroll();
+        } else if (ActivityBrowseOptions.useShowMore) {
+            updateShowMore();
+        }
+    }
+
+    maintainScrollState();  // http://xkcd.com/1309/
+    enableAdvancedPaging();
+});
+
+function markTop() {
+    var $marker = $('#offset-marker');
+    if (!$marker.length) {
+        $marker = $('<div id="offset-marker">&nbsp;</div>');
+        $marker.css({
+            'position': 'absolute',
+            'top': 0,
+            'width': '100%',
+            'border-top': '1px solid green'
+        });
+        $marker.appendTo($('body'));
+    }
+    $marker.css({'top': $(window).scrollTop()});
+}
+
+function markFirst() {
+    $('.timeline li:in-viewport:first').css({'background-color': '#f0fff0'});
+}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/ForgeActivity/forgeactivity/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/index.html b/ForgeActivity/forgeactivity/templates/index.html
index e63c904..4b8c162 100644
--- a/ForgeActivity/forgeactivity/templates/index.html
+++ b/ForgeActivity/forgeactivity/templates/index.html
@@ -38,27 +38,18 @@
 {% endblock %}
 
 {% block content %}
+{% do g.register_forge_js('js/jquery.viewport.js') %}
+{% do g.register_app_js('js/activity.js') %}
+
 <div class="activity">
   {% if not timeline %}
     No activity to display.
   {% else %}
-    <ul class="timeline">
-        {% for a in timeline %}
-        <li>
-          <time datetime="{{a.published|datetimeformat}}" title="{{a.published|datetimeformat}}">{{h.ago(a.published, show_date_after=None)}}</time>
-          <h1>
-              {{ am.icon(a.actor, 32, 'avatar') }}
-              {{am.activity_obj(a.actor)}} {{a.verb}} {{am.activity_obj(a.obj)}} {% if a.target.activity_name %}on {{am.activity_obj(a.target)}}{% endif %}
-          </h1>
-          {% if a.obj.activity_extras.get('summary') %}
-          <p>
-            {{ a.obj.activity_extras.get('summary') }}
-          </p>
-          {% endif %}
-        </li>
-        {% endfor %}
+    <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 %}
 </div>
 {% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/df82f288/ForgeActivity/forgeactivity/templates/timeline.html
----------------------------------------------------------------------
diff --git a/ForgeActivity/forgeactivity/templates/timeline.html b/ForgeActivity/forgeactivity/templates/timeline.html
new file mode 100644
index 0000000..499fe03
--- /dev/null
+++ b/ForgeActivity/forgeactivity/templates/timeline.html
@@ -0,0 +1,35 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+
+{% import 'forgeactivity:templates/macros.html' as am with context %}
+
+{% for a in timeline %}
+<li id="{{a._id}}" data-page="{{page}}">
+  <time datetime="{{a.published|datetimeformat}}" title="{{a.published|datetimeformat}}">{{h.ago(a.published, show_date_after=None)}}</time>
+  <h1>
+      {{ am.icon(a.actor, 32, 'avatar') }}
+      {{am.activity_obj(a.actor)}} {{a.verb}} {{am.activity_obj(a.obj)}} {% if a.target.activity_name %}on {{am.activity_obj(a.target)}}{% endif %}
+  </h1>
+  {% if a.obj.activity_extras.get('summary') %}
+  <p>
+    {{ a.obj.activity_extras.get('summary') }}
+  </p>
+  {% endif %}
+</li>
+{% endfor %}


[09/10] git commit: [#4257] Ugly hack to fix Access Denied error in IE

Posted by jo...@apache.org.
[#4257] Ugly hack to fix Access Denied error in IE

It seems that some combination of IE11, jQuery 1.8.0, and possibly
something else on our page, doing $('<li>elem</li>') causes IE to raise
an "Access denied" error claiming that we're attempting cross-site
javascript iframe access.  However, doing $('#elem').append('<li>elem</li>')
works fine.  I'd prefer to upgrade jQuery but this is a quicker work-around.

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/a3c5bf7f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/a3c5bf7f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/a3c5bf7f

Branch: refs/heads/cj/4395
Commit: a3c5bf7f2328c21303f17a6a1f1aeffb7fab02d2
Parents: c77b366
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Jan 22 17:05:58 2014 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Thu Jan 23 17:28:04 2014 +0000

----------------------------------------------------------------------
 .../forgeactivity/nf/activity/js/activity.js         | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a3c5bf7f/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 f6807d7..80b79d8 100644
--- a/ForgeActivity/forgeactivity/nf/activity/js/activity.js
+++ b/ForgeActivity/forgeactivity/nf/activity/js/activity.js
@@ -164,16 +164,21 @@ $(function() {
         }
         var newerText = newer ? 'newer' : 'older';
         $.get(url, function(html) {
-            var $html = $(html);
             var $timeline = $('.timeline');
-            var newPage = $html.data('page');
+            var empty = html.match(/^\s*$/);
+            var newestPage = newer && $('.timeline li:first').data('page') <= 1;
             var limit = $('.timeline').data('limit');
+            var fullPage = true;
             saveScrollPosition();
-            if ($html.length < limit || newPage == 0) {
+            if (!empty) {
+                $timeline[newer ? 'prepend' : 'append'](html);
+                var newPage = $timeline.find('li:' + (newer ? 'first' : 'last')).data('page');
+                fullPage = $timeline.find('li:timeline-page('+newPage+')').length == limit;
+                pageOut(!newer);
+            }
+            if (empty || !fullPage || newestPage) {
                 makeNoMore(newer);
             }
-            $timeline[newer ? 'prepend' : 'append']($html);
-            pageOut(!newer);
             if (ASOptions.useShowMore) {
                 // this has to be here instead of showMoreLink handler to
                 // ensure that scroll changes between added / removed content