changeset 126:9079fb01abb8

Improved wiki history page: - Collapsable list of pages when there's more than one. - Added a `limit` parameter to the API. - Better code for special pages' views and models.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 24 Nov 2013 14:14:32 -0800
parents 886f36b05e5f
children 6d5c339af405
files static/js/wikked/app.js static/js/wikked/models.js static/js/wikked/views.js static/tpl/special-changes.html wikked/scm.py wikked/views.py wikked/wiki.py
diffstat 7 files changed, 76 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/static/js/wikked/app.js	Sun Nov 24 14:04:05 2013 -0800
+++ b/static/js/wikked/app.js	Sun Nov 24 14:14:32 2013 -0800
@@ -75,7 +75,8 @@
             'login':                 "showLogin",
             'logout':                "doLogout",
             'special':               "showSpecialPages",
-            'special/:page':         "showSpecialPage"
+            'special/changes':       "showSiteChanges",
+            'special/orphans':       "showOrphans"
         },
         readPage: function(path) {
             path_clean = this.stripQuery(path);
@@ -179,25 +180,19 @@
             this.viewManager.switchView(view, false);
             this.navigate('/special');
         },
-        showSpecialPage: function(page) {
-            var viewType = false;
-            switch (page) {
-                case "changes":
-                    viewType = Views.SpecialChangesView;
-                    break;
-                case "orphans":
-                    viewType = Views.SpecialOrphansView;
-                    break;
-            }
-            if (viewType === false) {
-                console.error("Unsupported special page: ", page);
-                return;
-            }
-            var view = new viewType({
-                model: new Models.GenericSpecialPageModel({ page: page })
+        showSiteChanges: function() {
+            var view = new Views.SpecialChangesView({
+                model: new Models.SpecialChangesModel()
             });
             this.viewManager.switchView(view);
-            this.navigate('/special/' + page);
+            this.navigate('/special/changes');
+        },
+        showOrphans: function() {
+            var view = new Views.SpecialOrphansView({
+                model: new Models.SpecialOrphansModel()
+            });
+            this.viewManager.switchView(view);
+            this.navigate('/special/orphans');
         },
         stripQuery: function(url) {
             q = url.indexOf("?");
--- a/static/js/wikked/models.js	Sun Nov 24 14:04:05 2013 -0800
+++ b/static/js/wikked/models.js	Sun Nov 24 14:14:32 2013 -0800
@@ -425,42 +425,24 @@
         }
     });
 
-    var GenericSpecialPageModel = exports.GenericSpecialPageModel = MasterPageModel.extend({
+    var SpecialPageModel = exports.SpecialPageModel = MasterPageModel.extend({
         action: 'special',
         initialize: function() {
-            GenericSpecialPageModel.__super__.initialize.apply(this, arguments);
+            SpecialPageModel.__super__.initialize.apply(this, arguments);
             this.footer.clearExtraUrls();
-            var key = this.get('page');
-            if (key in this.assignMap) {
-                this.assignMap[key].apply(this);
-            }
-        },
-        assignMap: {
-        },
-        titleMap: {
-            orphans: 'Orphaned Pages',
-            changes: 'Wiki History'
-        },
-        title: function() {
-            var key = this.get('page');
-            if (key in this.titleMap) {
-                return this.titleMap[key];
-            }
-            return 'Unknown';
-        },
-        urlMap: {
-            orphans: '/api/orphans',
-            changes: '/api/history'
-        },
-        url: function() {
-            var key = this.get('page');
-            if (key in this.urlMap) {
-                return this.urlMap[key];
-            }
-            return false;
         }
     });
 
+    var SpecialChangesModel = exports.SpecialChangesModel = SpecialPageModel.extend({
+        title: "Wiki History",
+        url: '/api/history'
+    });
+
+    var SpecialOrphansModel = exports.SpecialOrphansModel = SpecialPageModel.extend({
+        title: "Orphaned Pages",
+        url: '/api/orphans'
+    });
+
     return exports;
 });
 
--- a/static/js/wikked/views.js	Sun Nov 24 14:04:05 2013 -0800
+++ b/static/js/wikked/views.js	Sun Nov 24 14:14:32 2013 -0800
@@ -104,7 +104,7 @@
             this.$el.html(tpl(this.model.toJSON()));
         },
         renderTitle: function(formatter) {
-            var title = this.model.title();
+            var title = _.result(this, 'title');
             if (formatter !== undefined) {
                 title = formatter.call(this, title);
             }
@@ -506,6 +506,19 @@
 
     var SpecialChangesView = exports.SpecialChangesView = SpecialMasterPageView.extend({
         defaultTemplateSource: tplSpecialChanges,
+        renderCallback: function() {
+            SpecialChangesView.__super__.renderCallback.apply(this, arguments);
+            if (this.isError) {
+                return;
+            }
+
+            this.$('.history-list .page-details').hide();
+            this.$('.history-list .page-details-toggler').click(function (e) {
+                index = $(this).attr('data-index');
+                $('.history-list .page-details-' + index).toggle();
+                e.preventDefault();
+            });
+        },
         _onModelChange: function() {
             var history = this.model.get('history');
             if (history) {
--- a/static/tpl/special-changes.html	Sun Nov 24 14:04:05 2013 -0800
+++ b/static/tpl/special-changes.html	Sun Nov 24 14:14:32 2013 -0800
@@ -5,7 +5,7 @@
     <section>
         <p>Here are the recent changes on this wiki.</p>
         <form>
-            <table class="table table-hover">
+            <table class="table table-hover history-list">
                 <thead>
                     <tr>
                         <th>Revision</th>
@@ -14,7 +14,7 @@
                 </thead>
                 <tbody>
                     {{#eachr history}}
-                    <tr>
+                    <tr class='history-entry'>
                         <td>{{rev_name}}</td>
                         <td>
                             <dl class="dl-horizontal">
@@ -22,22 +22,25 @@
                                 <dd>{{date_from_now timestamp}}</dd>
                                 <dt>Author</dt>
                                 <dd>{{author}}</dd>
-                                <dt>Pages</dt>
+                                <dt>Pages ({{num_pages}})</dt>
                                 <dd>
+                                {{#if make_collapsable}}
+                                    <button class="btn page-details-toggler" data-index="{{index}}">Show/Hide</button>
+                                    <div class="page-details page-details-{{index}}">
+                                {{/if}}
                                     <ul class="unstyled">
                                         {{#each changes}}
                                         <li>
-                                            {{#if valid_url}}
-                                            <a href="{{get_read_url url}}">{{url}}</a>
-                                            {{else}}
-                                            <code>{{url}}</code>
-                                            {{/if}}
+                                            <a href="#/revision{{url}}/{{../rev_id}}">{{url}}</a>
                                             {{#if is_edit}}(edit) {{/if}}
                                             {{#if is_add}}(added) {{/if}}
                                             {{#if is_delete}}(deleted) {{/if}}
                                         </li>
                                         {{/each}}
                                     </ul>
+                                {{#if make_collapsable}}
+                                    </div>
+                                {{/if}}
                                 </dd>
                                 <dt>Comment</dt>
                                 <dd>{{description}}</dd>
--- a/wikked/scm.py	Sun Nov 24 14:04:05 2013 -0800
+++ b/wikked/scm.py	Sun Nov 24 14:14:32 2013 -0800
@@ -36,7 +36,7 @@
     def getSpecialFilenames(self):
         raise NotImplementedError()
 
-    def getHistory(self, path=None):
+    def getHistory(self, path=None, limit=10):
         raise NotImplementedError()
 
     def getState(self, path):
@@ -119,7 +119,7 @@
         self.hg = 'hg'
         self.log_style = os.path.join(os.path.dirname(__file__), 'resources', 'hg_log.style')
 
-    def getHistory(self, path=None):
+    def getHistory(self, path=None, limit=10):
         if path is not None:
             st_out = self._run('status', path)
             if len(st_out) > 0 and st_out[0] == '?':
@@ -129,6 +129,7 @@
         if path is not None:
             log_args.append(path)
         log_args += ['--style', self.log_style]
+        log_args += ['-l', limit]
         log_out = self._run('log', *log_args)
 
         revisions = []
@@ -232,7 +233,7 @@
         import hglib
         self.client = hglib.open(self.root)
 
-    def getHistory(self, path=None):
+    def getHistory(self, path=None, limit=10):
         if path is not None:
             rel_path = os.path.relpath(path, self.root)
             status = self.client.status(include=[rel_path])
@@ -241,10 +242,10 @@
 
         needs_files = False
         if path is not None:
-            repo_revs = self.client.log(files=[path], follow=True)
+            repo_revs = self.client.log(files=[path], follow=True, limit=limit)
         else:
             needs_files = True
-            repo_revs = self.client.log(follow=True)
+            repo_revs = self.client.log(follow=True, limit=limit)
         revisions = []
         for rev in repo_revs:
             r = Revision(rev.node)
--- a/wikked/views.py	Sun Nov 24 14:04:05 2013 -0800
+++ b/wikked/views.py	Sun Nov 24 14:14:32 2013 -0800
@@ -8,7 +8,7 @@
 from pygments.lexers import get_lexer_by_name
 from pygments.formatters import get_formatter_by_name
 from web import app, login_manager
-from page import Page, PageData, PageLoadingError
+from page import Page, DatabasePage, PageData, PageLoadingError
 from fs import PageNotFoundError
 from formatter import PageFormatter, FormattingContext
 from utils import title_to_url, path_to_url
@@ -121,11 +121,12 @@
             rev_data['pages'] = []
             for f in rev.files:
                 url = None
-                is_url_valid = True
-                page = g.wiki.db.getPage(path=f['path'])
-                if page is not None:
+                path = os.path.join(g.wiki.root, f['path'])
+                db_obj = g.wiki.db.getPage(path=path)
+                if db_obj is not None:
                     try:
                         # Hide pages that the user can't see.
+                        page = DatabasePage(g.wiki, db_obj=db_obj)
                         if not is_page_readable(page):
                             continue
                         url = page.url
@@ -135,12 +136,12 @@
                         pass
                 if not url:
                     url = path_to_url(f['path'])
-                    is_url_valid = False
                 rev_data['pages'].append({
                     'url': url,
-                    'valid_url': is_url_valid,
                     'action': scm.ACTION_NAMES[f['action']]
                     })
+            rev_data['num_pages'] = len(rev_data['pages'])
+            rev_data['make_collapsable'] = len(rev_data['pages']) > 1
             if len(rev_data['pages']) > 0:
                 hist_data.append(rev_data)
         else:
@@ -418,7 +419,13 @@
 
 @app.route('/api/history')
 def api_site_history():
-    history = g.wiki.getHistory()
+    limit = request.args.get('l')
+    if not limit:
+        limit = 10
+    else:
+        limit = int(limit)
+
+    history = g.wiki.getHistory(limit=limit)
     hist_data = get_history_data(history, needs_files=True)
     result = {'history': hist_data}
     return make_auth_response(result)
--- a/wikked/wiki.py	Sun Nov 24 14:04:05 2013 -0800
+++ b/wikked/wiki.py	Sun Nov 24 14:14:32 2013 -0800
@@ -124,6 +124,10 @@
         self.fs.excluded += parameters.getSpecialFilenames()
         self.fs.excluded += self.scm.getSpecialFilenames()
 
+    @property
+    def root(self):
+        return self.fs.root
+
     def start(self, update=True):
         """ Properly initializes the wiki and all its sub-systems.
         """
@@ -247,10 +251,10 @@
         """
         return self.db.pageExists(url)
 
-    def getHistory(self):
+    def getHistory(self, limit=10):
         """ Shorthand method to get the history from the source-control.
         """
-        return self.scm.getHistory()
+        return self.scm.getHistory(limit=limit)
 
     def _cachePages(self, only_urls=None):
         self.logger.debug("Caching extended page data...")