Commit 9fa0b565383754d62fd01d080312f65326fa96a5
- Diff rendering mode:
- inline
- side by side
mouchak/server.py
(55 / 6)
  | |||
50 | 50 | if siteMenu.find_one() == None: | |
51 | 51 | siteMenu.insert({'customMenu': False, 'menuOrder': [], 'html': ''}) | |
52 | 52 | ||
53 | siteFooter = db['footer'] | ||
54 | if siteFooter.find_one() == None: | ||
55 | siteFooter.insert({'html': ''}) | ||
53 | 56 | ||
57 | siteHeader = db['header'] | ||
58 | if siteHeader.find_one() == None: | ||
59 | siteHeader.insert({'html': ''}) | ||
60 | |||
61 | |||
54 | 62 | # handy reference to otherwise long name | |
55 | 63 | bson.ObjId = bson.objectid.ObjectId | |
56 | 64 | ||
… | … | ||
76 | 76 | del(menu['_id']) | |
77 | 77 | menu['id'] = str(objId) | |
78 | 78 | ||
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) | ||
80 | 83 | ||
84 | header = siteHeader.find_one() | ||
85 | objId = bson.ObjId(header['_id']) | ||
86 | del(header['_id']) | ||
87 | header['id'] = str(objId) | ||
81 | 88 | ||
89 | return {'content': content, 'menu': menu, 'footer': footer, 'header': | ||
90 | header} | ||
91 | |||
92 | |||
82 | 93 | def allowed_file(filename): | |
83 | 94 | return '.' in filename and \ | |
84 | 95 | filename.rsplit('.', 1)[1] in PLUGIN_ALLOWED_EXTENSIONS | |
… | … | ||
103 | 103 | @app.route('/', methods=['GET']) | |
104 | 104 | def index(): | |
105 | 105 | return flask.render_template('index.html', content=getContent(), | |
106 | title=conf.SITE_TITLE, footer=conf.SITE_FOOTER) | ||
106 | title=conf.SITE_TITLE) | ||
107 | 107 | ||
108 | 108 | ||
109 | 109 | @app.route('/edit', methods=['GET']) | |
110 | 110 | def edit(): | |
111 | 111 | if "logged_in" in flask.session: | |
112 | 112 | flask.session['key'] = conf.SECRET_KEY | |
113 | #print getContent() | ||
113 | 114 | return flask.render_template('editor.html', content=getContent(), | |
114 | 115 | title=conf.SITE_TITLE) | |
115 | 116 | else: | |
… | … | ||
131 | 131 | for page in siteContent.find().sort('_id', 1)[offset:offset+limit]: | |
132 | 132 | del(page['_id']) | |
133 | 133 | content.append(page) | |
134 | print len(content) | ||
134 | #print len(content) | ||
135 | 135 | return flask.make_response(json.dumps(content), '200 OK', | |
136 | 136 | {'Content-Type': 'application/json'}) | |
137 | 137 | else: | |
… | … | ||
144 | 144 | try: | |
145 | 145 | page = siteContent.find_one({'_id': bson.ObjId(_id)}) | |
146 | 146 | del(page['_id']) | |
147 | print page | ||
147 | #print page | ||
148 | 148 | return flask.jsonify(page) | |
149 | 149 | except: | |
150 | 150 | return flask.abort(404) | |
… | … | ||
153 | 153 | @app.route('/page', methods=['POST']) | |
154 | 154 | def insertPage(): | |
155 | 155 | newpage = flask.request.json | |
156 | print newpage | ||
156 | #print newpage | ||
157 | 157 | res = siteContent.insert(newpage) | |
158 | 158 | _id = bson.ObjId(res) | |
159 | 159 | newpage['id'] = str(_id) | |
160 | 160 | del(newpage['_id']) | |
161 | print newpage | ||
161 | #print newpage | ||
162 | 162 | # FIXME: handle errors | |
163 | 163 | #return flask.jsonify(status='ok', page=newpage) | |
164 | 164 | return flask.jsonify(newpage) | |
… | … | ||
188 | 188 | return flask.jsonify(status='ok') | |
189 | 189 | else: | |
190 | 190 | return flask.jsonify(error=res['err'], status='error') | |
191 | |||
192 | |||
193 | @app.route('/footer', methods=['POST']) | ||
194 | def insertFooter(): | ||
195 | return '200 OK' | ||
196 | |||
197 | @app.route('/footer/<_id>', methods=['PUT']) | ||
198 | def 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']) | ||
208 | def insertHeader(): | ||
209 | return '200 OK' | ||
210 | |||
211 | @app.route('/header/<_id>', methods=['PUT']) | ||
212 | def 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) | ||
191 | 220 | ||
192 | 221 | ||
193 | 222 | @app.route('/menu', methods=['POST']) |
  | |||
