});
$config.plugins.push('wupload');
+ $config.wAttachmentUrl = '{link controller='Attachment' id=987654321}thumbnail=1{/link}';
{/if}
{event name='javascriptInit'}
html = html.replace(/<img [^>]*?alt="([^"]+?)" class="smiley".*?>/gi, '$1'); // firefox
html = html.replace(/<img [^>]*?class="smiley" alt="([^"]+?)".*?>/gi, '$1'); // chrome, ie
+ // attachments
+ html = html.replace(/<img [^>]*?class="redactorEmbeddedAttachment" data-attachment-id="(\d+)".*?>/gi, '[attach=$1][/attach]');
+
// [img]
html = html.replace(/<img [^>]*?src=(["'])([^"']+?)\1 style="float: (left|right)[^"]*".*?>/gi, "[img='$2',$3][/img]");
html = html.replace(/<img [^>]*?src=(["'])([^"']+?)\1.*?>/gi, '[img]$2[/img]');
return '<td>' + $tdContent + '</td>';
});
+ // attachments
+ var $attachmentUrl = this.getOption('wAttachmentUrl');
+ if ($attachmentUrl) {
+ data = data.replace(/\[attach=(\d+)\]\[\/attach\]/, function(match, attachmentID) {
+ return '<img src="' + $attachmentUrl.replace(/987654321/, attachmentID) + '" class="redactorEmbeddedAttachment" data-attachment-id="' + attachmentID + '" />';
+ });
+ }
+
// smileys
for (var smileyCode in __REDACTOR_SMILIES) {
$smileyCode = smileyCode.replace(/</g, '<').replace(/>/g, '>');
html = html.replace(/\[size=(\d+)\]/g, '<p><br></p><p><inline style="font-size: $1pt">');
html = html.replace(/\[\/size\]/g, '</inline></p><p><br></p>');
+ // handle pasting of images in Firefox
+ html = html.replace(/<img([^>]+)>/g, function(match, content) {
+ match = match.replace(/data-mozilla-paste-image="0"/, 'data-mozilla-paste-image="0" style="display:none"');
+ return match;
+ });
+
return html;
+ },
+
+ /**
+ * Inserts an attachment with live preview.
+ *
+ * @param integer attachmentID
+ */
+ insertAttachment: function(attachmentID) {
+ var $attachmentUrl = this.getOption('wAttachmentUrl');
+ var $bbcode = '[attach=' + attachmentID + '][/attach]';
+
+ if ($attachmentUrl) {
+ this.insertDynamic(
+ '<img src="' + $attachmentUrl.replace(/987654321/, attachmentID) + '" class="redactorEmbeddedAttachment" data-attachment-id="' + attachmentID + '" />',
+ $bbcode
+ );
+ }
+ else {
+ this.insertDynamic($bbcode);
+ }
}
};
$(document).on('dragend', function(event) { event.preventDefault(); });
}
+
+ WCF.System.Event.addListener('com.woltlab.wcf.attachment', 'autoInsert_' + this.$source.wcfIdentify(), $.proxy(this.insertPastedImageAttachment, this));
},
/**
WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'upload_' + $containerID, { file: event.dataTransfer.files[0] });
}
+ },
+
+ /**
+ * Overwrites $.Redactor.pasteClipboardUploadMozilla() to upload files as attachments.
+ *
+ * @see $.Redactor.pasteClipboardUploadMozilla()
+ */
+ pasteClipboardUploadMozilla: function() {
+ this.$editor.find('img[data-mozilla-paste-image]').each($.proxy(function(index, image) {
+ var $image = $(image);
+ var $src = $image.prop('src').split(',');
+ var $contentType = $src[0].split(';')[0].split(':')[1];
+ var $data = $src[1]; // raw base64
+
+ var $eventData = {
+ blob: WCF.base64toBlob($data, $contentType),
+ uploadID: null
+ };
+ WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'upload_' + this.$source.wcfIdentify(), $eventData);
+
+ // drop image
+ $image.replaceWith('<span class="redactor-pastedImageFromClipboard-' + $eventData.uploadID + '" />');
+ }, this));
+ },
+
+ /**
+ * Inserts the attachment at the placeholder location.
+ *
+ * @param object data
+ */
+ insertPastedImageAttachment: function(data) {
+ var $placeholder = this.$editor.find('span.redactor-pastedImageFromClipboard-' + data.uploadID);
+ $placeholder.before(data.attachment);
+ $placeholder.remove();
}
};
* @see WCF.Upload
*/
WCF.Attachment.Upload = WCF.Upload.extend({
+ /**
+ * list of upload ids which should be automatically inserted
+ * @var array<integer>
+ */
+ _autoInsert: [ ],
+
/**
* reference to 'Insert All' button
* @var jQuery
init: function(buttonSelector, fileListSelector, objectType, objectID, tmpHash, parentObjectID, maxUploads, wysiwygContainerID) {
this._super(buttonSelector, fileListSelector, 'wcf\\data\\attachment\\AttachmentAction', { multiple: true, maxUploads: maxUploads });
+ this._autoInsert = [ ];
this._objectType = objectType;
this._objectID = objectID;
this._tmpHash = tmpHash;
}
},
+ /**
+ * Handles drag & drop uploads and clipboard paste.
+ *
+ * @param object data
+ */
_editorUpload: function(data) {
+ var $uploadID;
+
// show tab
var $tabMenuContainer = this._fileListSelector.closest('.messageTabMenu')
$tabMenuContainer.messageTabMenu('showTab', 'attachments', true);
- this._upload(undefined, [ data.file ]);
+ if (data.file) {
+ $uploadID = this._upload(undefined, data.file);
+ }
+ else {
+ $uploadID = this._upload(undefined, undefined, data.blob);
+ }
+
+ this._autoInsert.push($uploadID);
+ data.uploadID = $uploadID;
},
/**
/**
* @see WCF.Upload._upload()
*/
- _upload: function(event, files) {
+ _upload: function(event, file, blob) {
+ var $uploadID;
+
if (this._validateLimit()) {
- this._super(event, files);
+ $uploadID = this._super(event, file, blob);
}
if (this._fileUpload) {
this._removeButton();
this._createButton();
}
+
+ return $uploadID;
},
/**
// fix webkit rendering bug
$li.css('display', 'block');
+
+ if (WCF.inArray(uploadID, this._autoInsert)) {
+ this._autoInsert.splice(this._autoInsert.indexOf(uploadID), 1);
+
+ if (!$li.hasClass('uploadFailed')) {
+ WCF.System.Event.fireEvent('com.woltlab.wcf.attachment', 'autoInsert_' + this._wysiwygContainerID, {
+ attachment: '[attach=' + data.returnValues.attachments[$internalFileID].attachmentID + '][/attach]',
+ uploadID: uploadID
+ });
+ }
+ }
}
this._makeSortable();
*/
_insert: function(event, attachmentID) {
var $attachmentID = (event === null) ? attachmentID : $(event.currentTarget).data('objectID');
- var $bbcode = '[attach=' + $attachmentID + '][/attach]';
if ($.browser.redactor) {
- $('#' + this._wysiwygContainerID).redactor('insertDynamic', $bbcode);
+ $('#' + this._wysiwygContainerID).redactor('insertAttachment', $attachmentID);
}
},
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
+ },
+
+ /**
+ * Converts a base64 encoded file into a native Blob.
+ *
+ * @param string base64data
+ * @param string contentType
+ * @param integer sliceSize
+ * @return Blob
+ */
+ base64toBlob: function(base64data, contentType, sliceSize) {
+ contentType = contentType || '';
+ sliceSize = sliceSize || 512;
+
+ var $byteCharacters = atob(base64data);
+ var $byteArrays = [ ];
+
+ for (var $offset = 0; $offset < $byteCharacters.length; $offset += sliceSize) {
+ var $slice = $byteCharacters.slice($offset, $offset + sliceSize);
+
+ var $byteNumbers = new Array($slice.length);
+ for (var $i = 0; $i < $slice.length; $i++) {
+ $byteNumbers[$i] = $slice.charCodeAt($i);
+ }
+
+ var $byteArray = new Uint8Array($byteNumbers);
+ $byteArrays.push($byteArray);
+ }
+
+ return new Blob($byteArrays, { type: contentType });
}
});
* Callback for file uploads.
*
* @param object event
- * @param array<File> files
+ * @param File file
+ * @param Blob blob
+ * @return integer
*/
- _upload: function(event, files) {
- var $files = files || this._fileUpload.prop('files');
+ _upload: function(event, file, blob) {
+ var $uploadID = null;
+ var $files = [ ];
+ if (file) {
+ $files.push(file);
+ }
+ else if (blob) {
+ var $ext = '';
+ switch (blob.type) {
+ case 'image/png':
+ $ext = '.png';
+ break;
+
+ case 'image/jpeg':
+ $ext = '.jpg';
+ break;
+
+ case 'image/gif':
+ $ext = '.gif';
+ break;
+ }
+
+ $files.push({
+ name: 'pasted-from-clipboard' + $ext
+ });
+ }
+ else {
+ $files = this._fileUpload.prop('files');
+ }
+
if ($files.length) {
var $fd = new FormData();
- var $uploadID = this._createUploadMatrix($files);
+ $uploadID = this._createUploadMatrix($files);
// no more files left, abort
if (!this._uploadMatrix[$uploadID].length) {
- return;
+ return null;
}
for (var $i = 0, $length = $files.length; $i < $length; $i++) {
if (this._uploadMatrix[$uploadID][$i]) {
var $internalFileID = this._uploadMatrix[$uploadID][$i].data('internalFileID');
- $fd.append('__files[' + $internalFileID + ']', $files[$i]);
+
+ if (blob) {
+ $fd.append('__files[' + $internalFileID + ']', blob, $files[$i].name);
+ }
+ else {
+ $fd.append('__files[' + $internalFileID + ']', $files[$i]);
+ }
}
}
}
});
}
+
+ return $uploadID;
},
/**