diff options
-rw-r--r-- | askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js | 4 | ||||
-rw-r--r-- | askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js | 3 | ||||
-rw-r--r-- | askbot/media/js/utils.js | 214 | ||||
-rw-r--r-- | askbot/media/style/style.css | 74 | ||||
-rw-r--r-- | askbot/media/style/style.less | 41 | ||||
-rw-r--r-- | askbot/views/writers.py | 13 |
6 files changed, 282 insertions, 67 deletions
diff --git a/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js b/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js index d1ef13b4..5f996804 100644 --- a/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js +++ b/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js @@ -27,11 +27,9 @@ }
};
- var modalMenuHeadline = gettext('Insert a file');
-
var createDialog = function() {
var dialog = new FileUploadDialog();
- dialog.setHeadingText(modalMenuHeadline);
+ dialog.setFileType('attachment');
dialog.setPostUploadHandler(insertIntoDom);
dialog.setInputId('askbot_attachment_input');
dialog.setUrlInputTooltip(gettext('Or paste file url here'));
diff --git a/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js b/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js index 7fa6b6be..0cd70473 100644 --- a/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js +++ b/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js @@ -27,11 +27,8 @@ }
};
- var modalMenuHeadline = gettext('Upload an image');
-
var createDialog = function() {
var dialog = new FileUploadDialog();
- dialog.setHeadingText(modalMenuHeadline);
dialog.setPostUploadHandler(insertIntoDom);
dialog.setUrlInputTooltip('Or paste image url here');
dialog.setInputId('askbot_imageuploader_input');
diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js index 8ce4e205..a26c1ec9 100644 --- a/askbot/media/js/utils.js +++ b/askbot/media/js/utils.js @@ -903,6 +903,7 @@ var ModalDialog = function() { var me = this; this._reject_handler = function() { me.hide(); }; this._content_element = undefined; + this._headerEnabled = true; }; inherits(ModalDialog, WrappedElement); @@ -965,19 +966,21 @@ ModalDialog.prototype.createDom = function() { element.addClass('modal'); //1) create header - var header = this.makeElement('div') - header.addClass('modal-header'); - element.append(header); + if (this._headerEnabled) { + var header = this.makeElement('div') + header.addClass('modal-header'); + element.append(header); + var close_link = this.makeElement('div'); + close_link.addClass('close'); + close_link.attr('data-dismiss', 'modal'); + close_link.html('x'); + header.append(close_link); + var title = this.makeElement('h3'); + title.html(this._heading_text); + header.append(title); + } - var close_link = this.makeElement('div'); - close_link.addClass('close'); - close_link.attr('data-dismiss', 'modal'); - close_link.html('x'); - header.append(close_link); - var title = this.makeElement('h3'); - title.html(this._heading_text); - header.append(title); //2) create content var body = this.makeElement('div') @@ -994,13 +997,13 @@ ModalDialog.prototype.createDom = function() { element.append(footer); var accept_btn = this.makeElement('button'); - accept_btn.addClass('btn btn-primary'); + accept_btn.addClass('submit'); accept_btn.html(this._accept_button_text); footer.append(accept_btn); if (this._reject_button_text) { var reject_btn = this.makeElement('button'); - reject_btn.addClass('btn cancel'); + reject_btn.addClass('submit cancel'); reject_btn.html(this._reject_button_text); footer.append(reject_btn); } @@ -1010,7 +1013,9 @@ ModalDialog.prototype.createDom = function() { if (this._reject_button_text) { setupButtonEventHandlers(reject_btn, this._reject_handler); } - setupButtonEventHandlers(close_link, this._reject_handler); + if (this._headerEnabled) { + setupButtonEventHandlers(close_link, this._reject_handler); + } this.hide(); }; @@ -1020,10 +1025,27 @@ ModalDialog.prototype.createDom = function() { */ var FileUploadDialog = function() { ModalDialog.call(this); - self._post_upload_handler = undefined; + this._post_upload_handler = undefined; + this._fileType = 'image'; + this._headerEnabled = false; }; inherits(FileUploadDialog, ModalDialog); +/** + * allowed values: 'image', 'attachment' + */ +FileUploadDialog.prototype.setFileType = function(fileType) { + this._fileType = fileType; +}; + +FileUploadDialog.prototype.getFileType = function() { + return this._fileType; +}; + +FileUploadDialog.prototype.setButtonText = function(text) { + this._fakeInput.val(text); +}; + FileUploadDialog.prototype.setPostUploadHandler = function(handler) { this._post_upload_handler = handler; }; @@ -1040,6 +1062,10 @@ FileUploadDialog.prototype.getInputId = function() { return this._input_id; }; +FileUploadDialog.prototype.setLabelText= function(text) { + this._label.html(text); +}; + FileUploadDialog.prototype.setUrlInputTooltip = function(text) { this._url_input_tooltip = text; }; @@ -1063,30 +1089,112 @@ FileUploadDialog.prototype.resetInputs = function() { this._upload_input.val(''); }; +FileUploadDialog.prototype.getInputElement = function() { + return $('#' + this.getInputId()); +}; + +FileUploadDialog.prototype.installFileUploadHandler = function(handler) { + var upload_input = this.getInputElement(); + upload_input.unbind('change'); + //todo: fix this - make event handler reinstall work + upload_input.change(handler); +}; + FileUploadDialog.prototype.show = function() { //hack around the ajaxFileUpload plugin FileUploadDialog.superClass_.show.call(this); - var upload_input = this._upload_input; - upload_input.unbind('change'); - //todo: fix this - make event handler reinstall work - upload_input.change(this.getStartUploadHandler()); + var handler = this.getStartUploadHandler(); + this.installFileUploadHandler(handler); }; -FileUploadDialog.prototype.getStartUploadHandler = function(){ - /* startUploadHandler is passed in to re-install the event handler - * which is removed by the ajaxFileUpload jQuery extension - */ +FileUploadDialog.prototype.getUrlInputElement = function() { + return this._url_input.getElement(); +}; + +/* + * argument startUploadHandler is very special it must + * be a function calling this one!!! Todo: see if there + * is a more civilized way to do this. + */ +FileUploadDialog.prototype.startFileUpload = function(startUploadHandler) { + var spinner = this._spinner; - var uploadInputId = this.getInputId(); - var urlInput = this._url_input; + var label = this._label; + + spinner.ajaxStart(function(){ + spinner.show(); + label.hide(); + }); + spinner.ajaxComplete(function(){ + spinner.hide(); + label.show(); + }); + + /* important!!! upload input must be loaded by id + * because ajaxFileUpload monkey-patches the upload form */ + var uploadInput = this.getInputElement(); + uploadInput.ajaxStart(function(){ uploadInput.hide(); }); + uploadInput.ajaxComplete(function(){ uploadInput.show(); }); + + //var localFilePath = upload_input.val(); + + var me = this; + + $.ajaxFileUpload({ + url: askbot['urls']['upload'], + secureuri: false,//todo: check on https + fileElementId: this.getInputId(), + dataType: 'xml', + success: function (data, status) { + + var fileURL = $(data).find('file_url').text(); + var origFileName = $(data).find('orig_file_name').text(); + var newStatus = interpolate( + gettext('Uploaded file: %s'), + [origFileName] + ); + /* + * hopefully a fix for the "fakepath" issue + * https://www.mediawiki.org/wiki/Special:Code/MediaWiki/83225 + */ + fileURL = fileURL.replace(/\w:.*\\(.*)$/,'$1'); + var error = $(data).find('error').text(); + if (error != ''){ + alert(error); + } else { + me.getUrlInputElement().attr('value', fileURL); + me.setLabelText(newStatus); + if (me.getFileType() === 'image') { + var buttonText = gettext('Choose a different image'); + } else { + var buttonText = gettext('Choose a different file'); + } + me.setButtonText(buttonText); + } + + /* re-install this as the upload extension + * will remove the handler to prevent double uploading + * this hack is a manipulation around the + * ajaxFileUpload jQuery plugin. */ + me.installFileUploadHandler(startUploadHandler); + }, + error: function (data, status, e) { + /* re-install this as the upload extension + * will remove the handler to prevent double uploading */ + me.installFileUploadHandler(startUploadHandler); + } + }); + return false; +}; + +FileUploadDialog.prototype.getStartUploadHandler = function(){ + var me = this; var handler = function() { - var options = { - 'spinner': spinner, - 'uploadInputId': uploadInputId, - 'urlInput': urlInput.getElement(), - 'startUploadHandler': handler//pass in itself - }; - return ajaxFileUpload(options); + /* the trick is that we need inside the function call + * to have a reference to itself + * in order to reinstall the handler later + * because ajaxFileUpload jquery extension might be destroying it */ + return me.startFileUpload(handler); }; return handler; }; @@ -1113,10 +1221,11 @@ FileUploadDialog.prototype.createDom = function() { superClass.createDom.call(this); var form = this.makeElement('form'); + form.addClass('ajax-file-upload'); form.css('margin-bottom', 0); this.prependContent(form); - // File upload button + // Browser native file upload field var upload_input = this.makeElement('input'); upload_input.attr({ id: this._input_id, @@ -1126,9 +1235,32 @@ FileUploadDialog.prototype.createDom = function() { }); form.append(upload_input); this._upload_input = upload_input; - form.append($('<br/>')); - // The url input text box + var fakeInput = this.makeElement('input'); + fakeInput.attr('type', 'button'); + fakeInput.addClass('submit'); + fakeInput.addClass('fake-file-input'); + if (this._fileType === 'image') { + var buttonText = gettext('Choose an image to insert'); + } else { + var buttonText = gettext('Choose a file to insert'); + } + fakeInput.val(buttonText); + this._fakeInput = fakeInput; + form.append(fakeInput); + + setupButtonEventHandlers(fakeInput, function() { upload_input.click() }); + + // Label which will also serve as status display + var label = this.makeElement('label'); + label.attr('for', this._input_id); + var types = askbot['settings']['allowedUploadFileTypes']; + types = types.join(', '); + label.html(gettext('Allowed file types are:') + ' ' + types + '.'); + form.append(label); + this._label = label; + + // The url input text box, probably unused in fact var url_input = new TippedInput(); url_input.setInstruction(this._url_input_tooltip || gettext('Or paste file url here')); var url_input_element = url_input.getElement(); @@ -1140,15 +1272,6 @@ FileUploadDialog.prototype.createDom = function() { //form.append($('<br/>')); this._url_input = url_input; - var label = this.makeElement('label'); - label.attr('for', this._input_id); - - var types = askbot['settings']['allowedUploadFileTypes']; - types = types.join(', '); - label.html(gettext('Allowed file types are:') + ' ' + types + '.'); - form.append(label); - form.append($('<br/>')); - /* //Description input box var descr_input = new TippedInput(); descr_input.setInstruction(gettext('Describe the image here')); @@ -1158,8 +1281,9 @@ FileUploadDialog.prototype.createDom = function() { this._description_input = descr_input; */ var spinner = this.makeElement('img'); - spinner.attr('src', mediaUrl('media/images/indicator.gif')); + spinner.attr('src', mediaUrl('media/images/ajax-loader.gif')); spinner.css('display', 'none'); + spinner.addClass('spinner'); form.append(spinner); this._spinner = spinner; diff --git a/askbot/media/style/style.css b/askbot/media/style/style.css index 3c447e56..9e386c09 100644 --- a/askbot/media/style/style.css +++ b/askbot/media/style/style.css @@ -144,6 +144,12 @@ html { height: 0; visibility: hidden; } +.invisible { + margin: -1px 0 0 -1px; + height: 1px; + overflow: hidden; + width: 1px; +} .badges a { color: #763333; text-decoration: underline; @@ -610,19 +616,20 @@ input[type="submit"], input[type="button"], input[type="reset"], .button { + border: 0 !important; + border-top: #eaf2f3 1px solid; cursor: pointer; color: #4a757f; - height: 27px; font-family: 'Open Sans Condensed', Arial, sans-serif; font-size: 14px; font-weight: bold; + height: 27px; + margin-right: 10px; text-align: center; text-decoration: none; text-shadow: 0px 1px 0px #c6d9dd; -moz-text-shadow: 0px 1px 0px #c6d9dd; -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border: 0 !important; - border-top: #eaf2f3 1px solid; background-color: #d1e2e5; background-repeat: no-repeat; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); @@ -678,6 +685,39 @@ input[type="submit"].link { input[type="submit"].link:hover { text-decoration: underline; } +form.ajax-file-upload { + height: 60px; + position: relative; +} +form.ajax-file-upload input[type="file"], +form.ajax-file-upload input.fake-file-input { + cursor: pointer; + height: 32px; + position: absolute; + top: 0; + left: 0; +} +form.ajax-file-upload input[type="file"] { + z-index: 2; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -moz-opacity: 0; + -khtml-opacity: 0; + opacity: 0; +} +form.ajax-file-upload input.fake-file-input { + z-index: 1; +} +form.ajax-file-upload label, +form.ajax-file-upload img.spinner { + bottom: 0; + left: 3px; + position: absolute; +} +form.ajax-file-upload img.spinner { + bottom: 6px; + left: 10px; +} #askButton { /* check blocks/secondary_header.html and widgets/ask_button.html*/ @@ -1750,6 +1790,13 @@ ul#related-tags li { width: 723px; width: 100%; } +.ask-page .post-comments .wmd-container, +.question-page .post-comments .wmd-container, +.edit-question-page .post-comments .wmd-container, +.edit-answer-page .post-comments .wmd-container { + margin-bottom: 8px; + margin-left: -2px; +} .ask-page #editor, .question-page #editor, .edit-question-page #editor, @@ -1967,6 +2014,10 @@ ul#related-tags li { width: 20px; vertical-align: top; } +.question-page .answer-table .mceEditor td, +.question-page #question-table .mceEditor td { + width: auto; +} .question-page .question-body, .question-page .answer-body { overflow: auto; @@ -2298,6 +2349,13 @@ ul#related-tags li { vertical-align: top; width: 100px; } +.question-page .comments input[name="suppress_email"] { + margin: 4px 5px 0 0; + width: auto; +} +.question-page .comments label[for="suppress_email"] { + vertical-align: top; +} .question-page .comments button.submit { height: 26px; line-height: 26px; @@ -2308,7 +2366,6 @@ ul#related-tags li { display: inline-block; width: 245px; float: right; - color: #b6a475 !important; vertical-align: top; font-family: Arial; float: right; @@ -3082,16 +3139,16 @@ ins { /* ----- Red Popup notification ----- */ .vote-notification { z-index: 1; + background-color: #8e0000; + color: white; cursor: pointer; display: none; - position: absolute; font-family: Arial; font-size: 14px; font-weight: normal; - color: white; - background-color: #8e0000; - text-align: center; padding-bottom: 10px; + position: absolute; + text-align: center; -webkit-box-shadow: 0px 2px 4px #370000; -moz-box-shadow: 0px 2px 4px #370000; box-shadow: 0px 2px 4px #370000; @@ -3108,6 +3165,7 @@ ins { margin-bottom: 5px; border-top: #8e0000 1px solid; color: #fff; + line-height: 20px; font-weight: normal; border-top-right-radius: 4px; border-top-left-radius: 4px; diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less index 85b18ac1..3c50090e 100644 --- a/askbot/media/style/style.less +++ b/askbot/media/style/style.less @@ -665,17 +665,18 @@ input[type="submit"], input[type="button"], input[type="reset"], .button { + border: 0 !important; + border-top: #eaf2f3 1px solid; cursor: pointer; color: @button-label; - height: 27px; font-family: @main-font; font-size: 14px; font-weight: bold; + height: 27px; + margin-right: 10px; text-align: center; text-decoration: none; .text-shadow(0px,1px,0px,#c6d9dd); - border: 0 !important; - border-top: #eaf2f3 1px solid; .linear-gradient(#d1e2e5,#a9c2c7); .rounded-corners(4px); .box-shadow(1px, 1px, 2px, #636363) @@ -709,6 +710,40 @@ input[type="submit"].link:hover { text-decoration: underline; } +form.ajax-file-upload { + height: 60px; + position: relative; + input[type="file"], + input.fake-file-input { + cursor: pointer; + height: 32px; + position: absolute; + top: 0; + left: 0; + } + input[type="file"] { + z-index: 2; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -moz-opacity: 0; + -khtml-opacity: 0; + opacity: 0; + } + input.fake-file-input { + z-index: 1; + } + label, + img.spinner { + bottom: 0; + left: 3px; + position: absolute; + } + img.spinner { + bottom: 6px; + left: 10px; + } +} + #askButton { /* check blocks/secondary_header.html and widgets/ask_button.html*/ float:right; font-size: 20px; diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 896ef09d..deec46cc 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -62,6 +62,8 @@ 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 = '' @@ -81,10 +83,11 @@ def upload(request):#ajax upload file to a question or answer raise exceptions.PermissionDenied('invalid upload file name prefix') #todo: check file type - f = request.FILES['file-upload']#take first file + uploaded_file = request.FILES['file-upload']#take first file + orig_file_name = uploaded_file.name #todo: extension checking should be replaced with mimetype checking #and this must be part of the form validation - file_extension = os.path.splitext(f.name)[1].lower() + file_extension = os.path.splitext(orig_file_name)[1].lower() if not file_extension in settings.ASKBOT_ALLOWED_UPLOAD_FILE_TYPES: file_types = "', '".join(settings.ASKBOT_ALLOWED_UPLOAD_FILE_TYPES) msg = _("allowed file types are '%(file_types)s'") % \ @@ -93,7 +96,7 @@ def upload(request):#ajax upload file to a question or answer # generate new file name and storage object file_storage, new_file_name, file_url = store_file( - f, file_name_prefix + uploaded_file, file_name_prefix ) # check file size # byte @@ -122,8 +125,8 @@ def upload(request):#ajax upload file to a question or answer # 'file_url': file_url #}) #return HttpResponse(data, mimetype = 'application/json') - xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>" - xml = xml_template % (result, error, file_url) + xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url><orig_file_name><![CDATA[%s]]></orig_file_name></result>" + xml = xml_template % (result, error, file_url, orig_file_name) return HttpResponse(xml, mimetype="application/xml") |