Commit 4e1af813c4647126c917e339c4d879362cefa339
- Diff rendering mode:
- inline
- side by side
.gitignore
(4 / 0)
  | |||
6 | 6 | /lib/ | |
7 | 7 | /local/ | |
8 | 8 | /include/ | |
9 | |||
10 | #uploads directory | ||
11 | mouchak/static/uploads/* | ||
12 | mouchak/static/user_plugins/* |
mouchak/server.py
(46 / 0)
  | |||
7 | 7 | import pymongo | |
8 | 8 | import bson | |
9 | 9 | import conf | |
10 | import os | ||
11 | from werkzeug import secure_filename | ||
10 | 12 | ||
13 | PLUGIN_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)) | ||
14 | + '/static/user_plugins') | ||
15 | PLUGIN_ALLOWED_EXTENSIONS = set(['js', 'css']) | ||
16 | |||
17 | FILE_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)) + | ||
18 | '/static/uploads') | ||
19 | |||
11 | 20 | app = flask.Flask(__name__) | |
12 | 21 | ||
13 | 22 | ||
… | … | ||
49 | 49 | return {'content': content, 'menu': menu} | |
50 | 50 | ||
51 | 51 | ||
52 | def allowed_file(filename): | ||
53 | return '.' in filename and \ | ||
54 | filename.rsplit('.', 1)[1] in PLUGIN_ALLOWED_EXTENSIONS | ||
55 | |||
56 | |||
52 | 57 | @app.errorhandler(404) | |
53 | 58 | def pageNotFound(e): | |
54 | 59 | return flask.render_template('404.html'), 404 | |
… | … | ||
167 | 167 | flask.flash('You were logged out') | |
168 | 168 | return flask.redirect(flask.url_for('login')) | |
169 | 169 | ||
170 | |||
171 | #TODO: refactor these code to classes | ||
172 | #TODO: find out if this is a good method for saving plugins.. | ||
173 | @app.route('/static/user_plugins/<filename>', methods=['POST']) | ||
174 | def savePlugin(filename): | ||
175 | if flask.request.method == 'POST': | ||
176 | if filename and allowed_file(filename): | ||
177 | data = flask.request.form['code'] | ||
178 | filename = secure_filename(filename) | ||
179 | fh = open(os.path.join(PLUGIN_UPLOAD_FOLDER + '/' + filename), 'w') | ||
180 | fh.write(data) | ||
181 | fh.close() | ||
182 | return flask.jsonify(saved = True) | ||
183 | |||
184 | #TODO: find out if this is a good method for uploading plugins.. | ||
185 | @app.route('/upload/plugin', methods=['POST']) | ||
186 | def uploadPlugin(): | ||
187 | if flask.request.method == 'POST': | ||
188 | print flask.request.files | ||
189 | file = flask.request.files['plugin-file'] | ||
190 | if file and allowed_file(file.filename): | ||
191 | filename = secure_filename(file.filename) | ||
192 | file.save(os.path.join(app.config['PLUGIN_UPLOAD_FOLDER'], | ||
193 | filename)) | ||
194 | |||
195 | #return flask.redirect(flask.url_for('uploaded_file', | ||
196 | # filename=filename)) | ||
197 | return flask.jsonify(uploaded = True, | ||
198 | path=flask.url_for('static', filename = | ||
199 | 'user_plugins/'+ filename)) | ||
200 | |||
170 | 201 | @app.route('/robots.txt') | |
171 | 202 | @app.route('/crossdomain.xml') | |
172 | 203 | def static_from_root(): | |
… | … | ||
205 | 205 | ||
206 | 206 | ||
207 | 207 | app.config.from_object(conf) | |
208 | app.config['PLUGIN_UPLOAD_FOLDER'] = PLUGIN_UPLOAD_FOLDER | ||
208 | 209 | ||
209 | 210 | import logging,os | |
210 | 211 | from logging import FileHandler |
  | |||
73 | 73 | left: 33%; | |
74 | 74 | top: 0px; | |
75 | 75 | } | |
76 | #code-edit { | ||
76 | .ace-mouchak { | ||
77 | 77 | position: relative; | |
78 | 78 | top: 0; | |
79 | 79 | left: 0; |
mouchak/static/js/editor.js
(44 / 1)
  | |||
186 | 186 | split('-')[1]; | |
187 | 187 | var content = this.model.get('content')[idx]; | |
188 | 188 | content = new M.types.model[content.type](content); | |
189 | console.log('model inited ', content); | ||
189 | 190 | this.editing = true; | |
190 | 191 | this.edit_idx = idx; | |
191 | 192 | var contentview = new ContentView({model: content}); | |
… | … | ||
300 | 300 | 'click #updateContent': 'update', | |
301 | 301 | 'click #back' : 'back', | |
302 | 302 | 'click #edit-type button' : 'editTypeChanged', | |
303 | 'change .contentview select': 'typeChanged' | ||
303 | 'change .contentview select': 'typeChanged', | ||
304 | /* plugin events */ | ||
305 | 'click #upload-plugin': 'uploadPlugin' | ||
304 | 306 | }, | |
305 | 307 | initialize: function() { | |
306 | 308 | _.bindAll.apply(_, [this].concat(_.functions(this))); | |
… | … | ||
361 | 361 | src: this.model.get('src'), | |
362 | 362 | callback: this.model.get('callback') | |
363 | 363 | })); | |
364 | if(this.model.get('src')) { | ||
365 | var plugin_type = this.model.get('plugin_type'); | ||
366 | plugin_type = (plugin_type === 'js') ? 'javascript': 'css'; | ||
367 | this.model.getCode(function(data) { | ||
368 | $('#plugin-edit').html(escapeHtml(data)); | ||
369 | M.editor.code.init('plugin-edit', plugin_type); | ||
370 | }); | ||
371 | } | ||
364 | 372 | } | |
365 | 373 | else if(type === 'map') { | |
366 | 374 | var template = _.template($('#map-template').html()); | |
… | … | ||
382 | 382 | var type = this.$select.val(); | |
383 | 383 | //TODO: do validation on type - a list of valid models is in | |
384 | 384 | //M.types.model | |
385 | var base_props = _.keys(new M.types.model.base().defaults); | ||
386 | var props = _.omit(this.model.toJSON(), base_props); | ||
387 | var new_model = new M.types.model[type](props); | ||
388 | this.model = new_model; | ||
385 | 389 | this.model.set({'type': type}); | |
386 | 390 | this.render(); | |
387 | 391 | }, | |
… | … | ||
425 | 425 | new_attrs['data'] = data; | |
426 | 426 | } | |
427 | 427 | } | |
428 | else if(this.$select.val() === 'plugin') { | ||
429 | var data = M.editor.code.save('plugin-edit'); | ||
430 | this.model.saveCode(data, function(resp) { | ||
431 | console.log('plugin saved..'); | ||
432 | }); | ||
433 | } | ||
428 | 434 | this.model.set(new_attrs); | |
429 | 435 | M.editor.pageview.updateContent(this.model.toJSON()); | |
430 | 436 | }, | |
… | … | ||
446 | 446 | }, | |
447 | 447 | back: function() { | |
448 | 448 | this.cleanUp(); | |
449 | }, | ||
450 | //upload inputed plugin file to server | ||
451 | uploadPlugin: function(event) { | ||
452 | var self = this; | ||
453 | M.editor.showOverlay(); | ||
454 | var $form = $('#plugin-upload-form')[0]; | ||
455 | console.log($form); | ||
456 | var formdata = new FormData($form); | ||
457 | console.log(formdata); | ||
458 | $.ajax({ | ||
459 | type: 'POST', | ||
460 | url: M.PluginUploadURL(), | ||
461 | data: formdata, | ||
462 | processData: false, | ||
463 | contentType: false, | ||
464 | success: function(response) { | ||
465 | self.model.set({'src': response.path}) | ||
466 | self.render(); | ||
467 | M.editor.hideOverlay(); | ||
468 | console.log(self.model.toJSON()); | ||
469 | } | ||
470 | }); | ||
449 | 471 | } | |
450 | 472 | }); | |
451 | 473 |
mouchak/static/js/models.js
(34 / 1)
  | |||
