* @param string message
*/
convertFromHtml: function(message) {
- // DEBUG ONLY
- return __REDACTOR_AMD_DEPENDENCIES.BBCodeFromHTML.convert(message);
+ var obj = { html: message };
- var $searchFor = [ ];
+ /** @deprecated legacy event */
+ WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'beforeConvertFromHtml', obj);
- WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'beforeConvertFromHtml', { html: html });
+ /** @deprecated legacy event */
+ WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'convertFromHtml', obj);
- // remove zero-width space sometimes slipping through
- html = html.replace(/&#(8203|x200b);/g, '');
+ obj.html = __REDACTOR_AMD_DEPENDENCIES.BBCodeFromHTML.convert(obj.html);
- // revert conversion of special characters
- html = html.replace(/™/gi, '\u2122');
- html = html.replace(/©/gi, '\u00a9');
- html = html.replace(/…/gi, '\u2026');
- html = html.replace(/—/gi, '\u2014');
- html = html.replace(/‐/gi, '\u2010');
+ /** @deprecated legacy event */
+ WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'afterConvertFromHtml', obj);
- // attachments
- html = html.replace(/<img([^>]*?)class="[^"]*redactorEmbeddedAttachment[^"]*"([^>]*?)>/gi, function(match, attributesBefore, attributesAfter) {
- var $attributes = attributesBefore + ' ' + attributesAfter;
- var $attachmentID;
- if ($attributes.match(/data-attachment-id="(\d+)"/)) {
- $attachmentID = RegExp.$1;
- }
- else {
- return match;
- }
-
- var $float = 'none';
- var $width = null;
-
- if ($attributes.match(/style="([^"]+)"/)) {
- var $styles = RegExp.$1.split(';');
-
- for (var $i = 0; $i < $styles.length; $i++) {
- var $style = $.trim($styles[$i]);
- if ($style.match(/^float: (left|right)$/)) {
- $float = RegExp.$1;
- }
- else if ($style.match(/^width: (\d+)px$/)) {
- $width = RegExp.$1;
- }
- }
-
- if ($width !== null) {
- return '[attach=' + $attachmentID + ',' + $float + ',' + $width + '][/attach]';
- }
- else if ($float !== 'none') {
- return '[attach=' + $attachmentID + ',' + $float + '][/attach]';
- }
- }
-
- return '[attach=' + $attachmentID + '][/attach]';
- });
-
- WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'convertFromHtml', { html: html });
-
- // Remove remaining tags.
- html = html.replace(/<[^(<|>)]+>/g, '');
-
- // Restore <, > and &
- html = html.replace(/</g, '<');
- html = html.replace(/>/g, '>');
- html = html.replace(/&/g, '&');
-
- // Restore ( and )
- html = html.replace(/%28/g, '(');
- html = html.replace(/%29/g, ')');
-
- WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'afterConvertFromHtml', { html: html });
-
- return html;
+ return obj.html;
},
/**
* @param string message
*/
convertToHtml: function(message) {
- // DEBUG ONLY
- return __REDACTOR_AMD_DEPENDENCIES.BBCodeToHTML.convert(message);
+ var obj = { data: message };
- WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'beforeConvertToHtml', { data: data });
-
- // remove 0x200B (unicode zero width space)
- data = this.wutil.removeZeroWidthSpace(data);
-
- // attachments
- var $attachmentUrl = this.wutil.getOption('woltlab.attachmentUrl');
- var $attachmentThumbnailUrl = this.wutil.getOption('woltlab.attachmentThumbnailUrl');
- if ($attachmentUrl) {
- var $imageAttachments = this.wbbcode._getImageAttachments();
-
- data = data.replace(/\[attach=(\d+)\]\[\/attach\]/g, function(match, attachmentID, alignment) {
- attachmentID = parseInt(attachmentID);
-
- if ($imageAttachments[attachmentID] !== undefined) {
- return '<img src="' + $attachmentThumbnailUrl.replace(/987654321/, attachmentID) + '" class="redactorEmbeddedAttachment redactorDisableResize" data-attachment-id="' + attachmentID + '" />';
- }
-
- return match;
- });
-
- data = data.replace(/\[attach=(\d+),(left|right|none)\]\[\/attach\]/g, function(match, attachmentID, alignment) {
- attachmentID = parseInt(attachmentID);
-
- if ($imageAttachments[attachmentID] !== undefined) {
- var $style = '';
- if (alignment === 'left' || alignment === 'right') {
- $style = 'float: ' + alignment + ';';
-
- if (alignment === 'left') {
- $style += 'margin: 0 15px 7px 0';
- }
- else {
- $style += 'margin: 0 0 7px 15px';
- }
- }
-
- $style = ' style="' + $style + '"';
-
- return '<img src="' + $attachmentThumbnailUrl.replace(/987654321/, attachmentID) + '" class="redactorEmbeddedAttachment redactorDisableResize" data-attachment-id="' + attachmentID + '"' + $style + ' />';
- }
-
- return match;
- });
-
- data = data.replace(/\[attach=(\d+),(left|right|none),(\d+)\]\[\/attach\]/g, function(match, attachmentID, alignment, width) {
- attachmentID = parseInt(attachmentID);
-
- if ($imageAttachments[attachmentID] !== undefined) {
- var $style = 'width: ' + width + 'px; max-height: ' + $imageAttachments[attachmentID].height + 'px; max-width: ' + $imageAttachments[attachmentID].width + 'px;';
- if (alignment === 'left' || alignment === 'right') {
- $style += 'float: ' + alignment + ';';
-
- if (alignment === 'left') {
- $style += 'margin: 0 15px 7px 0';
- }
- else {
- $style += 'margin: 0 0 7px 15px';
- }
- }
-
- $style = ' style="' + $style + '"';
-
- return '<img src="' + $attachmentUrl.replace(/987654321/, attachmentID) + '" class="redactorEmbeddedAttachment" data-attachment-id="' + attachmentID + '"' + $style + ' />';
- }
-
- return match;
- });
- }
+ /** @deprecated legacy event */
+ WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'beforeConvertToHtml', obj);
- // remove "javascript:"
- data = data.replace(/(javascript):/gi, '$1<span></span>:');
+ obj.data = __REDACTOR_AMD_DEPENDENCIES.BBCodeToHTML.convert(obj.data, {
+ attachments: {
+ images: this.wbbcode._getImageAttachments(),
+ thumbnailUrl: this.wutil.getOption('woltlab.attachmentThumbnailUrl'),
+ url: this.wutil.getOption('woltlab.attachmentUrl')
+ }
+ });
- WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'afterConvertToHtml', { data: data });
+ /** @deprecated legacy event */
+ WCF.System.Event.fireEvent('com.woltlab.wcf.redactor', 'afterConvertToHtml', obj);
- return data;
+ return obj.data;
},
/**
}
}
else if (container.nextSibling === container.nextElementSibling) {
- console.debug("this!");
if (container.nextElementSibling.nodeName === 'KBD' || container.nextElementSibling.nodeName === 'BR') {
setCaretBeforeOrAfter(container, false);
}
- else {
- console.debug(container.nextSibling);
- console.debug(container.nextElementSibling);
- }
}
if (container === editor.lastElementChild) {
}).bind(this);
// image.update
- var $moveImage = (function(image) {
- var $parent = image.parent();
- image = image.detach();
- image.prependTo($parent);
-
- this.caret.setAfter(image);
- }).bind(this);
-
this.image.update = (function(image) {
this.image.hideResize();
this.buffer.set();
image.attr('src', $('#redactor-image-link-source').val());
this.image.setFloating(image);
- $moveImage(image);
var link = $('#redactor-image-link-href').val().trim();
var anchor = image.closest('a', this.$editor[0]);
var element = this.selection.getCurrent();
if (element === false) {
- console.debug("nope");
return;
}
if (element.nodeType === Node.TEXT_NODE) {
element = element.parentNode;
}
- console.debug(element);
+
if (element === this.$editor[0]) {
return;
}
if (element.classList.contains('smiley')) {
// smiley
element.outerHTML = (addSmileyPadding(element, true) ? ' ' : '') + element.getAttribute('alt') + (addSmileyPadding(element, false) ? ' ' : '');
+ return;
}
- else if (element.classList.contains('redactorEmbeddedAttachment')) {
- // TODO: handle attachments
+
+ var float = element.style.getPropertyValue('float') || 'none';
+ var width = element.style.getPropertyValue('width');
+ width = (typeof width === 'string') ? ~~width.replace(/px$/, '') : 0;
+
+ if (element.classList.contains('redactorEmbeddedAttachment')) {
+ var attachmentId = element.getAttribute('data-attachment-id');
+
+ if (width > 0) {
+ element.outerHTML = "[attach=" + attachmentId + "," + float + "," + width + "][/attach]";
+ }
+ else if (float !== 'none') {
+ element.outerHTML = "[attach=" + attachmentId + "," + float + "][/attach]";
+ }
+ else {
+ element.outerHTML = "[attach=" + attachmentId + "][/attach]";
+ }
}
else {
// regular image
- var float = element.style.getPropertyValue('float') || 'none';
var source = element.src.trim();
- var width = ~~element.style.getPropertyValue('width').replace(/px$/, '') || 0;
if (width > 0) {
element.outerHTML = "[img='" + source + "'," + float + "," + width + "][/img]";
-define(['EventHandler', 'Language', 'StringUtil', 'WoltLab/WCF/BBCode/Parser'], function(EventHandler, Language, StringUtil, BBCodeParser) {
+define(['Core', 'EventHandler', 'Language', 'StringUtil', 'WoltLab/WCF/BBCode/Parser'], function(Core, EventHandler, Language, StringUtil, BBCodeParser) {
"use strict";
var _bbcodes = null;
+ var _options = {};
var _removeNewlineAfter = [];
var _removeNewlineBefore = [];
function isHighlighter(value) { return __REDACTOR_CODE_HIGHLIGHTERS.hasOwnProperty(value); }
var BBCodeToHtml = {
- convert: function(message) {
+ convert: function(message, options) {
+ _options = Core.extend({
+ attachments: {
+ images: {},
+ thumbnailUrl: '',
+ url: ''
+ }
+ }, options);
+
this._convertSpecials(message);
var stack = BBCodeParser.parse(message);
this._initBBCodes();
}
- var item;
+ var item, value;
for (var i = 0, length = stack.length; i < length; i++) {
item = stack[i];
if (typeof item === 'object') {
- stack[i] = this._replace(stack, item, i);
+ value = this._replace(stack, item, i);
+ if (Array.isArray(value)) {
+ stack[i] = (value[0] === null ? item.source : value[0]);
+ stack[item.pair] = (value[1] === null ? stack[item.pair].source : value[1]);
+ }
+ else {
+ stack[i] = value;
+ }
}
}
tt: 'kbd',
// callback replacement
+ attach: this._replaceAttachment.bind(this),
color: this._replaceColor.bind(this),
code: this._replaceCode.bind(this),
email: this._replaceEmail.bind(this),
if (replace === undefined) {
// treat as plain text
- console.debug(item);
- console.debug(stack);
- stack[item.pair] = stack[item.pair].source;
-
- return item.source;
+ return [null, null];
}
if (_removeNewlineAfter.indexOf(item.name) !== -1) {
this._replaceSmilies(stack);
if (typeof replace === 'string') {
- stack[item.pair] = '</' + replace + '>';
-
- return '<' + replace + '>';
+ return ['<' + replace + '>', '</' + replace + '>'];
}
else {
return replace(stack, item, index);
}
},
+ _replaceAttachment: function(stack, item, index) {
+ var attachmentId = 0, attributes = item.attributes, length = attributes.length;
+ if (!_options.attachments.url) {
+ length = 0;
+ }
+ else if (length > 0) {
+ attachmentId = ~~attributes[0];
+ if (!_options.attachments.images.hasOwnProperty(attachmentId)) {
+ length = 0;
+ }
+ }
+
+ if (length === 0) {
+ return [null, null];
+ }
+
+ var maxHeight = ~~_options.attachments.images[attachmentId].height;
+ var maxWidth = ~~_options.attachments.images[attachmentId].width;
+ var styles = ['max-height: ' + maxHeight + 'px', 'max-width: ' + maxWidth + 'px'];
+
+ if (length > 1) {
+ if (item.attributes[1] === 'left' || attributes[1] === 'right') {
+ styles.push('float: ' + attributes[1]);
+ styles.push('margin: ' + (attributes[1] === 'left' ? '0 15px 7px 0' : '0 0 7px 15px'));
+ }
+ }
+
+ var baseUrl = _options.attachments.thumbnailUrl;
+ if (length > 2) {
+ width = ~~attributes[2] || 0;
+ if (width) {
+ if (width > maxWidth) width = maxWidth;
+
+ styles.push('width: ' + width + 'px');
+ baseUrl = _options.attachments.url;
+ }
+ }
+
+ return [
+ '<img src="' + baseUrl.replace(/987654321/, attachmentId) + '" class="redactorEmbeddedAttachment redactorDisableResize" data-attachment-id="' + attachmentId + '"' + (styles.length ? ' style="' + styles.join(';') + '"' : '') + '>',
+ ''
+ ];
+ },
+
_replaceCode: function(stack, item, index) {
var attributes = item.attributes, filename = '', highlighter = 'auto', lineNumber = 0;
}
}
- stack[item.pair] = '</ol></div></div>';
-
- return '<div class="codeBox container" contenteditable="false" data-highlighter="' + highlighter + '" data-filename="' + (filename ? StringUtil.escapeHTML(filename) : '') + '">'
+ return [
+ '<div class="codeBox container" contenteditable="false" data-highlighter="' + highlighter + '" data-filename="' + (filename ? StringUtil.escapeHTML(filename) : '') + '">'
+ '<div>'
+ '<div>'
+ '<h3>' + __REDACTOR_CODE_HIGHLIGHTERS[highlighter] + (filename ? ': ' + StringUtil.escapeHTML(filename) : '') + '</h3>'
+ '</div>'
- + '<ol start="' + (lineNumber > 1 ? lineNumber : 1) + '">';
+ + '<ol start="' + (lineNumber > 1 ? lineNumber : 1) + '">',
+ '</ol></div></div>'
+ ];
},
_replaceColor: function(stack, item, index) {
if (!item.attributes.length || !item.attributes[0].match(/^[a-z0-9#]+$/i)) {
- stack[item.pair] = '';
-
- return '';
+ return [null, null];
}
- stack[item.pair] = '</span>';
-
- return '<span style="color: ' + StringUtil.escapeHTML(item.attributes[0]) + '">';
+ return ['<span style="color: ' + StringUtil.escapeHTML(item.attributes[0]) + '">', '</span>'];
},
_replaceEmail: function(stack, item, index) {
// no attribute present and element is empty, handle as plain text
if (email.trim() === '') {
- stack[item.pair] = stack[item.pair].source;
-
- return item.source;
+ return [null, null];
}
}
- stack[item.pair] = '</a>';
-
- return '<a href="mailto:' + StringUtil.escapeHTML(email) + '">';
+ return ['<a href="mailto:' + StringUtil.escapeHTML(email) + '">', '</a>'];
},
_replaceImage: function(stack, item, index) {
- stack[item.pair] = '';
-
var float = 'none', source = '', width = 0;
switch (item.attributes.length) {
styles.push('margin: ' + (float === 'left' ? '0 15px 7px 0' : '0 0 7px 15px'));
}
- return '<img src="' + StringUtil.escapeHTML(source) + '"' + (styles.length ? ' style="' + styles.join(';') + '"' : '') + '>';
+ return ['<img src="' + StringUtil.escapeHTML(source) + '"' + (styles.length ? ' style="' + styles.join(';') + '"' : '') + '>', ''];
},
_replaceList: function(stack, item, index) {
}
if (type == '1' || type === 'decimal') {
- stack[item.pair] = '</ol>';
-
- return '<ol>';
+ return ['<ol>', '</ol>'];
}
- stack[item.pair] = '</ul>';
if (type.length && type.match(/^(?:none|circle|square|disc|decimal|lower-roman|upper-roman|decimal-leading-zero|lower-greek|lower-latin|upper-latin|armenian|georgian)$/)) {
- return '<ul style="list-style-type: ' + type + '">';
+ return ['<ul style="list-style-type: ' + type + '">', '</ul>'];
}
- return '<ul>';
+ return ['<ul>', '</ul>'];
},
_replaceQuote: function(stack, item, index) {
author = item.attributes[0];
}
- stack[item.pair] = '</div></blockquote>';
-
// get rid of the trailing newline for quote content
for (var i = item.pair - 1; i > index; i--) {
if (typeof stack[i] === 'string') {
header = '<small>' + Language.get('wcf.bbcode.quote.title.clickToSet') + '</small>';
}
- return '<blockquote class="quoteBox container containerPadding quoteBoxSimple" cite="' + StringUtil.escapeHTML(link) + '" data-author="' + StringUtil.escapeHTML(author) + '">'
+ return [
+ '<blockquote class="quoteBox container containerPadding quoteBoxSimple" cite="' + StringUtil.escapeHTML(link) + '" data-author="' + StringUtil.escapeHTML(author) + '">'
+ '<header contenteditable="false">'
+ '<h3>'
+ header
+ '</h3>'
+ '<a class="redactorQuoteEdit"></a>'
+ '</header>'
- + '<div>\u200b';
+ + '<div>\u200b',
+ '</div></blockquote>'
+ ];
},
_replaceSmilies: function(stack) {
return '';
}
- stack[item.pair] = '</a>';
-
- return '<a href="' + StringUtil.escapeHTML(item.attributes[0]) + '">';
+ return ['<a href="' + StringUtil.escapeHTML(item.attributes[0]) + '">', '</a>'];
}
};