83 | 83 | width: 100%; | |
84 | 84 | height: 300px; | |
85 | 85 | } | |
86 | #updateMenu { | ||
86 | .update-btn { | ||
87 | 87 | margin-top: 10px; | |
88 | 88 | } | |
89 | 89 | #editor-overlay { |
mouchak/static/js/editor.js
(90 / 2)
  | |||
10 | 10 | 'click #addPage': 'addPage', | |
11 | 11 | 'click .pagename .remove': 'removePage', | |
12 | 12 | 'click #menu-config': 'showMenu', | |
13 | 'click #footer-config': 'showFooterConfig' | ||
13 | 'click #footer-config': 'showFooterConfig', | ||
14 | 'click #header-config': 'showHeaderConfig' | ||
14 | 15 | }, | |
15 | 16 | initialize: function() { | |
16 | 17 | _.bindAll.apply(_, [this].concat(_.functions(this))); | |
… | … | ||
26 | 26 | //console.log(menu); | |
27 | 27 | this.menuconfig = new M.types.model.menu(menu); | |
28 | 28 | 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}); | ||
29 | 33 | }, | |
30 | 34 | render: function() { | |
31 | 35 | // append the page list | |
… | … | ||
94 | 94 | }, | |
95 | 95 | showFooterConfig: function(event) { | |
96 | 96 | event.preventDefault(); | |
97 | //this.footerconfigview.render(); | ||
97 | this.footerconfigview.render(); | ||
98 | 98 | return false; | |
99 | 99 | }, | |
100 | showHeaderConfig: function(event) { | ||
101 | event.preventDefault(); | ||
102 | this.headerconfigview.render(); | ||
103 | return false; | ||
104 | }, | ||
100 | 105 | // validate the page list with menu order list | |
101 | 106 | validate: function() { | |
102 | 107 | //TODO: validate if the menu order list matches with the list of pages | |
… | … | ||
561 | 561 | ||
562 | 562 | /* Footer Config View */ | |
563 | 563 | 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 | } | ||
564 | 642 | }); | |
565 | 643 | ||
566 | 644 | /* Notification view */ |
mouchak/static/js/models.js
(26 / 0)
  | |||
169 | 169 | }, | |
170 | 170 | }); | |
171 | 171 | ||
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 | |||
172 | 196 | //export types to the typemap | |
173 | 197 | M.types = M.types || {}; | |
174 | 198 | M.types.model = { | |
… | … | ||
201 | 201 | 'image': Image, | |
202 | 202 | 'video': Video, | |
203 | 203 | 'menu': Menu, | |
204 | 'footer': Footer, | ||
205 | 'header': Header, | ||
204 | 206 | 'rss': RSS, | |
205 | 207 | 'table': Table, | |
206 | 208 | 'plugin': Plugin, |
mouchak/static/js/mouchak.js
(11 / 5)
  | |||
38 | 38 | }, | |
39 | 39 | render: function() { | |
40 | 40 | // if custom menu is not defined, render a default menu | |
41 | console.log(this.model.toJSON()); | ||
41 | //console.log(this.model.toJSON()); | ||
42 | 42 | if(this.model.get('customMenu') === false) { | |
43 | console.log('generating default menu..'); | ||
43 | //console.log('generating default menu..'); | ||
44 | 44 | var startpage = M.site_content.menu.menuOrder[0]; | |
45 | 45 | this.$el.append(this.template({ | |
46 | 46 | brand: document.title,//brand name, | |
… | … | ||
51 | 51 | } | |
52 | 52 | // else render the custom menu | |
53 | 53 | else { | |
54 | console.log('rendering custom menu..'); | ||
54 | //console.log('rendering custom menu..'); | ||
55 | 55 | this.$el.append(this.model.get('html')); | |
56 | 56 | } | |
57 | 57 | this.$links = $('.nav li'); | |
… | … | ||
86 | 86 | if(!event) { | |
87 | 87 | var fragment = location.hash.split('/')[1]; | |
88 | 88 | //var pos = _.indexOf(M.pages.models, M.pages.where({'name': fragment})[0]); | |
89 | //console.log(fragment); | ||
89 | 90 | var pos = _.indexOf(this.model.get('menuOrder'), fragment); | |
91 | //console.log(pos); | ||
90 | 92 | if(!fragment) { | |
91 | 93 | pos = 0; | |
92 | 94 | } | |
93 | 95 | $(this.$links[pos]).addClass('active'); | |
94 | 96 | } | |
95 | 97 | else { | |
98 | //console.log(); | ||
96 | 99 | $(event.currentTarget).parent().addClass('active'); | |
97 | 100 | } | |
98 | 101 | } | |
… | … | ||
125 | 125 | else { | |
126 | 126 | $('#navigation').show(); | |
127 | 127 | } | |
128 | M.appView.navView.trigger('navclicked'); | ||
128 | //console.log('navclicked'); | ||
129 | M.appView.navView.trigger('navclicked'); | ||
129 | 130 | }, | |
130 | 131 | render404: function() { | |
131 | 132 | $('.pageview').hide(); | |
… | … | ||
184 | 184 | Backbone.history.start(); | |
185 | 185 | ||
186 | 186 | 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); | ||
188 | 189 | app_router.navigate(startpage, {trigger: true}); | |
189 | 190 | } | |
191 | M.app_router = app_router; | ||
190 | 192 | ||
191 | 193 | //M.simHeir(); | |
192 | 194 | }; |
mouchak/templates/editor.html
(30 / 1)
  | |||