80 | 80 | data: {}, | |
81 | 81 | callback: "" | |
82 | 82 | }, BaseType.prototype.defaults), | |
83 | |||
83 | 84 | initialize: function() { | |
84 | 85 | BaseType.prototype.initialize.call(this, arguments); | |
85 | |||
86 | 86 | if(this.get('src').match(/\.js/)) { | |
87 | this.set({'plugin_type': 'js'}); | ||
88 | } | ||
89 | else if(this.get('src').match(/\.css/)) { | ||
90 | this.set({'plugin_type': 'css'}); | ||
91 | } | ||
92 | }, | ||
93 | exec: function() { | ||
94 | console.log('exec called'); | ||
95 | if(this.get('src').match(/\.js/)) { | ||
87 | 96 | var script = document.createElement('script'); | |
88 | 97 | var callback = this.get('callback'); | |
89 | 98 | script.src = this.get('src'); | |
… | … | ||
111 | 111 | link.type = 'text/css'; | |
112 | 112 | document.body.appendChild(link); | |
113 | 113 | } | |
114 | }, | ||
115 | // get the source code of the plugin from the src path | ||
116 | getCode: function(cb) { | ||
117 | var self = this; | ||
118 | $.ajax({ | ||
119 | type: 'GET', | ||
120 | url: self.get('src'), | ||
121 | cache: false, | ||
122 | success: function(data) { | ||
123 | cb(data); | ||
124 | } | ||
125 | }); | ||
126 | }, | ||
127 | // save the source code of the plugin to the src path | ||
128 | saveCode: function(data, cb) { | ||
129 | var self = this; | ||
130 | $.ajax({ | ||
131 | type: 'POST', | ||
132 | url: this.get('src'), | ||
133 | data: {code: data}, | ||
134 | success: function(data) { | ||
135 | cb(data); | ||
136 | } | ||
137 | }); | ||
114 | 138 | } | |
115 | 139 | }); | |
116 | 140 |
mouchak/static/js/views.js
(1 / 1)
  | |||
