Commit 9fa0b565383754d62fd01d080312f65326fa96a5

Add Header and Footer config in the editor

  Now header and footer can be added from the Mouchak editor directly (via HTML)
  
5050if siteMenu.find_one() == None:
5151 siteMenu.insert({'customMenu': False, 'menuOrder': [], 'html': ''})
5252
53siteFooter = db['footer']
54if siteFooter.find_one() == None:
55 siteFooter.insert({'html': ''})
5356
57siteHeader = db['header']
58if siteHeader.find_one() == None:
59 siteHeader.insert({'html': ''})
60
61
5462# handy reference to otherwise long name
5563bson.ObjId = bson.objectid.ObjectId
5664
7676 del(menu['_id'])
7777 menu['id'] = str(objId)
7878
79 return {'content': content, 'menu': menu}
79 footer = siteFooter.find_one()
80 objId = bson.ObjId(footer['_id'])
81 del(footer['_id'])
82 footer['id'] = str(objId)
8083
84 header = siteHeader.find_one()
85 objId = bson.ObjId(header['_id'])
86 del(header['_id'])
87 header['id'] = str(objId)
8188
89 return {'content': content, 'menu': menu, 'footer': footer, 'header':
90 header}
91
92
8293def allowed_file(filename):
8394 return '.' in filename and \
8495 filename.rsplit('.', 1)[1] in PLUGIN_ALLOWED_EXTENSIONS
103103@app.route('/', methods=['GET'])
104104def index():
105105 return flask.render_template('index.html', content=getContent(),
106 title=conf.SITE_TITLE, footer=conf.SITE_FOOTER)
106 title=conf.SITE_TITLE)
107107
108108
109109@app.route('/edit', methods=['GET'])
110110def edit():
111111 if "logged_in" in flask.session:
112112 flask.session['key'] = conf.SECRET_KEY
113 #print getContent()
113114 return flask.render_template('editor.html', content=getContent(),
114115 title=conf.SITE_TITLE)
115116 else:
131131 for page in siteContent.find().sort('_id', 1)[offset:offset+limit]:
132132 del(page['_id'])
133133 content.append(page)
134 print len(content)
134 #print len(content)
135135 return flask.make_response(json.dumps(content), '200 OK',
136136 {'Content-Type': 'application/json'})
137137 else:
144144 try:
145145 page = siteContent.find_one({'_id': bson.ObjId(_id)})
146146 del(page['_id'])
147 print page
147 #print page
148148 return flask.jsonify(page)
149149 except:
150150 return flask.abort(404)
153153@app.route('/page', methods=['POST'])
154154def insertPage():
155155 newpage = flask.request.json
156 print newpage
156 #print newpage
157157 res = siteContent.insert(newpage)
158158 _id = bson.ObjId(res)
159159 newpage['id'] = str(_id)
160160 del(newpage['_id'])
161 print newpage
161 #print newpage
162162 # FIXME: handle errors
163163 #return flask.jsonify(status='ok', page=newpage)
164164 return flask.jsonify(newpage)
188188 return flask.jsonify(status='ok')
189189 else:
190190 return flask.jsonify(error=res['err'], status='error')
191
192
193@app.route('/footer', methods=['POST'])
194def insertFooter():
195 return '200 OK'
196
197@app.route('/footer/<_id>', methods=['PUT'])
198def updateFooter(_id):
199 if flask.request.method == 'PUT':
200 changedFooter = flask.request.json
201 print "changed footer:"
202 print changedFooter
203 res = siteFooter.update({'_id': bson.ObjId(_id)}, changedFooter)
204 print res
205 return flask.jsonify(changedFooter)
206
207@app.route('/header', methods=['POST'])
208def insertHeader():
209 return '200 OK'
210
211@app.route('/header/<_id>', methods=['PUT'])
212def updateHeader(_id):
213 if flask.request.method == 'PUT':
214 changedHeader = flask.request.json
215 print "changed header:"
216 print changedHeader
217 res = siteHeader.update({'_id': bson.ObjId(_id)}, changedHeader)
218 print res
219 return flask.jsonify(changedHeader)
191220
192221
193222@app.route('/menu', methods=['POST'])
  
8383 width: 100%;
8484 height: 300px;
8585}
86#updateMenu {
86.update-btn {
8787 margin-top: 10px;
8888}
8989#editor-overlay {
  
