Mercurial > wikked
changeset 296:d1e7f4c35afd
Frontend code cleanup, optimization, and remembering the menu state.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 28 Sep 2014 23:24:44 -0700 |
parents | 3faee3c34d0c |
children | eb4897943264 |
files | wikked/assets/js/wikked/app.js wikked/assets/js/wikked/models.js wikked/assets/js/wikked/views.js wikked/assets/tpl/nav.html |
diffstat | 4 files changed, 133 insertions(+), 120 deletions(-) [+] |
line wrap: on
line diff
--- a/wikked/assets/js/wikked/app.js Sun Sep 28 23:23:51 2014 -0700 +++ b/wikked/assets/js/wikked/app.js Sun Sep 28 23:24:44 2014 -0700 @@ -31,12 +31,12 @@ if (view) { this._currentView = view; - this.el.html(view.el); if (autoFetch || autoFetch === undefined) { view.model.fetch(); } else { view.render(); } + this.el.empty().append(view.el); } return this; @@ -80,14 +80,15 @@ 'special/orphans': "showOrphans" }, readPage: function(path) { - path_clean = this.stripQuery(path); - no_redirect = this.getQueryVariable('no_redirect', path); + var path_clean = this.stripQuery(path); + var no_redirect = this.getQueryVariable('no_redirect', path); + var model_attrs = { path: path_clean }; + if (no_redirect) model_attrs.no_redirect = true; + var view = new Views.PageReadView({ - model: new Models.PageReadModel({ path: path_clean }) + model: new Models.PageReadModel(model_attrs) }); - if (no_redirect) { - view.model.set('no_redirect', true); - } + this.viewManager.switchView(view); this.navigate('/read/' + path); },
--- a/wikked/assets/js/wikked/models.js Sun Sep 28 23:23:51 2014 -0700 +++ b/wikked/assets/js/wikked/models.js Sun Sep 28 23:24:44 2014 -0700 @@ -16,22 +16,18 @@ defaults: function() { return { path: "", - action: "read", username: false, + urls: [], url_extras: [ { name: 'Special Pages', url: '/#/special', icon: 'dashboard' } ] }; }, initialize: function() { - this.on('change:path', function(model, path) { - model._onChangePath(path); - }); - this._onChangePath(this.get('path')); - this.on('change:user', function(model, auth) { - model._onChangeUser(auth); - }); - this._onChangeUser(this.get('user')); + this.on('change:path', this._onChangePath, this); + this.on('change:user', this._onChangeUser, this); + this._onChangePath(this, this.get('path')); + this._onChangeUser(this, this.get('user')); return this; }, url: function() { @@ -76,14 +72,17 @@ doNewPage: function(form) { this.navigate('/create/', { trigger: true }); }, - _onChangePath: function(path) { - this.set({ - url_home: '/', - url_read: '/#/read/' + path, - url_edit: '/#/edit/' + path, - url_hist: '/#/changes/' + path, - url_search: '/search' - }); + _onChangePath: function(model, path) { + var attrs ={ + url_home: '/#/'}; + var urls = this.get('urls'); + if (_.contains(urls, 'read')) + attrs.url_read = '/#/read/' + path; + if (_.contains(urls, 'edit')) + attrs.url_edit = '/#/edit/' + path; + if (_.contains(urls, 'history')) + attrs.url_hist = '/#/changes/' + path; + this.set(attrs); }, _isSearching: false, _pendingQuery: null, @@ -97,7 +96,7 @@ this.doPreviewSearch(q, c); } }, - _onChangeUser: function(user) { + _onChangeUser: function(model, user) { if (user) { this.set({ url_login: false, @@ -158,14 +157,10 @@ }; }, initialize: function() { - this.on('change:path', function(model, path) { - model._onChangePath(path); - }); - this.on('change:text', function(model, text) { - model._onChangeText(text); - }); - this._onChangePath(this.get('path')); - this._onChangeText(''); + this.on('change:path', this._onChangePath, this); + this.on('change:text', this._onChangeText, this); + this._onChangePath(this, this.get('path')); + this._onChangeText(this, ''); return this; }, url: function() { @@ -189,45 +184,53 @@ this._onAppSet(app); } }, - _onChangePath: function(path) { + _onChangePath: function(model, path) { }, - _onChangeText: function(text) { + _onChangeText: function(model, text) { this.set('content', new Handlebars.SafeString(text)); } }); var PageStateModel = exports.PageStateModel = PageModel.extend({ urlRoot: '/api/state/', - _onChangePath: function(path) { + _onChangePath: function(model, path) { PageStateModel.__super__._onChangePath.apply(this, arguments); this.set('url_edit', '/#/edit/' + path); } }); var MasterPageModel = exports.MasterPageModel = PageModel.extend({ + navUrls: [], initialize: function() { - this.nav = new NavigationModel({ path: this.id }); + var navAttrs = { path: this.id, urls: this.navUrls }; + this.nav = new NavigationModel(navAttrs); this.footer = new FooterModel(); MasterPageModel.__super__.initialize.apply(this, arguments); - this.on('change:auth', function(model, auth) { - model._onChangeAuth(auth); - }); + this._addNavExtraUrls(); + this._addFooterExtraUrls(); + this.on('change:auth', this._onChangeAuth, this); this.on('error', this._onError, this); - if (this.action !== undefined) { - this.nav.set('action', this.action); - this.footer.set('action', this.action); - } return this; }, + _addNavExtraUrls: function() { + }, + _addFooterExtraUrls: function() { + var model = this; + this.footer.addExtraUrl( + 'JSON', + function() { return model.url(); }, + -1, + 'cog'); + }, _onAppSet: function(app) { this.nav.app = app; this.footer.app = app; }, - _onChangePath: function(path) { + _onChangePath: function(model, path) { MasterPageModel.__super__._onChangePath.apply(this, arguments); this.nav.set('path', path); }, - _onChangeAuth: function(auth) { + _onChangeAuth: function(model, auth) { this.nav.set('auth', auth); }, _onError: function(model, resp) { @@ -252,23 +255,29 @@ var PageReadModel = exports.PageReadModel = MasterPageModel.extend({ urlRoot: '/api/read/', - action: 'read', + navUrls: ['edit', 'history'], initialize: function() { PageReadModel.__super__.initialize.apply(this, arguments); this.on('change', this._onChange, this); - - // Add extra links to the footer. + return this; + }, + _addNavExtraUrls: function() { + PageReadModel.__super__._addNavExtraUrls.apply(this, arguments); var model = this; this.nav.addExtraUrl( 'Pages Linking Here', function() { return '/#/inlinks/' + model.id; }, 1, 'link'); + }, + _addFooterExtraUrls: function() { + PageReadModel.__super__._addFooterExtraUrls.apply(this, arguments); + var model = this; this.footer.addExtraUrl( - 'JSON', - function() { return '/api/read/' + model.id; }, + 'RAW', + function() { return '/api/raw/' + model.id; }, -1, - 'cog'); + 'wrench'); }, url: function() { var url = PageReadModel.__super__.url.apply(this, arguments); @@ -293,13 +302,12 @@ }); var PageSourceModel = exports.PageSourceModel = MasterPageModel.extend({ - urlRoot: '/api/raw/', - action: 'source' + urlRoot: '/api/raw/' }); var PageEditModel = exports.PageEditModel = MasterPageModel.extend({ - action: 'edit', urlRoot: '/api/edit/', + navUrls: ['read', 'history'], doEdit: function(form) { if (this.get('is_new')) { this.set('path', $('input[name="title"]', form).val()); @@ -329,16 +337,7 @@ var PageHistoryModel = exports.PageHistoryModel = MasterPageModel.extend({ urlRoot: '/api/history/', - action: 'history', - initialize: function() { - PageHistoryModel.__super__.initialize.apply(this, arguments); - var model = this; - this.nav.addExtraUrl( - 'JSON', - function() { return '/api/history/' + model.id; }, - -1, - 'road'); - }, + navUrls: ['read', 'edit'], doDiff: function(form) { var rev1 = $('input[name=rev1]:checked', form).val(); var rev2 = $('input[name=rev2]:checked', form).val(); @@ -357,7 +356,6 @@ }); var PageRevisionModel = exports.PageRevisionModel = MasterPageModel.extend({ - action: 'revision', defaults: function() { return { path: "", @@ -369,10 +367,8 @@ }, initialize: function() { PageRevisionModel.__super__.initialize.apply(this, arguments); - this.on('change:rev', function(model, rev) { - model._onChangeRev(rev); - }); - this._onChangeRev(this.get('rev')); + this.on('change:rev', this._onChangeRev, this); + this._onChangeRev(this, this.get('rev')); return this; }, doRevert: function(form) { @@ -386,7 +382,7 @@ alert('Error reverting page...'); }); }, - _onChangeRev: function(rev) { + _onChangeRev: function(model, rev) { var setmap = { disp_rev: rev }; if (rev.match(/[a-f0-9]{40}/)) { setmap.disp_rev = rev.substring(0, 8); @@ -396,7 +392,6 @@ }); var PageDiffModel = exports.PageDiffModel = MasterPageModel.extend({ - action: 'diff', defaults: function() { return { path: "", @@ -413,24 +408,20 @@ }, initialize: function() { PageDiffModel.__super__.initialize.apply(this, arguments); - this.on('change:rev1', function(model, rev1) { - model._onChangeRev1(rev1); - }); - this.on('change:rev2', function(model, rev2) { - model._onChangeRev2(rev2); - }); - this._onChangeRev1(this.get('rev1')); - this._onChangeRev2(this.get('rev2')); + this.on('change:rev1', this._onChangeRev1, this); + this.on('change:rev2', this._onChangeRev2, this); + this._onChangeRev1(this, this.get('rev1')); + this._onChangeRev2(this, this.get('rev2')); return this; }, - _onChangeRev1: function(rev1) { + _onChangeRev1: function(model, rev1) { var setmap = { disp_rev1: rev1 }; if (rev1 !== undefined && rev1.match(/[a-f0-9]{40}/)) { setmap.disp_rev1 = rev1.substring(0, 8); } this.set(setmap); }, - _onChangeRev2: function(rev2) { + _onChangeRev2: function(model, rev2) { var setmap = { disp_rev2: rev2 }; if (rev2 !== undefined && rev2.match(/[a-f0-9]{40}/)) { setmap.disp_rev2 = rev2.substring(0, 8); @@ -441,7 +432,6 @@ var IncomingLinksModel = exports.IncomingLinksModel = MasterPageModel.extend({ urlRoot: '/api/inlinks/', - action: 'inlinks', _onChangePath: function(path) { IncomingLinksModel.__super__._onChangePath.apply(this, arguments); this.set('url_read', '/#/read/' + path); @@ -450,7 +440,6 @@ var WikiSearchModel = exports.WikiSearchModel = MasterPageModel.extend({ urlRoot: '/api/search', - action: 'search', title: function() { return 'Search'; }, @@ -460,21 +449,19 @@ }); var SpecialPagesModel = exports.SpecialPagesModel = MasterPageModel.extend({ - action: 'special', title: function() { return 'Special Pages'; }, initialize: function() { SpecialPagesModel.__super__.initialize.apply(this, arguments); - this.nav.clearExtraUrls(); + }, + _addFooterExtraUrls: function() { } }); var SpecialPageModel = exports.SpecialPageModel = MasterPageModel.extend({ - action: 'special', initialize: function() { SpecialPageModel.__super__.initialize.apply(this, arguments); - this.nav.clearExtraUrls(); } }); @@ -482,10 +469,10 @@ title: "Wiki History", initialize: function() { SpecialChangesModel.__super__.initialize.apply(this, arguments); - this.on('change:history', this._onHistoryChanged); + this.on('change:history', this._onHistoryChanged, this); }, url: function() { - var url = '/api/history'; + var url = '/api/site-history'; if (this.get('after_rev')) url += '?rev=' + this.get('after_rev'); return url;
--- a/wikked/assets/js/wikked/views.js Sun Sep 28 23:23:51 2014 -0700 +++ b/wikked/assets/js/wikked/views.js Sun Sep 28 23:24:44 2014 -0700 @@ -124,10 +124,8 @@ isMainPage: true, initialize: function() { PageView.__super__.initialize.apply(this, arguments); - if (this.model !== undefined) { - var $view = this; - this.model.on("change", function() { $view._onModelChange(); }); - } + if (this.model) + this.model.on("change", this._onModelChange, this); return this; }, dispose: function() { @@ -145,7 +143,12 @@ this.template = Handlebars.compile(_.result(this, 'templateSource')); } if (this.template !== undefined) { - this.renderTemplate(this.template); + var markup = this.renderTemplate(this.template); + var $markup = $(markup); + if (this.preRenderCallback !== undefined) { + this.preRenderCallback($markup); + } + this.$el.append($markup); if (this.renderCallback !== undefined) { this.renderCallback(); } @@ -156,7 +159,11 @@ return this; }, renderTemplate: function(tpl) { - this.$el.html(tpl(this.model.toJSON())); + var ctx = this.renderContext(); + return tpl(ctx); + }, + renderContext: function() { + return this.model.toJSON(); }, renderTitle: function(formatter) { var title = _.result(this.model, 'title'); @@ -172,26 +179,30 @@ _.extend(PageView, Backbone.Events); var NavigationView = exports.NavigationView = PageView.extend({ + className: 'nav-wrapper', templateSource: tplNav, isMainPage: false, initialize: function() { NavigationView.__super__.initialize.apply(this, arguments); return this; }, - render: function() { - NavigationView.__super__.render.apply(this, arguments); - + renderContext: function() { + var ctx = NavigationView.__super__.renderContext.apply(this, arguments); + var ima = localStorage.getItem('wikked.nav.isMenuActive'); + if (ima == 'true') ctx.showMenu = true; + return ctx; + }, + renderCallback: function() { // Hide the drop-down for the search results. this.searchPreviewList = this.$('#search-preview'); this.searchPreviewList.hide(); this.activeResultIndex = -1; - this.wikiMenu = $('#wiki-menu'); - this.wrapperAndWikiMenu = $('.wrapper, #wiki-menu'); + // Cache some stuff for handling the menu. + this.wikiMenu = this.$('#wiki-menu'); + this.wrapperAndWikiMenu = this.$('.wrapper, #wiki-menu'); this.isMenuActive = (this.wikiMenu.css('left') == '0px'); this.isMenuActiveLocked = false; - - return this; }, events: { "click #wiki-menu-shortcut": "_onMenuShortcutClick", @@ -208,6 +219,7 @@ }, _onMenuShortcutClick: function(e) { this.isMenuActive = !this.isMenuActive; + localStorage.setItem('wikked.nav.isMenuActive', this.isMenuActive); }, _onMenuShortcutHover: function(e) { if (!this.isMenuActive && !this.isMenuActiveLocked) @@ -313,6 +325,7 @@ }); var FooterView = exports.FooterView = PageView.extend({ + className: 'footer-wrapper', templateSource: tplFooter, isMainPage: false, initialize: function() { @@ -338,17 +351,37 @@ }); var MasterPageView = exports.MasterPageView = PageView.extend({ + className: function() { + var cls = 'wrapper'; + + // HACK-ish: we need to know if the menu needs to be shown + // on init or not. Can't do it later otherwise + // we'll get the CSS animation to play right away. + var ima = localStorage.getItem('wikked.nav.isMenuActive'); + if (ima == 'true') cls += ' wiki-menu-active'; + + return cls; + }, initialize: function() { MasterPageView.__super__.initialize.apply(this, arguments); this.nav = this._createNavigation(this.model.nav); this.footer = this._createFooter(this.model.footer); return this; }, + dispose: function() { + if (this.footer) this.footer.dispose(); + if (this.nav) this.nav.dispose(); + MasterPageView.__super__.dispose.apply(this, arguments); + }, renderCallback: function() { - this.$el.prepend('<div class="nav-wrapper"></div>'); - this.$el.append('<div class="footer-wrapper"></div>'); - this.nav.setElement(this.$('>.nav-wrapper')).render(); - this.footer.setElement(this.$('>.footer-wrapper')).render(); + if (this.nav) { + this.nav.render(); + this.$el.prepend(this.nav.el); + } + if (this.footer) { + this.footer.render(); + this.$el.append(this.footer.el); + } this.isError = (this.model.get('error_code') !== undefined); }, templateSource: function() { @@ -588,16 +621,8 @@ defaultTemplateSource: tplSearchResults }); - var SpecialNavigationView = exports.SpecialNavigationView = NavigationView.extend({ - templateSource: tplSpecialNav - }); - var SpecialMasterPageView = exports.SpecialMasterPageView = MasterPageView.extend({ - className: 'wrapper special', - _createNavigation: function(model) { - model.set('show_root_link', true); - return new SpecialNavigationView({ model: model }); - } + className: 'wrapper special' }); var SpecialPagesView = exports.SpecialPagesView = SpecialMasterPageView.extend({
--- a/wikked/assets/tpl/nav.html Sun Sep 28 23:23:51 2014 -0700 +++ b/wikked/assets/tpl/nav.html Sun Sep 28 23:24:44 2014 -0700 @@ -1,13 +1,13 @@ <a id="wiki-menu-shortcut" class="wiki-logo"> <span>W</span> </a> -<nav id="wiki-menu" role="navigation" class="pure-menu pure-menu-open"> +<nav id="wiki-menu" role="navigation" class="pure-menu pure-menu-open{{#if showMenu}} wiki-menu-active{{/if}}"> <ul class=""> <li><a href="/"><span class="glyphicon glyphicon-home"></span> Home</a></li> <li><a href="/#/create/"><span class="glyphicon glyphicon-file"></span> New Page</a></li> - {{#ifneq action to='read'}}<li><a href="{{url_read}}"><span class="glyphicon glyphicon-book"></span> Read</a></li>{{/ifneq}} - {{#ifneq action to='edit'}}<li><a href="{{url_edit}}"><span class="glyphicon glyphicon-edit"></span> Edit</a></li>{{/ifneq}} - {{#ifneq action to='history'}}<li><a href="{{url_hist}}"><span class="glyphicon glyphicon-road"></span> History</a></li>{{/ifneq}} + {{#if url_read}}<li><a href="{{url_read}}"><span class="glyphicon glyphicon-book"></span> Read</a></li>{{/if}} + {{#if url_edit}}<li><a href="{{url_edit}}"><span class="glyphicon glyphicon-edit"></span> Edit</a></li>{{/if}} + {{#if url_hist}}<li><a href="{{url_hist}}"><span class="glyphicon glyphicon-road"></span> History</a></li>{{/if}} </ul> <form role="search" id="search" class="pure-form pure-menu-form pure-menu-divider"> <fieldset>