106 | 106 | return; | |
107 | 107 | }, | |
108 | 108 | render: function(el) { | |
109 | return; | ||
109 | this.model.exec(); | ||
110 | 110 | } | |
111 | 111 | }); | |
112 | 112 |
mouchak/templates/editor.html
(24 / 5)
  | |||
21 | 21 | <script> | |
22 | 22 | // initialize editor | |
23 | 23 | window.M = window.M || {}; | |
24 | M.MenuURL = function() { return "{{ url_for('insertMenu') }}"}; | ||
25 | M.PageURL = function() { return "{{ url_for('insertPage') }}"}; | ||
24 | M.MenuURL = function() { return "{{ url_for('insertMenu') }}"; }; | ||
25 | M.PageURL = function() { return "{{ url_for('insertPage') }}"; }; | ||
26 | M.PluginUploadURL = function() { return "{{ url_for('uploadPlugin') }}"; }; | ||
26 | 27 | M.site_content = {{ content|tojson|safe }}; | |
27 | 28 | window.onload = function() { | |
28 | 29 | M.editor.init(); | |
… | … | ||
291 | 291 | ||
292 | 292 | <script type="text/template" id="plugin-template"> | |
293 | 293 | <div class="data"> | |
294 | <div class="row"> | ||
294 | <!--div class="row"> | ||
295 | 295 | <div class="form-group col-lg-6"> | |
296 | 296 | <div class="input-group"> | |
297 | 297 | <span class="input-group-addon"><strong>path to file</strong></span> | |
… | … | ||
299 | 299 | m-data-target="src"> | |
300 | 300 | </div> | |
301 | 301 | </div> | |
302 | </div> | ||
302 | </div--> | ||
303 | <% if(!src) { %> | ||
304 | <div class="row"> | ||
305 | <div class="form-group col-lg-6"> | ||
306 | <form id="plugin-upload-form" action="" method="post" enctype="multipart/form-data"> | ||
307 | <input type="file" name="plugin-file" id="select-plugin"> | ||
308 | <input type="button" id="upload-plugin" class="btn btn-info" value="Upload Plugin"> | ||
309 | </form> | ||
310 | </div> | ||
311 | </div> | ||
312 | <div class="row"> | ||
313 | <div class="form-group col-lg-6"> | ||
314 | <button type="button" class="btn btn-info" id="create-plugin">Create a new plugin</button> | ||
315 | </div> | ||
316 | </div> | ||
317 | <% } %> | ||
303 | 318 | <div class="row"> | |
304 | 319 | <div class="form-group col-lg-6"> | |
305 | 320 | <div class="input-group"> | |
… | … | ||
325 | 325 | </div> | |
326 | 326 | </div> | |
327 | 327 | </div> | |
328 | <% if(src) { %> | ||
329 | <div class="ace-mouchak" id="plugin-edit"></div> | ||
330 | <% } %> | ||
328 | 331 | <div class="preview"></div> | |
329 | 332 | </div> | |
330 | 333 | </script> | |
… | … | ||
358 | 358 | <%= data %> | |
359 | 359 | </textarea> | |
360 | 360 | <% } else { %> | |
361 | <div id="code-edit" m-data-target="data"> | ||
361 | <div id="code-edit" class="ace-mouchak" m-data-target="data"> | ||
362 | 362 | <%= M.escapeHtml(data) %> | |
363 | 363 | </div> | |
364 | 364 | <% } %> |