summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2013-04-07 04:40:04 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2013-04-07 04:40:04 -0400
commitb03f881b11204b7e0fe323dd9148085ef0dfa35d (patch)
tree45fc9053dc3b7aa2ba5888b3ab26bfb22fc2b09e
parent580dce30624e7af950159e3f74f9181506b57a5d (diff)
downloadaskbot-b03f881b11204b7e0fe323dd9148085ef0dfa35d.tar.gz
askbot-b03f881b11204b7e0fe323dd9148085ef0dfa35d.tar.bz2
askbot-b03f881b11204b7e0fe323dd9148085ef0dfa35d.zip
allowed to choose plain text or rich text editor for the comments
-rw-r--r--askbot/conf/forum_data_rules.py23
-rw-r--r--askbot/doc/source/changelog.rst2
-rw-r--r--askbot/media/js/post.js88
-rw-r--r--askbot/media/js/utils.js32
-rw-r--r--askbot/media/js/wmd/wmd.css67
-rw-r--r--askbot/media/js/wmd/wmd.js142
-rw-r--r--askbot/media/style/style.less13
-rw-r--r--askbot/models/post.py40
-rw-r--r--askbot/templates/meta/bottom_scripts.html10
-rw-r--r--askbot/templates/meta/html_head_javascript.html9
-rw-r--r--askbot/utils/markup.py17
-rw-r--r--askbot/views/writers.py4
12 files changed, 282 insertions, 165 deletions
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index 524ab16a..b88d551e 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -28,6 +28,21 @@ settings.register(
)
)
+COMMENTS_EDITOR_CHOICES = (
+ ('plain-text', 'Plain text editor'),
+ ('rich-text', 'Same editor as for questions and answers')
+)
+
+settings.register(
+ livesettings.StringValue(
+ FORUM_DATA_RULES,
+ 'COMMENTS_EDITOR_TYPE',
+ default='plain-text',
+ choices=COMMENTS_EDITOR_CHOICES,
+ description=_('Editor for the comments')
+ )
+)
+
settings.register(
livesettings.BooleanValue(
FORUM_DATA_RULES,
@@ -315,8 +330,12 @@ settings.register(
livesettings.BooleanValue(
FORUM_DATA_RULES,
'SAVE_COMMENT_ON_ENTER',
- default = True,
- description = _('Save comment by pressing <Enter> key')
+ default=False,
+ description=_('Save comment by pressing <Enter> key'),
+ help_text=_(
+ 'This may be useful when only one-line comments '
+ 'are desired. Will not work with TinyMCE editor.'
+ )
)
)
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index f59138c5..90ec1257 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -3,6 +3,8 @@ Changes in Askbot
Development version
-------------------
+* Added possibility to choose editor for comments: plain text, or same as
+ editor used for the questions or answers: WMD or TinyMCE.
* Added a placeholder template for the custom javascript on the question page
* Allowed to disable the big "ask" button.
* Some support for the media compression (Tyler Mandry)
diff --git a/askbot/media/js/post.js b/askbot/media/js/post.js
index 8386ce5b..02aa02d6 100644
--- a/askbot/media/js/post.js
+++ b/askbot/media/js/post.js
@@ -1433,15 +1433,27 @@ EditCommentForm.prototype.setWaitingStatus = function(isWaiting) {
this._editor.getElement().hide();
this._submit_btn.hide();
this._cancel_btn.hide();
+ this._minorEditBox.hide();
+ this._element.hide();
} else {
+ this._element.show();
this._editor.getElement().show();
this._submit_btn.show();
this._cancel_btn.show();
+ this._minorEditBox.show();
}
};
-EditCommentForm.prototype.startEditor = function() {
- var editorId = 'comment-editor-' + getNewInt();
+EditCommentForm.prototype.getEditorType = function() {
+ if (askbot['settings']['commentsEditorType'] === 'rich-text') {
+ return askbot['settings']['editorType'];
+ } else {
+ return 'plain-text';
+ }
+};
+
+EditCommentForm.prototype.startTinyMCEEditor = function() {
+ var editorId = this.makeId('comment-editor');
var opts = {
mode: 'exact',
content_css: mediaUrl('media/style/tinymce/comments-content.css'),
@@ -1460,23 +1472,49 @@ EditCommentForm.prototype.startEditor = function() {
var editor = new TinyMCE(opts);
editor.setId(editorId);
editor.setText(this._text);
- //@todo: remove global variable maxCommentLength
this._editorBox.prepend(editor.getElement());
editor.start();
- editor.focus();
this._editor = editor;
+};
- return;
+EditCommentForm.prototype.startWMDEditor = function() {
+ var editor = new WMD();
+ editor.setEnabledButtons('bold italic link code ol ul');
+ editor.setPreviewerEnabled(false);
+ editor.setText(this._text);
+ this._editorBox.prepend(editor.getElement());//attach DOM before start
+ editor.start();//have to start after attaching DOM
+ this._editor = editor;
+};
+
+EditCommentForm.prototype.startSimpleEditor = function() {
+ this._editor = new SimpleEditor();
+ this._editorBox.prepend(this._editor.getElement());
+};
- //todo: make this work for tinymce
+EditCommentForm.prototype.startEditor = function() {
+ var editorType = this.getEditorType();
+ if (editorType === 'tinymce') {
+ this.startTinyMCEEditor();
+ //@todo: implement save on enter and character counter in tinyMCE
+ return;
+ } else if (editorType === 'markdown') {
+ this.startWMDEditor();
+ } else {
+ this.startSimpleEditor();
+ }
+
+ //code below is common to SimpleEditor and WMD
+ var editorElement = this._editor.getElement();
var updateCounter = this.getCounterUpdater();
var escapeHandler = makeKeyHandler(27, this.getCancelHandler());
-
//todo: try this on the div
- editor.getElement().blur(updateCounter)
- .focus(updateCounter)
- .keyup(updateCounter)
- .keyup(escapeHandler);
+ var editor = this._editor;
+ //this should be set on the textarea!
+ editorElement.blur(updateCounter);
+ editorElement.focus(updateCounter);
+ editorElement.keyup(updateCounter)
+ editorElement.keyup(escapeHandler);
if (askbot['settings']['saveCommentOnEnter']){
var save_handler = makeKeyHandler(13, this.getSaveHandler());
@@ -1513,8 +1551,8 @@ EditCommentForm.prototype.attachTo = function(comment, mode){
this.enableForm();
this.startEditor();
this._editor.setText(this._text);
- //this._editor.focus();
- //this._editor.putCursorAtEnd();
+ this._editor.focus();
+ this._editor.putCursorAtEnd();
setupButtonEventHandlers(this._submit_btn, this.getSaveHandler());
setupButtonEventHandlers(this._cancel_btn, this.getCancelHandler());
};
@@ -1556,6 +1594,7 @@ EditCommentForm.prototype.getCounterUpdater = function(){
}
counter.html(feedback);
counter.css('color', color);
+ return true;
};
return handler;
};
@@ -1573,8 +1612,7 @@ EditCommentForm.prototype.canCancel = function(){
var ctext = this._editor.getText();
if ($.trim(ctext) == $.trim(this._text)){
return true;
- }
- else if (this.confirmAbandon()){
+ } else if (this.confirmAbandon()){
return true;
}
this._editor.focus();
@@ -1718,7 +1756,8 @@ EditCommentForm.prototype.getSaveHandler = function(){
var timestamp = commentData['comment_added_at'] || gettext('just now');
var userName = commentData['user_display_name'] || askbot['data']['userName'];
me._comment.setContent({
- 'html': text,
+ 'html': editor.getHtml(),
+ 'text': text,
'user_display_name': userName,
'comment_added_at': timestamp
});
@@ -2426,6 +2465,10 @@ SimpleEditor.prototype.getText = function() {
return $.trim(this._textarea.val());
};
+SimpleEditor.prototype.getHtml = function() {
+ return '<div class="transient-comment">' + this.getText() + '</div>';
+};
+
SimpleEditor.prototype.setText = function(text) {
this._text = text;
if (this._textarea) {
@@ -2442,6 +2485,7 @@ SimpleEditor.prototype.createDom = function() {
this._element = this.makeElement('div');
var textarea = this.makeElement('textarea');
this._element.append(textarea);
+ this._textarea = textarea;
if (this._text) {
textarea.val(this._text);
};
@@ -2466,6 +2510,8 @@ var WMD = function(){
};
inherits(WMD, SimpleEditor);
+//@todo: implement getHtml method that runs text through showdown renderer
+
WMD.prototype.setEnabledButtons = function(buttons){
this._enabled_buttons = buttons;
};
@@ -2487,12 +2533,12 @@ WMD.prototype.createDom = function(){
this._element.append(wmd_container);
var wmd_buttons = this.makeElement('div')
- .attr('id', 'wmd-button-bar')
+ .attr('id', this.makeId('wmd-button-bar'))
.addClass('wmd-panel');
wmd_container.append(wmd_buttons);
var editor = this.makeElement('textarea')
- .attr('id', 'editor');
+ .attr('id', this.makeId('editor'));
wmd_container.append(editor);
this._textarea = editor;
@@ -2501,7 +2547,7 @@ WMD.prototype.createDom = function(){
}
var previewer = this.makeElement('div')
- .attr('id', 'previewer')
+ .attr('id', this.makeId('previewer'))
.addClass('wmd-preview');
wmd_container.append(previewer);
this._previewer = previewer;
@@ -2511,7 +2557,7 @@ WMD.prototype.createDom = function(){
};
WMD.prototype.start = function(){
- Attacklab.Util.startEditor(true, this._enabled_buttons);
+ Attacklab.Util.startEditor(true, this._enabled_buttons, this.getIdSeed());
};
/**
@@ -2577,6 +2623,8 @@ TinyMCE.prototype.getText = function() {
return tinyMCE.activeEditor.getContent();
};
+TinyMCE.prototype.getHtml = TinyMCE.prototype.getText;
+
TinyMCE.prototype.isLoaded = function() {
return (tinymce.get(this._id) !== undefined);
};
diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js
index a26c1ec9..0c056f44 100644
--- a/askbot/media/js/utils.js
+++ b/askbot/media/js/utils.js
@@ -28,7 +28,16 @@ var animateHashes = function(){
}
};
-var getNewInt = function() {
+/**
+ * @param {string} id_token - any token
+ * @param {string} unique_seed - the unique part
+ * @returns {string} unique id that can be used in DOM
+ */
+var askbotMakeId = function(id_token, unique_seed) {
+ return id_token + '-' + unique_seed;
+};
+
+var getNewUniqueInt = function() {
var num = askbot['data']['uniqueInt'] || 0;
num = num + 1;
askbot['data']['uniqueInt'] = num;
@@ -322,12 +331,33 @@ var inherits = function(childCtor, parentCtor) {
var WrappedElement = function(){
this._element = null;
this._in_document = false;
+ this._idSeed = null;
};
/* note that we do not call inherits() here
* See TippedInput as an example of a subclass
*/
/**
+ * returns a unique integer for any instance of WrappedElement
+ * which can be used to construct a unique id for use in the DOM
+ * @return {string}
+ */
+WrappedElement.prototype.getIdSeed = function() {
+ var seed = this._idSeed || parseInt(getNewUniqueInt());
+ this._idSeed = seed;
+ return seed;
+};
+
+/**
+ * returns unique ide based on the prefix and the id seed
+ * @param {string} prefix
+ * @return {string}
+ */
+WrappedElement.prototype.makeId = function(prefix) {
+ return askbotMakeId(prefix, this.getIdSeed());
+};
+
+/**
* notice that we use ObjCls.prototype.someMethod = function()
* notation - as we use Javascript's prototypal inheritance
* explicitly. The point of this is to be able to eventually
diff --git a/askbot/media/js/wmd/wmd.css b/askbot/media/js/wmd/wmd.css
index 678d70f3..eeb6adec 100644
--- a/askbot/media/js/wmd/wmd.css
+++ b/askbot/media/js/wmd/wmd.css
@@ -3,46 +3,39 @@
background-color: White
}
*/
-.wmd-panel
-{
+.wmd-panel {
}
-#wmd-button-bar
-{
+.wmd-button-bar {
background: url(images/editor-toolbar-background.png) repeat-x bottom;
- height: 30px;
+ height: 25px;
border: 0;
display: block;
}
-#wmd-input
-{
+.wmd-input {
height: 500px;
background-color: Gainsboro;
border: 1px solid DarkGray;
margin-top: -20px;
}
-#wmd-preview
-{
- background-color: LightSkyBlue;
+.wmd-preview {
+ background-color: #f5f5f5;
}
-#wmd-output
-{
+.wmd-output {
background-color: Pink;
}
-#wmd-button-row
-{
+.wmd-button-row {
position: relative;
- margin: 10px 2px 0 2px;
+ margin: 5px 2px;
padding: 0px;
height: 20px;
}
-.wmd-spacer
-{
+.wmd-spacer {
width: 1px;
height: 20px;
margin-left: 2px;
@@ -53,8 +46,7 @@
list-style: none;
}
-.wmd-button
-{
+.wmd-button {
width: 20px;
height: 20px;
margin-left: 5px;
@@ -68,8 +60,7 @@
list-style: none;
}
-.wmd-button > a
-{
+.wmd-button > a {
width: 20px;
height: 20px;
margin-left: 5px;
@@ -81,23 +72,23 @@
/* sprite button slicing style information */
-#wmd-button-bar #wmd-bold-button {left: 0px; background-position: 0px 0;}
-#wmd-button-bar #wmd-italic-button {left: 25px; background-position: -20px 0;}
-#wmd-button-bar #wmd-spacer1 {left: 50px;}
-#wmd-button-bar #wmd-link-button {left: 75px; background-position: -40px 0;}
-#wmd-button-bar #wmd-quote-button {left: 100px; background-position: -60px 0;}
-#wmd-button-bar #wmd-code-button {left: 125px; background-position: -80px 0;}
-#wmd-button-bar #wmd-image-button {left: 150px; background-position: -100px 0;}
-#wmd-button-bar #wmd-attachment-button {left: 175px; background-position: -120px 0;}
-#wmd-button-bar #wmd-spacer2 {left: 200px;}
-#wmd-button-bar #wmd-olist-button {left: 225px; background-position: -140px 0;}
-#wmd-button-bar #wmd-ulist-button {left: 250px; background-position: -160px 0;}
-#wmd-button-bar #wmd-heading-button {left: 275px; background-position: -180px 0;}
-#wmd-button-bar #wmd-hr-button {left: 300px; background-position: -200px 0;}
-#wmd-button-bar #wmd-spacer3 {left: 325px;}
-#wmd-button-bar #wmd-undo-button {left: 350px; background-position: -220px 0;}
-#wmd-button-bar #wmd-redo-button {left: 375px; background-position: -240px 0;}
-#wmd-button-bar #wmd-help-button {right: 0px; background-position: -260px 0;}
+.wmd-button-bar .wmd-bold-button {left: 0px; background-position: 0px 0;}
+.wmd-button-bar .wmd-italic-button {left: 25px; background-position: -20px 0;}
+.wmd-button-bar .wmd-spacer1 {left: 50px;}
+.wmd-button-bar .wmd-link-button {left: 75px; background-position: -40px 0;}
+.wmd-button-bar .wmd-quote-button {left: 100px; background-position: -60px 0;}
+.wmd-button-bar .wmd-code-button {left: 125px; background-position: -80px 0;}
+.wmd-button-bar .wmd-image-button {left: 150px; background-position: -100px 0;}
+.wmd-button-bar .wmd-attachment-button {left: 175px; background-position: -120px 0;}
+.wmd-button-bar .wmd-spacer2 {left: 200px;}
+.wmd-button-bar .wmd-olist-button {left: 225px; background-position: -140px 0;}
+.wmd-button-bar .wmd-ulist-button {left: 250px; background-position: -160px 0;}
+.wmd-button-bar .wmd-heading-button {left: 275px; background-position: -180px 0;}
+.wmd-button-bar .wmd-hr-button {left: 300px; background-position: -200px 0;}
+.wmd-button-bar .wmd-spacer3 {left: 325px;}
+.wmd-button-bar .wmd-undo-button {left: 350px; background-position: -220px 0;}
+.wmd-button-bar .wmd-redo-button {left: 375px; background-position: -240px 0;}
+.wmd-button-bar .wmd-help-button {right: 0px; background-position: -260px 0;}
.wmd-prompt-background
diff --git a/askbot/media/js/wmd/wmd.js b/askbot/media/js/wmd/wmd.js
index ddbc91ed..b3ed3f38 100644
--- a/askbot/media/js/wmd/wmd.js
+++ b/askbot/media/js/wmd/wmd.js
@@ -79,10 +79,10 @@ Attacklab.wmdBase = function(){
// A collection of the important regions on the page.
// Cached so we don't have to keep traversing the DOM.
wmd.PanelCollection = function(){
- this.buttonBar = doc.getElementById("wmd-button-bar");
- this.preview = doc.getElementById("previewer");
- this.output = doc.getElementById("wmd-output");
- this.input = doc.getElementById("editor");
+ this.buttonBar = doc.getElementById(util.makeId("wmd-button-bar"));
+ this.preview = doc.getElementById(util.makeId("previewer"));
+ this.output = doc.getElementById(util.makeId("wmd-output"));
+ this.input = doc.getElementById(util.makeId("editor"));
};
// This PanelCollection object can't be filled until after the page
@@ -195,7 +195,7 @@ Attacklab.wmdBase = function(){
var imgPath = imageDirectory + img;
var elem = doc.createElement("img");
- elem.className = "wmd-button";
+ elem.className = "wmd-button wmd-image-button";
elem.src = imgPath;
return elem;
@@ -276,24 +276,21 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
// so we make the whole window transparent.
//
// Is this necessary on modern konqueror browsers?
- if (global.isKonqueror){
+ if (global.isKonqueror) {
style.backgroundColor = "transparent";
- }
- else if (global.isIE){
+ } else if (global.isIE) {
style.filter = "alpha(opacity=50)";
- }
- else {
+ } else {
style.opacity = "0.5";
}
var pageSize = position.getPageSize();
style.height = pageSize[1] + "px";
- if(global.isIE){
+ if(global.isIE) {
style.left = doc.documentElement.scrollLeft;
style.width = doc.documentElement.clientWidth;
- }
- else {
+ } else {
style.left = "0";
style.width = "100%";
}
@@ -333,7 +330,7 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
// The input text box
input = doc.createElement("input");
if(dialogType == 'image' || dialogType == 'file'){
- input.id = "image-url";
+ input.id = util.makeId("image-url");
}
input.type = "text";
if (dialogType == 'file'){
@@ -932,8 +929,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
var setUndoRedoButtonStates = function(){
if(undoMgr){
- setupButton(document.getElementById("wmd-undo-button"), undoMgr.canUndo());
- setupButton(document.getElementById("wmd-redo-button"), undoMgr.canRedo());
+ setupButton(document.getElementById(util.makeId("wmd-undo-button")), undoMgr.canUndo());
+ setupButton(document.getElementById(util.makeId("wmd-redo-button")), undoMgr.canRedo());
}
};
@@ -981,19 +978,21 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
};
var makeSpritedButtonRow = function(){
- var buttonBar = document.getElementById("wmd-button-bar");
+ var buttonBar = document.getElementById(util.makeId("wmd-button-bar"));
+ buttonBar.className = 'wmd-button-bar';
var normalYShift = "0px";
var disabledYShift = "-20px";
var highlightYShift = "-40px";
var buttonRow = document.createElement("ul");
- buttonRow.id = "wmd-button-row";
+ buttonRow.className = 'wmd-button-row';
+ buttonRow.id = util.makeId("wmd-button-row");
buttonRow = buttonBar.appendChild(buttonRow);
if (isButtonUsed('bold')){
var boldButton = document.createElement("li");
- boldButton.className = "wmd-button";
- boldButton.id = "wmd-bold-button";
+ boldButton.className = "wmd-button wmd-bold-button";
+ boldButton.id = util.makeId("wmd-bold-button");
boldButton.title = toolbar_strong_label;
boldButton.XShift = "0px";
boldButton.textOp = command.doBold;
@@ -1003,8 +1002,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('italic')){
var italicButton = document.createElement("li");
- italicButton.className = "wmd-button";
- italicButton.id = "wmd-italic-button";
+ italicButton.className = "wmd-button wmd-italic-button";
+ italicButton.id = util.makeId("wmd-italic-button");
italicButton.title = toolbar_emphasis_label;
italicButton.XShift = "-20px";
italicButton.textOp = command.doItalic;
@@ -1020,15 +1019,15 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
isButtonUsed('attachment')
) {
var spacer1 = document.createElement("li");
- spacer1.className = "wmd-spacer";
- spacer1.id = "wmd-spacer1";
+ spacer1.className = "wmd-spacer wmd-spacer1";
+ spacer1.id = util.makeId("wmd-spacer1");
buttonRow.appendChild(spacer1);
}
if (isButtonUsed('link')){
var linkButton = document.createElement("li");
- linkButton.className = "wmd-button";
- linkButton.id = "wmd-link-button";
+ linkButton.className = "wmd-button wmd-link-button";
+ linkButton.id = util.makeId("wmd-link-button");
linkButton.title = toolbar_hyperlink_label;
linkButton.XShift = "-40px";
linkButton.textOp = function(chunk, postProcessing){
@@ -1040,8 +1039,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('blockquote')){
var quoteButton = document.createElement("li");
- quoteButton.className = "wmd-button";
- quoteButton.id = "wmd-quote-button";
+ quoteButton.className = "wmd-button wmd-quote-button";
+ quoteButton.id = util.makeId("wmd-quote-button");
quoteButton.title = toolbar_blockquote_label;
quoteButton.XShift = "-60px";
quoteButton.textOp = command.doBlockquote;
@@ -1051,8 +1050,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('code')){
var codeButton = document.createElement("li");
- codeButton.className = "wmd-button";
- codeButton.id = "wmd-code-button";
+ codeButton.className = "wmd-button wmd-code-button";
+ codeButton.id = util.makeId("wmd-code-button");
codeButton.title = toolbar_code_label;
codeButton.XShift = "-80px";
codeButton.textOp = command.doCode;
@@ -1062,8 +1061,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('image')){
var imageButton = document.createElement("li");
- imageButton.className = "wmd-button";
- imageButton.id = "wmd-image-button";
+ imageButton.className = "wmd-button wmd-image-button";
+ imageButton.id = util.makeId("wmd-image-button");
imageButton.title = toolbar_image_label;
imageButton.XShift = "-100px";
imageButton.textOp = function(chunk, postProcessing){
@@ -1075,8 +1074,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('attachment')){
var attachmentButton = document.createElement("li");
- attachmentButton.className = "wmd-button";
- attachmentButton.id = "wmd-attachment-button";
+ attachmentButton.className = "wmd-button wmd-attachment-button";
+ attachmentButton.id = util.makeId("wmd-attachment-button");
attachmentButton.title = toolbar_attachment_label;
attachmentButton.XShift = "-120px";
attachmentButton.textOp = function(chunk, postProcessing){
@@ -1093,15 +1092,15 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
isButtonUsed('hr')
) {
var spacer2 = document.createElement("li");
- spacer2.className = "wmd-spacer";
- spacer2.id = "wmd-spacer2";
+ spacer2.className = "wmd-spacer wmd-spacer2";
+ spacer2.id = util.makeId("wmd-spacer2");
buttonRow.appendChild(spacer2);
}
if (isButtonUsed('ol')) {
var olistButton = document.createElement("li");
- olistButton.className = "wmd-button";
- olistButton.id = "wmd-olist-button";
+ olistButton.className = "wmd-button wmd-olist-button";
+ olistButton.id = util.makeId("wmd-olist-button");
olistButton.title = toolbar_numbered_label;
olistButton.XShift = "-140px";
olistButton.textOp = function(chunk, postProcessing){
@@ -1113,8 +1112,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('ul')) {
var ulistButton = document.createElement("li");
- ulistButton.className = "wmd-button";
- ulistButton.id = "wmd-ulist-button";
+ ulistButton.className = "wmd-button wmd-ulist-button";
+ ulistButton.id = util.makeId("wmd-ulist-button");
ulistButton.title = toolbar_bulleted_label;
ulistButton.XShift = "-160px";
ulistButton.textOp = function(chunk, postProcessing){
@@ -1126,8 +1125,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('heading')) {
var headingButton = document.createElement("li");
- headingButton.className = "wmd-button";
- headingButton.id = "wmd-heading-button";
+ headingButton.className = "wmd-button wmd-heading-button";
+ headingButton.id = util.makeId("wmd-heading-button");
headingButton.title = toolbar_heading_label;
headingButton.XShift = "-180px";
headingButton.textOp = command.doHeading;
@@ -1137,8 +1136,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('hr')) {
var hrButton = document.createElement("li");
- hrButton.className = "wmd-button";
- hrButton.id = "wmd-hr-button";
+ hrButton.className = "wmd-button wmd-hr-button";
+ hrButton.id = util.makeId("wmd-hr-button");
hrButton.title = toolbar_horizontal_label;
hrButton.XShift = "-200px";
hrButton.textOp = command.doHorizontalRule;
@@ -1148,13 +1147,13 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
if (isButtonUsed('undo')){
var spacer3 = document.createElement("li");
- spacer3.className = "wmd-spacer";
- spacer3.id = "wmd-spacer3";
+ spacer3.className = "wmd-spacer wmd-spacer3";
+ spacer3.id = util.makeId("wmd-spacer3");
buttonRow.appendChild(spacer3);
var undoButton = document.createElement("li");
- undoButton.className = "wmd-button";
- undoButton.id = "wmd-undo-button";
+ undoButton.className = "wmd-button wmd-undo-button";
+ undoButton.id = util.makeId("wmd-undo-button");
undoButton.title = toolbar_undo_label;
undoButton.XShift = "-220px";
undoButton.execute = function(manager){
@@ -1164,8 +1163,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
buttonRow.appendChild(undoButton);
var redoButton = document.createElement("li");
- redoButton.className = "wmd-button";
- redoButton.id = "wmd-redo-button";
+ redoButton.className = "wmd-button wmd-redo-button";
+ redoButton.id = util.makeId("wmd-redo-button");
redoButton.title = toolbar_redo_label;
if (/win/.test(nav.platform.toLowerCase())) {
redoButton.title = toolbar_redo_label;
@@ -1184,8 +1183,8 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
}
/*
var helpButton = document.createElement("li");
- helpButton.className = "wmd-button";
- helpButton.id = "wmd-help-button";
+ helpButton.className = "wmd-button wmd-help-button";
+ helpButton.id = util.makeId("wmd-help-button");
helpButton.XShift = "-240px";
helpButton.isHelp = true;
@@ -1239,44 +1238,44 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
switch(keyCodeStr) {
case "b":
- doClick(document.getElementById("wmd-bold-button"));
+ doClick(document.getElementById(util.makeId("wmd-bold-button")));
break;
case "i":
- doClick(document.getElementById("wmd-italic-button"));
+ doClick(document.getElementById(util.makeId("wmd-italic-button")));
break;
case "l":
- doClick(document.getElementById("wmd-link-button"));
+ doClick(document.getElementById(util.makeId("wmd-link-button")));
break;
case ".":
- doClick(document.getElementById("wmd-quote-button"));
+ doClick(document.getElementById(util.makeId("wmd-quote-button")));
break;
case "k":
- doClick(document.getElementById("wmd-code-button"));
+ doClick(document.getElementById(util.makeId("wmd-code-button")));
break;
case "g":
- doClick(document.getElementById("wmd-image-button"));
+ doClick(document.getElementById(util.makeId("wmd-image-button")));
break;
case "o":
- doClick(document.getElementById("wmd-olist-button"));
+ doClick(document.getElementById(util.makeId("wmd-olist-button")));
break;
case "u":
- doClick(document.getElementById("wmd-ulist-button"));
+ doClick(document.getElementById(util.makeId("wmd-ulist-button")));
break;
case "h":
- doClick(document.getElementById("wmd-heading-button"));
+ doClick(document.getElementById(util.makeId("wmd-heading-button")));
break;
case "r":
- doClick(document.getElementById("wmd-hr-button"));
+ doClick(document.getElementById(util.makeId("wmd-hr-button")));
break;
case "y":
- doClick(document.getElementById("wmd-redo-button"));
+ doClick(document.getElementById(util.makeId("wmd-redo-button")));
break;
case "z":
if(key.shiftKey) {
- doClick(document.getElementById("wmd-redo-button"));
+ doClick(document.getElementById(util.makeId("wmd-redo-button")));
}
else {
- doClick(document.getElementById("wmd-undo-button"));
+ doClick(document.getElementById(util.makeId("wmd-undo-button")));
}
break;
default:
@@ -1877,8 +1876,17 @@ util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
wmd.wmd.editor = wmd.editor;
wmd.wmd.previewManager = wmd.previewManager;
};
+
+ util.makeId = function(idToken) {
+ if (wmd.wmd_env['idSeed']) {
+ return askbotMakeId(idToken, wmd.wmd_env['idSeed']);
+ }
+ return idToken;
+ };
- util.startEditor = function(start_now, buttons){
+ util.startEditor = function(start_now, buttons, idSeed){
+
+ wmd.wmd_env['idSeed'] = idSeed;
if (wmd.wmd_env.autostart === false) {
util.makeAPI();
@@ -2473,7 +2481,7 @@ Attacklab.account_options = {};
Attacklab.wmd_defaults = {version:1, output:"Markdown", lineLength:40, delayLoad:false};
//@todo: this needs to be moved out of the wmd.js as we have askbot-specific code here
-if(!Attacklab.wmd && askbot['data']['editorType'] === 'markdown') {
+if(!Attacklab.wmd && askbot['settings']['editorType'] === 'markdown') {
Attacklab.wmd = function() {
Attacklab.loadEnv = function() {
var mergeEnv = function(env) {
diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less
index 3c50090e..55b99ddb 100644
--- a/askbot/media/style/style.less
+++ b/askbot/media/style/style.less
@@ -2427,15 +2427,22 @@ ul#related-tags li {
textarea {
box-sizing: border-box;
border: #cce6ec 3px solid;
+ color: #666;
font-family: @body-font;
font-size: 13px;
height: 54px;
line-height: 1.3;
- margin: -1px 0 7px 1px;
+ margin: -1px 0 0 1px;
outline: none;
overflow:auto;
- padding: 0px 19px 2px 3px;
- width:100%;
+ padding: 5px 19px 2px 3px;
+ width: 99.6%;
+ }
+ .wmd-container textarea {
+ border: none;
+ }
+ .transient-comment {
+ margin-bottom: 3px; /* match paragraph style */
}
input {
margin-left: 10px;
diff --git a/askbot/models/post.py b/askbot/models/post.py
index e6c26154..10003e57 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -3,7 +3,6 @@ import datetime
import operator
import logging
-from django.utils.html import strip_tags
from django.contrib.sitemaps import ping_google
from django.utils import html
from django.conf import settings as django_settings
@@ -421,26 +420,8 @@ class Post(models.Model):
removed_mentions - list of mention <Activity> objects - for removed ones
"""
- if self.post_type in ('question', 'answer', 'tag_wiki', 'reject_reason'):
- _urlize = False
- _use_markdown = (askbot_settings.EDITOR_TYPE == 'markdown')
- elif self.is_comment():
- _urlize = True
- _use_markdown = (askbot_settings.EDITOR_TYPE == 'markdown')
- else:
- raise NotImplementedError
-
- text = self.text
-
- if _urlize:
- text = html.urlize(text)
-
- if _use_markdown:
- text = sanitize_html(markup.get_parser().convert(text))
-
- if askbot_settings.EDITOR_TYPE == 'tinymce':
- #todo: see what can be done with the "object" tag
- text = strip_tags(text, ['script', 'style', 'link'])
+ text_converter = self.get_text_converter()
+ text = text_converter(self.text)
#todo, add markdown parser call conditional on
#self.use_markdown flag
@@ -614,6 +595,23 @@ class Post(models.Model):
return answer
+ def get_text_converter(self):
+ have_simple_comment = (
+ self.is_comment() and
+ askbot_settings.COMMENTS_EDITOR_TYPE == 'plain-text'
+ )
+ if have_simple_comment:
+ parser_type = 'plain-text'
+ else:
+ parser_type = askbot_settings.EDITOR_TYPE
+
+ if parser_type == 'plain-text':
+ return markup.plain_text_input_converter
+ elif parser_type == 'markdown':
+ return markup.markdown_input_converter
+ elif parser_type == 'tynymce':
+ return markup.tinymce_input_converter
+
def has_group(self, group):
"""true if post belongs to the group"""
return self.groups.filter(id=group.id).exists()
diff --git a/askbot/templates/meta/bottom_scripts.html b/askbot/templates/meta/bottom_scripts.html
index 78e23d89..e7ccb822 100644
--- a/askbot/templates/meta/bottom_scripts.html
+++ b/askbot/templates/meta/bottom_scripts.html
@@ -30,6 +30,16 @@
askbot['settings']['minSearchWordLength'] = {{ min_search_word_length }};
askbot['settings']['mathjaxEnabled'] = {{ settings.ENABLE_MATHJAX|as_js_bool }};
askbot['settings']['sharingSuffixText'] = '{{ settings.SHARING_SUFFIX_TEXT|escape }}';
+ askbot['data']['maxCommentLength'] = {{ settings.MAX_COMMENT_LENGTH }};
+ askbot['settings']['editorType'] = '{{ settings.EDITOR_TYPE }}';
+ askbot['settings']['commentsEditorType'] = '{{ settings.COMMENTS_EDITOR_TYPE }}';
+ {% if settings.ALLOWED_UPLOAD_FILE_TYPES %}
+ askbot['settings']['allowedUploadFileTypes'] = [
+ "{{ settings.ALLOWED_UPLOAD_FILE_TYPES|join('", "')|replace('.','') }}"
+ ];
+ {% else %}
+ askbot['settings']['allowedUploadFileTypes'] = [];
+ {% endif %}
askbot['data']['haveFlashNotifications'] = {{ user_messages|as_js_bool }};
askbot['data']['activeTab'] = '{{ active_tab }}';
{% if search_state %}
diff --git a/askbot/templates/meta/html_head_javascript.html b/askbot/templates/meta/html_head_javascript.html
index 07a39f80..965dd350 100644
--- a/askbot/templates/meta/html_head_javascript.html
+++ b/askbot/templates/meta/html_head_javascript.html
@@ -13,17 +13,8 @@
{% else %}
askbot['data']['userReputation'] = 0;
{% endif %}
- askbot['data']['maxCommentLength'] = {{ settings.MAX_COMMENT_LENGTH }};
askbot['urls'] = {};
askbot['settings'] = {};
- askbot['settings']['editorType'] = '{{ settings.EDITOR_TYPE }}';
- {% if settings.ALLOWED_UPLOAD_FILE_TYPES %}
- askbot['settings']['allowedUploadFileTypes'] = [
- "{{ settings.ALLOWED_UPLOAD_FILE_TYPES|join('", "')|replace('.','') }}"
- ];
- {% else %}
- askbot['settings']['allowedUploadFileTypes'] = [];
- {% endif %}
askbot['messages'] = {};
</script>
<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
diff --git a/askbot/utils/markup.py b/askbot/utils/markup.py
index ac96ec74..33d0522e 100644
--- a/askbot/utils/markup.py
+++ b/askbot/utils/markup.py
@@ -7,6 +7,8 @@ import re
import logging
from askbot import const
from askbot.conf import settings as askbot_settings
+from askbot.utils.html import sanitize_html, strip_tags
+from django.utils.html import urlize
from markdown2 import Markdown
#url taken from http://regexlib.com/REDetails.aspx?regexp_id=501 by Brian Bothwell
URL_RE = re.compile("((?<!(href|.src|data)=['\"])((http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*))")
@@ -189,3 +191,18 @@ def mentionize_text(text, anticipated_authors):
#append the rest of text that did not have @ symbols
output += text
return mentioned_authors, output
+
+def plain_text_input_converter(text):
+ """plain text to html converter"""
+ return sanitize_html(urlize('<p>' + text + '</p>'))
+
+def markdown_input_converter(text):
+ """markdown to html converter"""
+ text = urlize(text)
+ text = get_parser().convert(text)
+ return sanitize_html(text)
+
+def tinymce_input_parser(text):
+ """tinymce input to production html converter"""
+ text = urlize(text)
+ return strip_tags(text, ['script', 'style', 'link'])
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index deec46cc..e8d50cea 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -62,9 +62,6 @@ ANSWERS_PAGE_SIZE = 10
def upload(request):#ajax upload file to a question or answer
"""view that handles file upload via Ajax
"""
- import pdb
- pdb.set_trace()
-
# check upload permission
result = ''
error = ''
@@ -744,7 +741,6 @@ def post_comments(request):#generic ajax handler to load comments to an object
@decorators.ajax_only
#@decorators.check_spam('comment')
def edit_comment(request):
-
if request.user.is_anonymous():
raise exceptions.PermissionDenied(_('Sorry, anonymous users cannot edit comments'))