22 | 22 | // initialize editor | |
23 | 23 | window.M = window.M || {}; | |
24 | 24 | M.MenuURL = function() { return "{{ url_for('insertMenu') }}"; }; | |
25 | M.FooterURL = function() { return "{{ url_for('insertFooter') }}"; }; | ||
26 | M.HeaderURL = function() { return "{{ url_for('insertHeader') }}"; }; | ||
25 | 27 | M.PageURL = function() { return "{{ url_for('insertPage') }}"; }; | |
26 | 28 | M.PluginUploadURL = function() { return "{{ url_for('uploadPlugin') }}"; }; | |
27 | 29 | M.site_content = {{ content|tojson|safe }}; | |
… | … | ||
102 | 102 | </div> | |
103 | 103 | <div class="clearfix"></div> | |
104 | 104 | <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> | ||
106 | 106 | </div> | |
107 | 107 | <div class="clearfix"></div> | |
108 | 108 | </div> | |
109 | 109 | </script> | |
110 | 110 | ||
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 | |||
111 | 137 | <script type="text/template" id="page-list-template"> | |
112 | 138 | <div id="pagelistview"> | |
113 | 139 | <h4> List of Pages </h4> | |
… | … | ||
141 | 141 | <button class="btn btn-primary" id="addPage">Add Page</button> | |
142 | 142 | <hr> | |
143 | 143 | <p> <a href="#" id="menu-config"> Site Menu </a> </p> | |
144 | <p> <a href="#" id="header-config"> Header Config </a> </p> | ||
144 | 145 | <p> <a href="#" id="footer-config"> Footer Config </a> </p> | |
145 | 146 | <p><a href="{{ url_for('index') }}"> Go to site </a></p> | |
146 | 147 | </div> |
mouchak/templates/index.html
(4 / 1)
  | |||
7 | 7 | {% block body %} | |
8 | 8 | <div class="container" id="container"> | |
9 | 9 | <div id="header"> | |
10 | <div id="header-banner"> | ||
11 | {{ content['header']['html']|safe }} | ||
12 | </div> | ||
10 | 13 | <div id="navigation"></div> | |
11 | 14 | </div> | |
12 | 15 | <div id="content-container"></div> | |
13 | <div id="footer"> {{ footer|safe }} </div> | ||
16 | <div id="footer"> {{ content['footer']['html']|safe }} </div> | ||
14 | 17 | </div> | |
15 | 18 | ||
16 | 19 | <script> |
setup.py
(2 / 2)
  | |||
10 | 10 | 'pymongo' | |
11 | 11 | ] | |
12 | 12 | ||
13 | setup(name='mouchak', | ||
13 | setup(name='Mouchak', | ||
14 | 14 | version='0.1', | |
15 | 15 | description='Web framework', | |
16 | 16 | license='BSD', | |
… | … | ||
23 | 23 | "Programming Language :: JavaScript", | |
24 | 24 | "Programming Language :: Python", | |
25 | 25 | "Programming Language :: Python :: 2.7", | |
26 | "Programming Language :: JavaScript", | ||
27 | 26 | "Topic :: Internet", | |
28 | 27 | "Topic :: Internet :: WWW/HTTP :: Site Management", | |
29 | 28 | ], | |
30 | 29 | author='Anon Ray, Arvind', | |
30 | author_email='rayanon@riseup.net', | ||
31 | 31 | url='https://git.pantoto.org/mouchak/mouchak.git', | |
32 | 32 | keywords='', | |
33 | 33 | packages=find_packages(), |