Commit 3fd837c82fc36a1c9d67b643bc967fcc8172d5c5

Add support for menu order in default menu

  - Now with default menu, can specify the order of pages.
  - Fix custom menu not getting saved.
  - Fix irrelevant types in content editor.
  • Diff rendering mode:
  • inline
  • side by side

mouchak/server.py

17siteContent = db['content']17siteContent = db['content']
18siteMenu = db['menu']18siteMenu = db['menu']
19if siteMenu.find_one() == None:19if siteMenu.find_one() == None:
20 siteMenu.insert({'customMenu': False})
20 siteMenu.insert({'customMenu': False, 'menuOrder': []})
2121
22
22# handy reference to otherwise long name23# handy reference to otherwise long name
23bson.ObjId = bson.objectid.ObjectId24bson.ObjId = bson.objectid.ObjectId
2425
50@app.route('/edit', methods=['GET'])50@app.route('/edit', methods=['GET'])
51def edit():51def edit():
52 return flask.render_template('editor.html', content=getContent(),52 return flask.render_template('editor.html', content=getContent(),
53 title=conf)
53 title=conf.SITE_TITLE)
5454
5555
56@app.route('/page', methods=['POST'])56@app.route('/page', methods=['POST'])
115 # print _id115 # print _id
116 # res = siteMenu.remove({'_id': bson.ObjId(_id)})116 # res = siteMenu.remove({'_id': bson.ObjId(_id)})
117 # return flask.jsonify(status='deleted')117 # return flask.jsonify(status='deleted')
118
118119
119120
120if __name__ == "__main__":121if __name__ == "__main__":

mouchak/static/js/editor.js