1010 'click #addPage': 'addPage',
1111 'click .pagename .remove': 'removePage',
1212 'click #menu-config': 'showMenu',
13 'click #footer-config': 'showFooterConfig'
13 'click #footer-config': 'showFooterConfig',
14 'click #header-config': 'showHeaderConfig'
1415 },
1516 initialize: function() {
1617 _.bindAll.apply(_, [this].concat(_.functions(this)));
2626 //console.log(menu);
2727 this.menuconfig = new M.types.model.menu(menu);
2828 this.menuconfigview = new MenuConfigView({model: this.menuconfig});
29 this.footerconfig = new M.types.model.footer(M.site_content.footer);
30 this.footerconfigview = new FooterConfigView({model: this.footerconfig});
31 this.headerconfig = new M.types.model.header(M.site_content.header);
32 this.headerconfigview = new HeaderConfigView({model: this.headerconfig});
2933 },
3034 render: function() {
3135 // append the page list
9494 },
9595 showFooterConfig: function(event) {
9696 event.preventDefault();
97 //this.footerconfigview.render();
97 this.footerconfigview.render();
9898 return false;
9999 },
100 showHeaderConfig: function(event) {
101 event.preventDefault();
102 this.headerconfigview.render();
103 return false;
104 },
100105 // validate the page list with menu order list
101106 validate: function() {
102107 //TODO: validate if the menu order list matches with the list of pages
561561
562562 /* Footer Config View */
563563 var FooterConfigView = Backbone.View.extend({
564 tagName: 'div',
565 className: 'prettybox-lg',
566 id: 'page',
567 events: {
568 'click #updateFooter': 'saveFooter'
569 },
570 initialize: function() {
571 _.bindAll.apply(_, [this].concat(_.functions(this)));
572 this.template = _.template($('#footer-config-template').html());
573 },
574 render: function() {
575 $('#page').remove();
576 $('#content-container').append(this.$el);
577 //console.log('rendering..', this.$el);
578 this.$el.html(this.template({
579 footer: this.model.get('html')
580 }));
581 M.editor.code.init('footer-input', 'html');
582 },
583 saveFooter: function() {
584 var html = M.editor.code.save('footer-input');
585 this.model.set({html: html});
586 this.model.save({}, {
587 success: function(model, response) {
588 //console.log(model, response);
589 M.editor.hideOverlay();
590 M.editor.notifs.show('success', 'Saved', '');
591
592 },
593 error: function(xhr, response) {
594 M.editor.hideOverlay();
595 var msg = 'Something went wrong, and the page could not be updated';
596 M.editor.notifs.show('fail', 'Error!', msg);
597 }
598 });
599 M.editor.showOverlay();
600 }
601 });
602
603 /* Header Config View */
604 var HeaderConfigView = Backbone.View.extend({
605 tagName: 'div',
606 className: 'prettybox-lg',
607 id: 'page',
608 events: {
609 'click #updateHeader': 'saveHeader'
610 },
611 initialize: function() {
612 _.bindAll.apply(_, [this].concat(_.functions(this)));
613 this.template = _.template($('#header-config-template').html());
614 },
615 render: function() {
616 $('#page').remove();
617 $('#content-container').append(this.$el);
618 //console.log('rendering..', this.$el);
619 this.$el.html(this.template({
620 header: this.model.get('html')
621 }));
622 M.editor.code.init('header-input', 'html');
623 },
624 saveHeader: function() {
625 var html = M.editor.code.save('header-input');
626 this.model.set({html: html});
627 this.model.save({}, {
628 success: function(model, response) {
629 //console.log(model, response);
630 M.editor.hideOverlay();
631 M.editor.notifs.show('success', 'Saved', '');
632
633 },
634 error: function(xhr, response) {
635 M.editor.hideOverlay();
636 var msg = 'Something went wrong, and the page could not be updated';
637 M.editor.notifs.show('fail', 'Error!', msg);
638 }
639 });
640 M.editor.showOverlay();
641 }
564642 });
565643
566644 /* Notification view */
  
169169 },
170170 });
171171
172 var Footer = Backbone.Model.extend({
173 defaults: {
174 html: ''
175 },
176 url: function() {
177 return M.FooterURL() + '/' + this.id;
178 },
179 initialize: function() {
180 this.id = this.get('id');
181 }
182 });
183
184 var Header = Backbone.Model.extend({
185 defaults: {
186 html: ''
187 },
188 url: function() {
189 return M.HeaderURL() + '/' + this.id;
190 },
191 initialize: function() {
192 this.id = this.get('id');
193 }
194 });
195
172196 //export types to the typemap
173197 M.types = M.types || {};
174198 M.types.model = {
201201 'image': Image,
202202 'video': Video,
203203 'menu': Menu,
204 'footer': Footer,
205 'header': Header,
204206 'rss': RSS,
205207 'table': Table,
206208 'plugin': Plugin,
  
3838 },
3939 render: function() {
4040 // if custom menu is not defined, render a default menu
41 console.log(this.model.toJSON());
41 //console.log(this.model.toJSON());
4242 if(this.model.get('customMenu') === false) {
43 console.log('generating default menu..');
43 //console.log('generating default menu..');
4444 var startpage = M.site_content.menu.menuOrder[0];
4545 this.$el.append(this.template({
4646 brand: document.title,//brand name,
5151 }
5252 // else render the custom menu
5353 else {
54 console.log('rendering custom menu..');
54 //console.log('rendering custom menu..');
5555 this.$el.append(this.model.get('html'));
5656 }
5757 this.$links = $('.nav li');
8686 if(!event) {
8787 var fragment = location.hash.split('/')[1];
8888 //var pos = _.indexOf(M.pages.models, M.pages.where({'name': fragment})[0]);
89 //console.log(fragment);
8990 var pos = _.indexOf(this.model.get('menuOrder'), fragment);
91 //console.log(pos);
9092 if(!fragment) {
9193 pos = 0;
9294 }
9395 $(this.$links[pos]).addClass('active');
9496 }
9597 else {
98 //console.log();
9699 $(event.currentTarget).parent().addClass('active');
97100 }
98101 }
125125 else {
126126 $('#navigation').show();
127127 }
128 M.appView.navView.trigger('navclicked');
128 //console.log('navclicked');
129 M.appView.navView.trigger('navclicked');
129130 },
130131 render404: function() {
131132 $('.pageview').hide();
184184 Backbone.history.start();
185185
186186 if(!window.location.hash) {
187 var startpage = M.site_content.menu.menuOrder[0];
187 var startpage = '#/' + M.site_content.menu.menuOrder[0];
188 //console.log(startpage);
188189 app_router.navigate(startpage, {trigger: true});
189190 }
191 M.app_router = app_router;
190192
191193 //M.simHeir();
192194};
  
2222 // initialize editor
2323 window.M = window.M || {};
2424 M.MenuURL = function() { return "{{ url_for('insertMenu') }}"; };
25 M.FooterURL = function() { return "{{ url_for('insertFooter') }}"; };
26 M.HeaderURL = function() { return "{{ url_for('insertHeader') }}"; };
2527 M.PageURL = function() { return "{{ url_for('insertPage') }}"; };
2628 M.PluginUploadURL = function() { return "{{ url_for('uploadPlugin') }}"; };
2729 M.site_content = {{ content|tojson|safe }};
102102 </div>
103103 <div class="clearfix"></div>
104104 <div class="row">
105 <button id="updateMenu" class="btn btn-primary pull-right"> Update </button>
105 <button id="updateMenu" class="btn btn-primary pull-right update-btn"> Update </button>
106106 </div>
107107 <div class="clearfix"></div>
108108 </div>
109109 </script>
110110
111 <script type="text/template" id="header-config-template">
112 <div class="page">
113 <h4> Configure your header here </h4>
114 <div id="header-input" class="ace-mouchak">
115 <%= M.escapeHtml(header) %>
116 </div>
117 <div class="row">
118 <button id="updateHeader" class="btn btn-primary pull-right update-btn"> Update </button>
119 </div>
120 <div class="clearfix"></div>
121 </div>
122 </script>
123
124 <script type="text/template" id="footer-config-template">
125 <div class="page">
126 <h4> Configure your footer here </h4>
127 <div id="footer-input" class="ace-mouchak">
128 <%= M.escapeHtml(footer) %>
129 </div>
130 <div class="row">
131 <button id="updateFooter" class="btn btn-primary pull-right update-btn"> Update </button>
132 </div>
133 <div class="clearfix"></div>
134 </div>
135 </script>
136
111137 <script type="text/template" id="page-list-template">
112138 <div id="pagelistview">
113139 <h4> List of Pages </h4>
141141 <button class="btn btn-primary" id="addPage">Add Page</button>
142142 <hr>
143143 <p> <a href="#" id="menu-config"> Site Menu </a> </p>
144 <p> <a href="#" id="header-config"> Header Config </a> </p>
144145 <p> <a href="#" id="footer-config"> Footer Config </a> </p>
145146 <p><a href="{{ url_for('index') }}"> Go to site </a></p>
146147 </div>
  
77{% block body %}
88 <div class="container" id="container">
99 <div id="header">
10 <div id="header-banner">
11 {{ content['header']['html']|safe }}
12 </div>
1013 <div id="navigation"></div>
1114 </div>
1215 <div id="content-container"></div>
13 <div id="footer"> {{ footer|safe }} </div>
16 <div id="footer"> {{ content['footer']['html']|safe }} </div>
1417 </div>
1518
1619 <script>
setup.py
(2 / 2)
  
1010 'pymongo'
1111 ]
1212
13setup(name='mouchak',
13setup(name='Mouchak',
1414 version='0.1',
1515 description='Web framework',
1616 license='BSD',
2323 "Programming Language :: JavaScript",
2424 "Programming Language :: Python",
2525 "Programming Language :: Python :: 2.7",
26 "Programming Language :: JavaScript",
2726 "Topic :: Internet",
2827 "Topic :: Internet :: WWW/HTTP :: Site Management",
2928 ],
3029 author='Anon Ray, Arvind',
30 author_email='rayanon@riseup.net',
3131 url='https://git.pantoto.org/mouchak/mouchak.git',
3232 keywords='',
3333 packages=find_packages(),