Commit 4e1af813c4647126c917e339c4d879362cefa339

Ace editor for plugins

  Integrating ace editor for plugins
  One can upload plugins too. Create plugin is not yet implemented.
  All plugins have to be moved to static/user_plugins/
.gitignore
(4 / 0)
  
66/lib/
77/local/
88/include/
9
10#uploads directory
11mouchak/static/uploads/*
12mouchak/static/user_plugins/*
  
77import pymongo
88import bson
99import conf
10import os
11from werkzeug import secure_filename
1012
13PLUGIN_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__))
14 + '/static/user_plugins')
15PLUGIN_ALLOWED_EXTENSIONS = set(['js', 'css'])
16
17FILE_UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)) +
18 '/static/uploads')
19
1120app = flask.Flask(__name__)
1221
1322
4949 return {'content': content, 'menu': menu}
5050
5151
52def allowed_file(filename):
53 return '.' in filename and \
54 filename.rsplit('.', 1)[1] in PLUGIN_ALLOWED_EXTENSIONS
55
56
5257@app.errorhandler(404)
5358def pageNotFound(e):
5459 return flask.render_template('404.html'), 404
167167 flask.flash('You were logged out')
168168 return flask.redirect(flask.url_for('login'))
169169
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'])
174def 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'])
186def 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
170201@app.route('/robots.txt')
171202@app.route('/crossdomain.xml')
172203def static_from_root():
205205
206206
207207app.config.from_object(conf)
208app.config['PLUGIN_UPLOAD_FOLDER'] = PLUGIN_UPLOAD_FOLDER
208209
209210import logging,os
210211from logging import FileHandler
  
7373 left: 33%;
7474 top: 0px;
7575}
76#code-edit {
76.ace-mouchak {
7777 position: relative;
7878 top: 0;
7979 left: 0;
  
186186 split('-')[1];
187187 var content = this.model.get('content')[idx];
188188 content = new M.types.model[content.type](content);
189 console.log('model inited ', content);
189190 this.editing = true;
190191 this.edit_idx = idx;
191192 var contentview = new ContentView({model: content});
300300 'click #updateContent': 'update',
301301 'click #back' : 'back',
302302 'click #edit-type button' : 'editTypeChanged',
303 'change .contentview select': 'typeChanged'
303 'change .contentview select': 'typeChanged',
304 /* plugin events */
305 'click #upload-plugin': 'uploadPlugin'
304306 },
305307 initialize: function() {
306308 _.bindAll.apply(_, [this].concat(_.functions(this)));
361361 src: this.model.get('src'),
362362 callback: this.model.get('callback')
363363 }));
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 }
364372 }
365373 else if(type === 'map') {
366374 var template = _.template($('#map-template').html());
382382 var type = this.$select.val();
383383 //TODO: do validation on type - a list of valid models is in
384384 //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;
385389 this.model.set({'type': type});
386390 this.render();
387391 },
425425 new_attrs['data'] = data;
426426 }
427427 }
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 }
428434 this.model.set(new_attrs);
429435 M.editor.pageview.updateContent(this.model.toJSON());
430436 },
446446 },
447447 back: function() {
448448 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 });
449471 }
450472 });
451473
  
8080 data: {},
8181 callback: ""
8282 }, BaseType.prototype.defaults),
83
8384 initialize: function() {
8485 BaseType.prototype.initialize.call(this, arguments);
85
8686 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/)) {
8796 var script = document.createElement('script');
8897 var callback = this.get('callback');
8998 script.src = this.get('src');
111111 link.type = 'text/css';
112112 document.body.appendChild(link);
113113 }
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 });
114138 }
115139 });
116140
  
106106 return;
107107 },
108108 render: function(el) {
109 return;
109 this.model.exec();
110110 }
111111 });
112112
  
2121 <script>
2222 // initialize editor
2323 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') }}"; };
2627 M.site_content = {{ content|tojson|safe }};
2728 window.onload = function() {
2829 M.editor.init();
291291
292292 <script type="text/template" id="plugin-template">
293293 <div class="data">
294 <div class="row">
294 <!--div class="row">
295295 <div class="form-group col-lg-6">
296296 <div class="input-group">
297297 <span class="input-group-addon"><strong>path to file</strong></span>
299299 m-data-target="src">
300300 </div>
301301 </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 <% } %>
303318 <div class="row">
304319 <div class="form-group col-lg-6">
305320 <div class="input-group">
325325 </div>
326326 </div>
327327 </div>
328 <% if(src) { %>
329 <div class="ace-mouchak" id="plugin-edit"></div>
330 <% } %>
328331 <div class="preview"></div>
329332 </div>
330333 </script>
358358 <%= data %>
359359 </textarea>
360360 <% } else { %>
361 <div id="code-edit" m-data-target="data">
361 <div id="code-edit" class="ace-mouchak" m-data-target="data">
362362 <%= M.escapeHtml(data) %>
363363 </div>
364364 <% } %>