9 'click .pagename .disp': 'showPage',9 'click .pagename .disp': 'showPage',
10 'click #addPage': 'addPage',10 'click #addPage': 'addPage',
11 'click .pagename .remove': 'removePage',11 'click .pagename .remove': 'removePage',
12 'click #menu-config': 'showMenu'//,
13 //'click #footer-config': 'footerConfig'
12 'click #menu-config': 'showMenu',
14 },13 },
15 initialize: function() {14 initialize: function() {
16 _.bindAll(this);15 _.bindAll(this);
24 //console.log(menu);24 //console.log(menu);
25 this.menuconfig = new M.types.model.menu(menu);25 this.menuconfig = new M.types.model.menu(menu);
26 this.menuconfigview = new MenuConfigView({model: this.menuconfig});26 this.menuconfigview = new MenuConfigView({model: this.menuconfig});
27 //this.footerconfigview = new FooterConfigView();
28 },27 },
29 render: function() {28 render: function() {
30 // append the page list29 // append the page list
67 },67 },
68 showMenu: function(event) {68 showMenu: function(event) {
69 this.menuconfigview.render();69 this.menuconfigview.render();
70 },
71 footerConfig: function(event) {
72 //this.footerconfigview.render();
73 }70 }
74 });71 });
7572
238 },238 },
239 render: function() {239 render: function() {
240 this.$el.html('');240 this.$el.html('');
241 console.log(this.model);
242 var type = this.model.get('type');241 var type = this.model.get('type');
243 this.$el.append(this.template({242 this.$el.append(this.template({
244 type: this.model.get('type'),243 type: this.model.get('type'),
246 }));246 }));
247247
248 this.$select = $('.contentview select');248 this.$select = $('.contentview select');
249 //this.$select.bind('change', this.typeChanged);
250 this.$select.val(type);249 this.$select.val(type);
251250
252 if(type === 'text') {251 if(type === 'text') {
258 }258 }
259 else if(type === 'image' || type === 'video' ||259 else if(type === 'image' || type === 'video' ||
260 type === 'audio' || type === 'plugin') {260 type === 'audio' || type === 'plugin') {
261 var template = _.template($('#media-template').html());
262261
262 var template = _.template($('#media-template').html());
263 $('#specific-content').html(template({263 $('#specific-content').html(template({
264 src: this.model.get('src')264 src: this.model.get('src')
265 }));265 }));
266266
267 //provide the users a preview
267 //TODO: provide the users a preview
268 /*var view = new M.types.view[type]({model: this.model});268 /*var view = new M.types.view[type]({model: this.model});
269 //$('#specific-content.preview').html();269 //$('#specific-content.preview').html();
270 view.render('.preview');*/270 view.render('.preview');*/
309 }309 }
310 });310 });
311311
312 /* view to configure footer */
313 var FooterConfigView = Backbone.View.extend({
314 tagName: 'div',
315 id: 'page',
316 events: {
317 'click #saveFooter': 'saveFooter'
318 },
319 initialize: function() {
320 _.bindAll(this);
321 this.template = _.template($('#footer-config-template').html());
322 },
323 render: function() {
324 $('#page').remove();
325 $('#content-container').append(this.$el);
326 this.$el.html(this.template());
327 M.editor.wysiwig('#footer-input');
328 },
329 saveFooter: function() {
330 tinymce.triggerSave(false, true);
331 var data = $('#footer-input').html();
332 console.log(data);
333 }
334 });
335
336 /* view to configure custom navigation menu */312 /* view to configure custom navigation menu */
337 var MenuConfigView = Backbone.View.extend({313 var MenuConfigView = Backbone.View.extend({
338 tagName: 'div',314 tagName: 'div',
326 $('#content-container').append(this.$el);326 $('#content-container').append(this.$el);
327 console.log('rendering..', this.$el);327 console.log('rendering..', this.$el);
328 this.$el.html(this.template({328 this.$el.html(this.template({
329 menu_order: this.model.get('menuOrder'),
329 pos: this.model.get('pos'),330 pos: this.model.get('pos'),
330 menu: this.model.get('html')331 menu: this.model.get('html')
331 }));332 }));
332 this.$menuOptions = $('.menu-options');333 this.$menuOptions = $('.menu-options');
334 this.$menuOrder = $('#menu-order-wrap');
333335
334 if(this.model.get('customMenu') === true) {336 if(this.model.get('customMenu') === true) {
335 $('#custom-menu').attr('checked', true);337 $('#custom-menu').attr('checked', true);
336 this.$menuOptions.show({complete: function() {338 this.$menuOptions.show({complete: function() {
337 M.editor.wysiwig('#menu');
339 //M.editor.wysiwig('#menu');
338 }});340 }});
339 }341 }
340 },342 },
341 showMenuOptions: function(bool) {343 showMenuOptions: function(bool) {
342 if(bool === true) {344 if(bool === true) {
345 this.$menuOrder.hide();
343 this.$menuOptions.show({complete: function() {346 this.$menuOptions.show({complete: function() {
344 //M.editor.wysiwig('#menu');347 //M.editor.wysiwig('#menu');
345 }});348 }});
346 }349 }
347 else {350 else {
351 this.$menuOrder.show();
348 this.$menuOptions.hide();352 this.$menuOptions.hide();
349 }353 }
350 },354 },
364 },364 },
365 saveMenu: function() {365 saveMenu: function() {
366 console.log('saving menu..');366 console.log('saving menu..');
367 // var menuHTML = $('#menu').val().trim();
368 //this.model.set({'html': menuHTML});
369 //console.log(this.model.toJSON());
370 //alert('saveMenu called');
371 var bool;
372 if($("custom-menu").is(":checked")) {
367 var bool, html = '', menuOrder = [];
368 if($('#custom-menu').is(":checked")) {
373 bool = true;369 bool = true;
370 html = $('#menu').val().trim();
374 }371 }
375 else {372 else {
376 bool = false;373 bool = false;
374 menuOrder = $('#menu-order').val().split(',');
377 }375 }
378 this.model.save({customMenu: bool}, {
376 this.model.set({'customMenu': bool, 'html': html, 'menuOrder': menuOrder});
377 console.log(this.model.toJSON());
378 this.model.save({}, {
379 success: function(model, response) {379 success: function(model, response) {
380 console.log(model, response);380 console.log(model, response);
381 },381 },

mouchak/static/js/models.js

137 'Pages': Pages137 'Pages': Pages
138 };138 };
139139
140 //content types to render in content menu
141 M.contentTypes = ['text', 'image', 'video', 'table', 'plugin'];
142
140})(M);143})(M);

mouchak/static/js/mouchak.js

