diff options
-rw-r--r-- | askbot/__init__.py | 1 | ||||
-rw-r--r-- | askbot/forms.py | 14 | ||||
-rw-r--r-- | askbot/skins/common/media/js/post.js | 76 | ||||
-rw-r--r-- | askbot/skins/common/media/js/user.js | 54 | ||||
-rw-r--r-- | askbot/skins/default/media/style/style.less | 19 | ||||
-rw-r--r-- | askbot/skins/default/templates/answer_edit.html | 2 | ||||
-rw-r--r-- | askbot/skins/default/templates/ask.html | 3 | ||||
-rw-r--r-- | askbot/skins/default/templates/embed/ask_by_widget.html | 3 | ||||
-rw-r--r-- | askbot/skins/default/templates/macros.html | 1 | ||||
-rw-r--r-- | askbot/skins/default/templates/meta/bottom_scripts.html | 1 | ||||
-rw-r--r-- | askbot/skins/default/templates/meta/tinymce_css.html (renamed from askbot/skins/default/templates/meta/tinymce.html) | 2 | ||||
-rw-r--r-- | askbot/skins/default/templates/question/javascript.html | 3 | ||||
-rw-r--r-- | askbot/skins/default/templates/question_edit.html | 2 | ||||
-rw-r--r-- | askbot/urls.py | 5 | ||||
-rw-r--r-- | askbot/views/commands.py | 33 | ||||
-rw-r--r-- | askbot_requirements.txt | 1 |
16 files changed, 181 insertions, 39 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py index 97b5ee92..3107c689 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -34,6 +34,7 @@ REQUIREMENTS = { 'pytz': 'pytz', 'tinymce': 'django-tinymce', 'longerusername': 'longerusername', + 'bs4': 'beautifulsoup4' } if platform.system() != 'Windows': diff --git a/askbot/forms.py b/askbot/forms.py index b720ad77..eb791595 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -274,13 +274,14 @@ class EditorField(forms.CharField): min_length = 10 # sentinel default value def __init__(self, *args, **kwargs): + editor_attrs = kwargs.pop('editor_attrs', {}) super(EditorField, self).__init__(*args, **kwargs) self.required = True widget_attrs = {'id': 'editor'} if askbot_settings.EDITOR_TYPE == 'markdown': self.widget = forms.Textarea(attrs=widget_attrs) elif askbot_settings.EDITOR_TYPE == 'tinymce': - self.widget = TinyMCE(attrs=widget_attrs) + self.widget = TinyMCE(attrs=widget_attrs, mce_attrs=editor_attrs) self.label = _('content') self.help_text = u'' self.initial = '' @@ -463,6 +464,17 @@ class SummaryField(forms.CharField): ) +class EditorForm(forms.Form): + """form with one field - `editor` + the field must be created dynamically, so it's added + in the __init__() function""" + + def __init__(self, editor_attrs=None): + super(EditorForm, self).__init__() + editor_attrs = editor_attrs or {} + self.fields['editor'] = EditorField(editor_attrs=editor_attrs) + + class DumpUploadForm(forms.Form): """This form handles importing data into the forum. At the moment it only diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js index 4cbb9f7e..adcb0cd6 100644 --- a/askbot/skins/common/media/js/post.js +++ b/askbot/skins/common/media/js/post.js @@ -2177,10 +2177,6 @@ WMD.prototype.setPreviewerEnabled = function(state){ } }; -WMD.prototype.setEscapeHandler = function(handler){ - this._escape_handler = handler; -}; - WMD.prototype.createDom = function(){ this._element = this.makeElement('div'); var clearfix = this.makeElement('div').addClass('clearfix'); @@ -2227,7 +2223,67 @@ WMD.prototype.getText = function(){ WMD.prototype.start = function(){ Attacklab.Util.startEditor(true, this._enabled_buttons); - this._textarea.keyup(makeKeyHandler(27, this._escape_handler)); +}; + +/** + * @constructor + */ +var TinyMCE = function(config) { + WrappedElement.call(this); + this._config = config || {}; +}; +inherits(TinyMCE, WrappedElement); + +/* 3 dummy functions to match WMD api */ +TinyMCE.prototype.setEnabledButtons = function() {}; +TinyMCE.prototype.start = function() { + this.loadEditor(); +}; +TinyMCE.prototype.setPreviewerEnabled = function() {}; + +TinyMCE.prototype.setText = function(text) { + askbot['data']['editorContent'] = text; +}; + +TinyMCE.prototype.getText = function() { + return tinyMCE.activeEditor.getContent(); +}; + +TinyMCE.prototype.loadEditor = function() { + var config = JSON.stringify(this._config); + var data = {config: config}; + var editorBox = this._element; + var me = this; + $.ajax({ + async: false, + type: 'GET', + dataType: 'json', + cache: false, + url: askbot['urls']['getEditor'], + data: data, + success: function(data) { + if (data['success']) { + editorBox.html(data['html']); + $.each(data['scripts'], function(idx, scriptData) { + var scriptElement = me.makeElement('script'); + scriptElement.attr('type', 'text/javascript'); + if (scriptData['src']) { + scriptElement.attr('src', scriptData['src']); + } + if (scriptData['contents']) { + scriptElement.html(scriptData['contents']); + } + $('head').append(scriptElement); + }); + } + } + }); +}; + +TinyMCE.prototype.createDom = function() { + var editorBox = this.makeElement('div'); + editorBox.addClass('wmd-container'); + this._element = editorBox; }; /** @@ -2379,13 +2435,19 @@ TagWikiEditor.prototype.decorate = function(element){ if (askbot['settings']['editorType'] === 'markdown') { var editor = new WMD(); } else { - var editor = new TinyMCEWrapper(); + var editor = new TinyMCE({//override defaults + mode: 'exact', + elements: 'editor', + theme_advanced_buttons1: 'bold, italic, |, link, |, numlist, bullist', + theme_advanced_buttons2: '', + plugins: '', + width: '200' + }); } if (this._enabled_editor_buttons){ editor.setEnabledButtons(this._enabled_editor_buttons); } editor.setPreviewerEnabled(this._is_previewer_enabled); - editor.setEscapeHandler(function(){me.cancelEdit()}); this._editor = editor; setupButtonEventHandlers(edit_btn, function(){ me.startActivatingEditor() }); setupButtonEventHandlers(cancel_btn, function(){me.cancelEdit()}); diff --git a/askbot/skins/common/media/js/user.js b/askbot/skins/common/media/js/user.js index 4795b7d2..2fd1195b 100644 --- a/askbot/skins/common/media/js/user.js +++ b/askbot/skins/common/media/js/user.js @@ -1,3 +1,4 @@ +//todo: refactor this into "Inbox" object or more specialized var setup_inbox = function(){ var getSelected = function(){ @@ -114,15 +115,15 @@ var setup_inbox = function(){ var rejectPostDialog = new RejectPostDialog(); rejectPostDialog.decorate($('#reject-edit-modal')); + rejectPostDialog.setSelectedEditDataReader(function(){ + return getSelected(); + }); setupButtonEventHandlers( $('#re_delete_post'), function(){ - var data = getSelected(); - if (data['id_list'].length === 0){ - return; + if (rejectPostDialog.readSelectedEditData()) { + rejectPostDialog.show(); } - rejectPostDialog.setSelectedEditData(data); - rejectPostDialog.show(); } ); @@ -136,15 +137,6 @@ var setup_inbox = function(){ $(response).append(control.getElement()); }); } - //setupButtonEventHandlers($('.re_expand'), - // function(e){ - // e.preventDefault(); - // var re_snippet = $(this).find(".re_snippet:first") - // var re_content = $(this).find(".re_content:first") - // $(re_snippet).slideToggle(); - // $(re_content).slideToggle(); - // } - //); }; var setup_badge_details_toggle = function(){ @@ -182,9 +174,19 @@ PostModerationControls.prototype.getMemoId = function() { return this._parent_element.data('responseId'); }; -PostModerationControls.prototype.removeMemo = function() { +PostModerationControls.prototype.getMemoElement = function() { var reId = this.getMemoId(); - $('#re_' + reId).remove(); + return $('#re_' + reId); +}; + +PostModerationControls.prototype.removeMemo = function() { + this.getMemoElement().remove(); +}; + +PostModerationControls.prototype.markMemo = function() { + var memo = this.getMemoElement(); + var checkbox = memo.find('input[type="checkbox"]'); + checkbox.attr('checked', true); }; PostModerationControls.prototype.addReason = function(id, title) { @@ -277,7 +279,9 @@ PostModerationControls.prototype.createDom = function() { var reasonsDlg = this._reasonsDialog; setupButtonEventHandlers(anchor, function() { - reasonsDlg.show(); + me.markMemo();//mark current post + reasonsDlg.readSelectedEditData();//read data of selected edits + reasonsDlg.show();//open the "big" dialog }); setupButtonEventHandlers(acceptBtn, function() { me.moderatePost(null, 'remove_flag'); @@ -295,9 +299,20 @@ var RejectPostDialog = function(){ this._selected_reason_id = null; this._state = null;//'select', 'preview', 'add-new' this._postModerationControls = []; + this._selectedEditDataReader = undefined; }; inherits(RejectPostDialog, WrappedElement); +RejectPostDialog.prototype.setSelectedEditDataReader = function(func) { + this._selectedEditDataReader = func; +}; + +RejectPostDialog.prototype.readSelectedEditData = function() { + var data = this._selectedEditDataReader(); + this.setSelectedEditData(data); + return data['id_list'].length > 0; +}; + RejectPostDialog.prototype.setSelectedEditData = function(data){ this._selected_edit_data = data; }; @@ -485,7 +500,10 @@ RejectPostDialog.prototype.rejectPost = function(reason_id){ url: askbot['urls']['manageInbox'], success: function(data){ if (data['success']){ - memos.remove(); + $.each(memos, function(idx, memo) { + $(memo).next('.post-moderation-controls').remove(); + $(memo).remove(); + }); me.hide(); } else { //only fatal errors here diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less index 71570ee1..8d10a4d4 100644 --- a/askbot/skins/default/media/style/style.less +++ b/askbot/skins/default/media/style/style.less @@ -1702,6 +1702,25 @@ ul#related-tags li { max-width: 600px; } +.defaultSkin table.mceLayout, +.defaultSkin table.mceLayout tr.mceFirst td { + border: none; +} +.defaultSkin table.mceLayout tr.mceLast td { + border-bottom: none; +} +.mceStatusbar { + height: 5px; + background: #fff; +} +.defaultSkin span.mce_askbot_imageuploader { + background-position: -380px 0px; +} +.defaultSkin span.mce_askbot_attachment { + background-image: url(../images/attachment.png); + background-position: 0px 0px; +} + .user-page .wmd-buttons { width: 725px; } diff --git a/askbot/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html index b38f3fff..8c3687f1 100644 --- a/askbot/skins/default/templates/answer_edit.html +++ b/askbot/skins/default/templates/answer_edit.html @@ -59,8 +59,6 @@ {% if settings.EDITOR_TYPE == 'markdown' %} <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> - {% else %} - {% include "meta/tinymce.html" %} {% endif %} <script type="text/javascript"> $().ready(function(){ diff --git a/askbot/skins/default/templates/ask.html b/askbot/skins/default/templates/ask.html index 5f072577..27434f83 100644 --- a/askbot/skins/default/templates/ask.html +++ b/askbot/skins/default/templates/ask.html @@ -19,9 +19,6 @@ {% if settings.EDITOR_TYPE == 'markdown' %} <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> - {% else %} - <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> - {% include "meta/tinymce.html" %} {% endif %} <script type='text/javascript'> var sortMethod = undefined;//need for live_search diff --git a/askbot/skins/default/templates/embed/ask_by_widget.html b/askbot/skins/default/templates/embed/ask_by_widget.html index d6438eb2..ebeec026 100644 --- a/askbot/skins/default/templates/embed/ask_by_widget.html +++ b/askbot/skins/default/templates/embed/ask_by_widget.html @@ -208,7 +208,7 @@ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> {% else %} - {% include "meta/tinymce.html" %} + {% include "meta/tinymce_css.html" %}{# todo - maybe move to form media? #} {% endif %} <script type="text/javascript" src='{{"/js/live_search_new_thread.js"|media}}'></script> @@ -222,4 +222,3 @@ }); </script> {% endblock %} - diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html index e976241c..91f2a655 100644 --- a/askbot/skins/default/templates/macros.html +++ b/askbot/skins/default/templates/macros.html @@ -432,6 +432,7 @@ for the purposes of the AJAX comment editor #} </div> </div> <script type="text/javascript"> + askbot['functions']['hideConvertLinks'](); askbot['functions']['renderPostControls']('{{comment.id}}'); </script> {% endfor %} diff --git a/askbot/skins/default/templates/meta/bottom_scripts.html b/askbot/skins/default/templates/meta/bottom_scripts.html index a36a63ec..09970468 100644 --- a/askbot/skins/default/templates/meta/bottom_scripts.html +++ b/askbot/skins/default/templates/meta/bottom_scripts.html @@ -25,6 +25,7 @@ askbot['urls']['unfollow_user'] = '/followit/unfollow/user/{{'{{'}}userId{{'}}'}}/'; askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}'; askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}'; + askbot['urls']['getEditor'] = '{% url "get_editor" %}'; </script> <script type="text/javascript" diff --git a/askbot/skins/default/templates/meta/tinymce.html b/askbot/skins/default/templates/meta/tinymce_css.html index d6b1b7b9..b6a1e798 100644 --- a/askbot/skins/default/templates/meta/tinymce.html +++ b/askbot/skins/default/templates/meta/tinymce_css.html @@ -1,4 +1,4 @@ -<style type="text/css"> +<style type="text/css">{# todo: clean up - this is also in style.less!!! #} .defaultSkin table.mceLayout, .defaultSkin table.mceLayout tr.mceFirst td { border: none; diff --git a/askbot/skins/default/templates/question/javascript.html b/askbot/skins/default/templates/question/javascript.html index 19a7269c..9e1366fb 100644 --- a/askbot/skins/default/templates/question/javascript.html +++ b/askbot/skins/default/templates/question/javascript.html @@ -32,8 +32,6 @@ {% if settings.EDITOR_TYPE == 'markdown' %} <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> -{% else %} - {% include "meta/tinymce.html" %} {% endif %} <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script> <script type='text/javascript' src='{{"/js/post.js"|media}}'></script> @@ -68,7 +66,6 @@ draftHandler.setThreadId({{ thread.id }}); draftHandler.decorate($(document)); } - askbot['functions']['hideConvertLinks'](); }); $(window).bind('hashchange', animate_hashes); diff --git a/askbot/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html index f4e4fbbf..f176b11d 100644 --- a/askbot/skins/default/templates/question_edit.html +++ b/askbot/skins/default/templates/question_edit.html @@ -64,8 +64,6 @@ {% if settings.EDITOR_TYPE == 'markdown' %} <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> - {% else %} - {% include "meta/tinymce.html" %} {% endif %} <script type="text/javascript"> {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %} diff --git a/askbot/urls.py b/askbot/urls.py index 808bf84c..c79ccb4b 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -118,6 +118,11 @@ urlpatterns = patterns('', name='get_users_info' ), url( + r'^get-editor/', + views.commands.get_editor, + name='get_editor' + ), + url( r'^%s%s$' % (_('questions/'), _('ask/')), views.writers.ask, name='ask' diff --git a/askbot/views/commands.py b/askbot/views/commands.py index a49104a0..1c3d607f 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -7,6 +7,7 @@ is not always very clean. """ import datetime import logging +from bs4 import BeautifulSoup from django.conf import settings as django_settings from django.core import exceptions #from django.core.management import call_command @@ -32,6 +33,7 @@ from askbot.utils import url_utils from askbot import mail from askbot.skins.loaders import render_into_skin, get_template from askbot.skins.loaders import render_into_skin_as_string +from askbot.skins.loaders import render_text_into_skin from askbot import const @@ -1339,3 +1341,34 @@ def moderate_group_join_request(request): else: raise Http404 +@decorators.get_only +def get_editor(request): + """returns bits of html for the tinymce editor in a dictionary with keys: + * html - the editor element + * scripts - an array of script tags + * success - True + """ + config = simplejson.loads(request.GET['config']) + form = forms.EditorForm(editor_attrs=config) + editor_html = render_text_into_skin( + '{{ form.media }} {{ form.editor }}', + {'form': form}, + request + ) + #parse out javascript and dom, and return them separately + #we need that, because js needs to be added in a special way + html_soup = BeautifulSoup(editor_html) + + parsed_scripts = list() + for script in html_soup.find_all('script'): + parsed_scripts.append({ + 'contents': script.string, + 'src': script.get('src', None) + }) + + data = { + 'html': str(html_soup.textarea), + 'scripts': parsed_scripts, + 'success': True + } + return HttpResponse(simplejson.dumps(data), mimetype='application/json') diff --git a/askbot_requirements.txt b/askbot_requirements.txt index 8771a7e6..2be12b8e 100644 --- a/askbot_requirements.txt +++ b/askbot_requirements.txt @@ -21,3 +21,4 @@ pystache==0.3.1 pytz django-tinymce longerusername +beautifulsoup4 |