# HG changeset patch # User Ludovic Chabant # Date 1357030194 28800 # Node ID 8a4e0fe2c68958e09b6e0f4955f3f79e7a1faa5c # Parent 8d6c2a5ed08d554939cc6fdf21cb85c02e166233 Added "Special Pages" section: - Only "orphaned" pages for now. - Made base view/model classes more extensible. Better way to export views and models from their module. diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/css/wikked.less --- a/wikked/static/css/wikked.less Mon Dec 31 22:02:39 2012 -0800 +++ b/wikked/static/css/wikked.less Tue Jan 01 00:49:54 2013 -0800 @@ -13,16 +13,21 @@ @colorNavLinkHover: rgb(96, 96, 96); @colorBlueDark: #48577D; -@colorBlueLight: #7690CF; +@colorBlueMedium: #7690CF; +@colorBlueLight: #D9E3FF; + @colorGrayBlueLight: #D3DCF2; @colorGrayBlueMedium: #9197A6; @colorGrayBlueDark: #43464C; + @colorGrayLight: #EEE; @colorGrayMedium: #AAA; @colorGrayDark: #666; + @colorCode: #523C37; @backgroundPage: white; +@backgroundPageSpecial: #E5D19E; // Macros .box-shadow(@style, @c) { @@ -136,6 +141,9 @@ padding: @baseLineHeight; background: @backgroundPage; } + .page.special { + background: @backgroundPageSpecial; + } .page>pre { margin-top: @baseLineHeight; @@ -192,7 +200,7 @@ } .preview-wiki-meta { .meta-name { - background: @colorBlueLight; + background: @colorBlueMedium; color: #fff; padding: 0.2em 0.4em 0.2em 0.6em; border-radius: 0.5em 0 0 0.5em; diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/js/wikked/app.js --- a/wikked/static/js/wikked/app.js Mon Dec 31 22:02:39 2012 -0800 +++ b/wikked/static/js/wikked/app.js Tue Jan 01 00:49:54 2013 -0800 @@ -25,7 +25,9 @@ 'diff/r/*path/:rev1/:rev2':"showDiff", 'search/:query': "showSearchResults", 'login': "showLogin", - 'logout': "doLogout" + 'logout': "doLogout", + 'special': "showSpecialPages", + 'special/:page': "showSpecialPage" }, readPage: function(path) { var view = new Views.PageReadView({ @@ -127,6 +129,23 @@ alert("Error logging out!"); }); }, + showSpecialPages: function() { + var view = new Views.SpecialPagesView({ + el: $('#app'), + model: new Models.SpecialPagesModel() + }); + view.model.setApp(this); + this.navigate('/special'); + }, + showSpecialPage: function(page) { + var view = new Views.GenericSpecialPageView({ + el: $('#app'), + model: new Models.GenericSpecialPageModel({ page: page }) + }); + view.model.setApp(this); + view.model.fetch(); + this.navigate('/special/' + page); + }, getQueryVariable: function(variable) { var query = window.location.search.substring(1); var vars = query.split("&"); diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/js/wikked/models.js --- a/wikked/static/js/wikked/models.js Mon Dec 31 22:02:39 2012 -0800 +++ b/wikked/static/js/wikked/models.js Tue Jan 01 00:49:54 2013 -0800 @@ -10,7 +10,9 @@ ], function(require, $, _, Backbone, Handlebars) { - var NavigationModel = Backbone.Model.extend({ + var exports = {}; + + var NavigationModel = exports.NavigationModel = Backbone.Model.extend({ idAttribute: 'path', defaults: function() { return { @@ -69,12 +71,18 @@ } }); - var FooterModel = Backbone.Model.extend({ + var FooterModel = exports.FooterModel = Backbone.Model.extend({ defaults: function() { return { - url_extras: [ { name: 'Home', url: '/' } ] + url_extras: [ + { name: 'Home', url: '/' }, + { name: 'Special Pages', url: '/#/special' } + ] }; }, + clearExtraUrls: function() { + this.get('url_extras').length = 0; + }, addExtraUrl: function(name, url, index) { if (index === undefined) { this.get('url_extras').push({ name: name, url: url }); @@ -84,7 +92,7 @@ } }); - var LoginModel = Backbone.Model.extend({ + var LoginModel = exports.LoginModel = Backbone.Model.extend({ setApp: function(app) { this.app = app; }, @@ -100,7 +108,7 @@ } }); - var PageModel = Backbone.Model.extend({ + var PageModel = exports.PageModel = Backbone.Model.extend({ idAttribute: 'path', defaults: function() { return { @@ -146,11 +154,11 @@ } }); - var PageStateModel = PageModel.extend({ + var PageStateModel = exports.PageStateModel = PageModel.extend({ urlRoot: '/api/state/' }); - var MasterPageModel = PageModel.extend({ + var MasterPageModel = exports.MasterPageModel = PageModel.extend({ initialize: function() { this.nav = new NavigationModel({ id: this.id }); this.footer = new FooterModel(); @@ -177,7 +185,7 @@ } }); - var PageReadModel = MasterPageModel.extend({ + var PageReadModel = exports.PageReadModel = MasterPageModel.extend({ urlRoot: '/api/read/', action: 'read', _onChangePath: function(path) { @@ -187,12 +195,12 @@ } }); - var PageSourceModel = MasterPageModel.extend({ + var PageSourceModel = exports.PageSourceModel = MasterPageModel.extend({ urlRoot: '/api/raw/', action: 'source' }); - var PageEditModel = MasterPageModel.extend({ + var PageEditModel = exports.PageEditModel = MasterPageModel.extend({ urlRoot: '/api/edit/', action: 'edit', doEdit: function(form) { @@ -208,7 +216,7 @@ } }); - var PageHistoryModel = MasterPageModel.extend({ + var PageHistoryModel = exports.PageHistoryModel = MasterPageModel.extend({ urlRoot: '/api/history/', action: 'history', doDiff: function(form) { @@ -224,7 +232,7 @@ } }); - var PageRevisionModel = MasterPageModel.extend({ + var PageRevisionModel = exports.PageRevisionModel = MasterPageModel.extend({ urlRoot: '/api/revision/', idAttribute: 'path_and_rev', action: 'revision', @@ -254,7 +262,7 @@ } }); - var PageDiffModel = MasterPageModel.extend({ + var PageDiffModel = exports.PageDiffModel = MasterPageModel.extend({ urlRoot: '/api/diff/', idAttribute: 'path_and_revs', action: 'diff', @@ -295,12 +303,12 @@ } }); - var IncomingLinksModel = MasterPageModel.extend({ + var IncomingLinksModel = exports.IncomingLinksModel = MasterPageModel.extend({ urlRoot: '/api/inlinks/', action: 'inlinks' }); - var WikiSearchModel = MasterPageModel.extend({ + var WikiSearchModel = exports.WikiSearchModel = MasterPageModel.extend({ urlRoot: '/api/search/', action: 'search', title: function() { @@ -318,18 +326,27 @@ } }); - return { - NavigationModel: NavigationModel, - FooterModel: FooterModel, - PageReadModel: PageReadModel, - PageEditModel: PageEditModel, - PageHistoryModel: PageHistoryModel, - IncomingLinksModel: IncomingLinksModel, - PageRevisionModel: PageRevisionModel, - PageDiffModel: PageDiffModel, - WikiSearchModel: WikiSearchModel, - LoginModel: LoginModel, - PageStateModel: PageStateModel - }; + var SpecialPagesModel = exports.SpecialPagesModel = MasterPageModel.extend({ + action: 'special', + title: function() { + return 'Special Pages'; + }, + initialize: function() { + SpecialPagesModel.__super__.initialize.apply(this, arguments); + this.footer.clearExtraUrls(); + } + }); + + var GenericSpecialPageModel = exports.GenericSpecialPageModel = MasterPageModel.extend({ + action: 'special', + urlRoot: '/api/special', + idAttribute: 'page', + initialize: function() { + GenericSpecialPageModel.__super__.initialize.apply(this, arguments); + this.footer.clearExtraUrls(); + } + }); + + return exports; }); diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/js/wikked/views.js --- a/wikked/static/js/wikked/views.js Mon Dec 31 22:02:39 2012 -0800 +++ b/wikked/static/js/wikked/views.js Tue Jan 01 00:49:54 2013 -0800 @@ -11,18 +11,22 @@ ], function($, _, Backbone, Handlebars, Models, Util) { - var PageView = Backbone.View.extend({ + var exports = {}; + + var PageView = exports.PageView = Backbone.View.extend({ tagName: 'div', className: 'wrapper', initialize: function() { PageView.__super__.initialize.apply(this, arguments); - var $view = this; - this.model.on("change", function() { $view.render(); }); + if (this.model !== undefined) { + var $view = this; + this.model.on("change", function() { $view.render(); }); + } return this; }, render: function(view) { if (this.templateName !== undefined) { - this.renderTemplate(this.templateName, this.renderCallback); + this.renderTemplate(_.result(this, 'templateName'), this.renderCallback); } this.renderTitle(this.titleFormat); return this; @@ -47,7 +51,7 @@ }); _.extend(PageView, Backbone.Events); - var NavigationView = PageView.extend({ + var NavigationView = exports.NavigationView = PageView.extend({ templateName: 'nav', initialize: function() { NavigationView.__super__.initialize.apply(this, arguments); @@ -55,7 +59,7 @@ return this; }, render: function() { - this.renderTemplate('nav'); + this.renderTemplate(this.templateName); }, postRender: function() { var model = this.model; @@ -106,7 +110,7 @@ } }); - var FooterView = PageView.extend({ + var FooterView = exports.FooterView = PageView.extend({ templateName: 'footer', initialize: function() { FooterView.__super__.initialize.apply(this, arguments); @@ -120,7 +124,7 @@ } }); - var LoginView = PageView.extend({ + var LoginView = exports.LoginView = PageView.extend({ templateName: 'login', initialize: function() { LoginView.__super__.initialize.apply(this, arguments); @@ -139,11 +143,11 @@ } }); - var MasterPageView = PageView.extend({ + var MasterPageView = exports.MasterPageView = PageView.extend({ initialize: function() { MasterPageView.__super__.initialize.apply(this, arguments); - this.nav = new NavigationView({ model: this.model.nav }); - this.footer = new FooterView({ model: this.model.footer }); + this.nav = this._createNavigation(this.model.nav); + this.footer = this._createFooter(this.model.footer); this.render(); return this; }, @@ -152,10 +156,16 @@ this.nav.postRender(); this.footer.$el.appendTo(this.$el); this.footer.postRender(); + }, + _createNavigation: function(model) { + return new NavigationView({ model: model }); + }, + _createFooter: function(model) { + return new FooterView({ model: model }); } }); - var PageReadView = MasterPageView.extend({ + var PageReadView = exports.PageReadView = MasterPageView.extend({ templateName: 'read-page', initialize: function() { PageReadView.__super__.initialize.apply(this, arguments); @@ -195,7 +205,7 @@ } }); - var PageEditView = MasterPageView.extend({ + var PageEditView = exports.PageEditView = MasterPageView.extend({ templateName: 'edit-page', renderCallback: function(view, model) { PageEditView.__super__.renderCallback.apply(this, arguments); @@ -210,7 +220,7 @@ } }); - var PageHistoryView = MasterPageView.extend({ + var PageHistoryView = exports.PageHistoryView = MasterPageView.extend({ templateName: 'history-page', renderCallback: function(view, model) { PageHistoryView.__super__.renderCallback.apply(this, arguments); @@ -225,40 +235,53 @@ } }); - var PageRevisionView = MasterPageView.extend({ + var PageRevisionView = exports.PageRevisionView = MasterPageView.extend({ templateName: 'revision-page', titleFormat: function(title) { return title + ' [' + this.model.get('rev') + ']'; } }); - var PageDiffView = MasterPageView.extend({ + var PageDiffView = exports.PageDiffView = MasterPageView.extend({ templateName: 'diff-page', titleFormat: function(title) { return title + ' [' + this.model.get('rev1') + '-' + this.model.get('rev2') + ']'; } }); - var IncomingLinksView = MasterPageView.extend({ + var IncomingLinksView = exports.IncomingLinksView = MasterPageView.extend({ templateName: 'inlinks-page', titleFormat: function(title) { return 'Incoming Links: ' + title; } }); - var WikiSearchView = MasterPageView.extend({ + var WikiSearchView = exports.WikiSearchView = MasterPageView.extend({ templateName: 'search-results' }); - return { - PageReadView: PageReadView, - PageEditView: PageEditView, - PageHistoryView: PageHistoryView, - IncomingLinksView: IncomingLinksView, - PageRevisionView: PageRevisionView, - PageDiffView: PageDiffView, - WikiSearchView: WikiSearchView, - LoginView: LoginView - }; + var SpecialNavigationView = exports.SpecialNavigationView = NavigationView.extend({ + templateName: 'special-nav' + }); + + var SpecialPagesView = exports.SpecialPagesView = MasterPageView.extend({ + templateName: 'special-pages', + _createNavigation: function(model) { + model.set('show_root_link', false); + return new SpecialNavigationView({ model: model }); + } + }); + + var GenericSpecialPageView = exports.GenericSpecialPageView = MasterPageView.extend({ + templateName: function() { + return 'special-' + this.model.get('page'); + }, + _createNavigation: function(model) { + model.set('show_root_link', true); + return new SpecialNavigationView({ model: model }); + } + }); + + return exports; }); diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/tpl/special-nav.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wikked/static/tpl/special-nav.html Tue Jan 01 00:49:54 2013 -0800 @@ -0,0 +1,18 @@ + diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/tpl/special-orphans.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wikked/static/tpl/special-orphans.html Tue Jan 01 00:49:54 2013 -0800 @@ -0,0 +1,14 @@ +
+
+