64 },64 },
65 populate: function() {65 populate: function() {
66 var item_template = _.template($('#nav-item-template').html());66 var item_template = _.template($('#nav-item-template').html());
67 _.each(M.pages.models, function(page) {
68 //console.log('no children?', _.isEmpty(page.get('children')));
67 _.each(this.model.get('menuOrder'), function(page) {
69 this.$ul.append(item_template({68 this.$ul.append(item_template({
69 cls: '',
70 page: page
71 }));
72 //console.log('no children?', _.isEmpty(page.get('children')));
73 /*this.$ul.append(item_template({
70 cls: (_.isEmpty(page.get('children'))) ? '' : 'dropdown',74 cls: (_.isEmpty(page.get('children'))) ? '' : 'dropdown',
71 page: page.get('name')75 page: page.get('name')
72 }));
76 }));*/
73 }, this);77 }, this);
74 },78 },
75 navClicked: function(event) {79 navClicked: function(event) {
76 this.$links.removeClass('active');80 this.$links.removeClass('active');
77 if(!event) {81 if(!event) {
78 var fragment = location.hash.split('/')[1];82 var fragment = location.hash.split('/')[1];
79 var pos = _.indexOf(M.pages.models, M.pages.where({'name': fragment})[0]);
83 //var pos = _.indexOf(M.pages.models, M.pages.where({'name': fragment})[0]);
84 var pos = _.indexOf(this.model.get('menuOrder'), fragment);
80 if(!fragment) {85 if(!fragment) {
81 pos = 0;86 pos = 0;
82 }87 }

mouchak/templates/editor.html

54 <div class="page">54 <div class="page">
55 <div class="menu-config">55 <div class="menu-config">
56 <h4> Menu Config </h4>56 <h4> Menu Config </h4>
57 <!-- <form class="form-horizontal"> -->
57 <div class="control-group">
58 <input id="custom-menu" type="checkbox">
59 <span class=""><strong> Custom Menu </strong></span>
60 </div>
61 <div class="control-group" id="menu-order-wrap">
62 <% if(!$('#custom-menu').is(':checked')) { %>
63 <div class="input-prepend">
64 <span class="add-on"> <strong> Menu Order</strong></span>
65 <input id="menu-order" type="text"
66 placeholder="list,page,names,for,menu,order" value="<%= menu_order %>">
67 </div>
68 <% } %>
69 </div>
70 <div class="menu-options" style="display: none;">
58 <div class="control-group">71 <div class="control-group">
59 <input id="custom-menu" type="checkbox">
60 <span class=""><strong> Custom Menu </strong></span>
61 </div>
62 <button id="updateMenu" class="btn btn-primary pull-right"> Update </button>
63 <div class="clearfix"></div>
64 <div class="menu-options" style="display: none;">
65 <div class="control-group">
66 <div class="input-prepend">
67 <span class="add-on"> <strong> Position </strong></span>
68 <input id="pos" type="text" placeholder="[left, top]"
69 value="<%= pos %>">
70 </div>
72 <div class="input-prepend">
73 <span class="add-on"> <strong> Position </strong></span>
74 <input id="pos" type="text" placeholder="[left, top]"
75 value="<%= pos %>">
71 </div>76 </div>
72 <label><strong> HTML </strong></label>
73 <div id="menu">
74 <%= menu %>
75 </div>
76 </div>77 </div>
77 <!-- </form> -->
78 <label><strong> HTML for menu: </strong></label>
79 <textarea cols="25" rows="8" id="menu"><%= menu %></textarea>
80 </div>
78 </div>81 </div>
82 <button id="updateMenu" class="btn btn-primary pull-right"> Update </button>
83 <div class="clearfix"></div>
79 </div>84 </div>
80 </script>85 </script>
8186
169 <div class="">169 <div class="">
170 <label><b>Type</b></label>170 <label><b>Type</b></label>
171 <select>171 <select>
172 <% _.each(_.keys(M.types.model), function(type) { %>
172 <% _.each(M.contentTypes, function(type) { %>
173 <option><%= type %></option>173 <option><%= type %></option>
174 <% }); %>174 <% }); %>
175 </select>175 </select>