Orphaned Pages

+

The following pages are not linked to by any other page in the wiki.

+

Note The main page can occasionally show up here but that's OK since it's the page visitors will see first anyway.

+ {{#if orphans}} + {{#each orphans}} +

{{meta.title}}

+ {{/each}} + {{else}} +

No orphaned pages!

+ {{/if}} +
+
diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/static/tpl/special-pages.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wikked/static/tpl/special-pages.html Tue Jan 01 00:49:54 2013 -0800 @@ -0,0 +1,7 @@ +
+
+

Special Pages

+

Orphaned Pages

+

Lists pages in the wiki that have no links to them.

+
+
diff -r 8d6c2a5ed08d -r 8a4e0fe2c689 wikked/views.py --- a/wikked/views.py Mon Dec 31 22:02:39 2012 -0800 +++ b/wikked/views.py Tue Jan 01 00:49:54 2013 -0800 @@ -209,6 +209,16 @@ pass +@app.route('/api/special/orphans') +def api_special_orphans(): + orphans = [] + for page in wiki.getPages(): + if len(page.in_links) == 0: + orphans.append({ 'path': page.url, 'meta': page.all_meta }) + result = { 'orphans': orphans } + return make_auth_response(result) + + @app.route('/api/history/') def api_page_history(url): page = get_page_or_404(url)