comparison src/sceditor.js @ 33:c23475f3f466

improve emoticons
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 14 Aug 2022 20:36:17 -0600
parents 98f11d0cbbd8
children 21090996a131
comparison
equal deleted inserted replaced
32:98f11d0cbbd8 33:c23475f3f466
2539 }, 2539 },
2540 // END_COMMAND 2540 // END_COMMAND
2541 2541
2542 // START_COMMAND: Emoticons 2542 // START_COMMAND: Emoticons
2543 emoticon: { 2543 emoticon: {
2544 exec: function (editor, caller) { 2544 base: function (editor, caller, targetToHtml) {
2545 var createContent = function (includeMore) { 2545 var createContent = function (includeMore) {
2546 var moreLink, 2546 var moreLink,
2547 opts = editor.opts, 2547 opts = editor.opts,
2548 emoticonsRoot = opts.emoticonsRoot || '', 2548 emoticonsRoot = opts.emoticonsRoot || '',
2549 emoticonsCompat = opts.emoticonsCompat, 2549 emoticonsCompat = opts.emoticonsCompat,
2550 rangeHelper = editor.getRangeHelper(),
2551 startSpace = emoticonsCompat &&
2552 rangeHelper.getOuterText(true, 1) !== ' ' ? ' ' : '',
2553 endSpace = emoticonsCompat &&
2554 rangeHelper.getOuterText(false, 1) !== ' ' ? ' ' : '',
2555 content = createElement('div'), 2550 content = createElement('div'),
2556 line = createElement('div'), 2551 line = createElement('div'),
2557 perLine = 0, 2552 perLine = 0,
2558 emoticons = extend( 2553 emoticons = extend(
2559 {}, 2554 {},
2564 appendChild(content, line); 2559 appendChild(content, line);
2565 2560
2566 perLine = Math.sqrt(Object.keys(emoticons).length); 2561 perLine = Math.sqrt(Object.keys(emoticons).length);
2567 2562
2568 onEvent1(content, 'click', 'img', function (target, e) { 2563 onEvent1(content, 'click', 'img', function (target, e) {
2569 editor.insert(startSpace + attr(target, 'alt') + endSpace, 2564 editor.insert(targetToHtml(target), null, false);
2570 null, false).closeDropDown(true); 2565 editor.closeDropDown(true);
2571 2566
2572 e.preventDefault(); 2567 e.preventDefault();
2573 }); 2568 });
2574 2569
2575 each(emoticons, function (code, emoticon) { 2570 each(emoticons, function (code, emoticon) {
2576 appendChild(line, createElement('img', { 2571 appendChild(line, createElement('img', {
2577 src: emoticonsRoot + (emoticon.url || emoticon), 2572 src: emoticonsRoot + (emoticon.url || emoticon),
2573 'data-sceditor-emoticon': code,
2578 alt: code, 2574 alt: code,
2579 title: emoticon.tooltip || code 2575 title: emoticon.tooltip || code
2580 })); 2576 }));
2581 2577
2582 if (line.children.length >= perLine) { 2578 if (line.children.length >= perLine) {
2607 return content; 2603 return content;
2608 }; 2604 };
2609 2605
2610 editor.createDropDown(caller, 'emoticons', createContent(false)); 2606 editor.createDropDown(caller, 'emoticons', createContent(false));
2611 }, 2607 },
2608 exec: function (editor, caller) {
2609 editor.commands.emoticon.base(editor, caller
2610 , function(target) { return target.outerHTML; }
2611 );
2612 },
2612 txtExec: function (editor, caller) { 2613 txtExec: function (editor, caller) {
2613 defaultCmds.emoticon.exec(editor, caller); 2614 editor.commands.emoticon.exec(editor, caller);
2614 }, 2615 },
2615 tooltip: 'Insert an emoticon' 2616 tooltip: 'Insert an emoticon'
2616 }, 2617 },
2617 // END_COMMAND 2618 // END_COMMAND
2618 2619
4042 * @param {HTMLElement} root 4043 * @param {HTMLElement} root
4043 * @param {Object<string, string>} emoticons 4044 * @param {Object<string, string>} emoticons
4044 * @param {boolean} emoticonsCompat 4045 * @param {boolean} emoticonsCompat
4045 * @return {void} 4046 * @return {void}
4046 */ 4047 */
4047 function replace(root, emoticons, emoticonsCompat) { 4048 function doReplaceEmoticons(root, emoticons, emoticonsCompat) {
4048 var doc = root.ownerDocument; 4049 var doc = root.ownerDocument;
4049 var space = '(^|\\s|\xA0|\u2002|\u2003|\u2009|$)'; 4050 var space = '(^|\\s|\xA0|\u2002|\u2003|\u2009|$)';
4050 var emoticonCodes = []; 4051 var emoticonCodes = [];
4051 var emoticonRegex = {}; 4052 var emoticonRegex = {};
4052 4053
4250 * The editors locale 4251 * The editors locale
4251 * 4252 *
4252 * @private 4253 * @private
4253 */ 4254 */
4254 var locale; 4255 var locale;
4255
4256 /**
4257 * Stores a cache of preloaded images
4258 *
4259 * @private
4260 * @type {Array.<HTMLImageElement>}
4261 */
4262 var preLoadCache = [];
4263 4256
4264 /** 4257 /**
4265 * The editors rangeHelper instance 4258 * The editors rangeHelper instance
4266 * 4259 *
4267 * @type {RangeHelper} 4260 * @type {RangeHelper}
4996 key: key, 4989 key: key,
4997 // Prefix emoticon root to emoticon urls 4990 // Prefix emoticon root to emoticon urls
4998 url: root + (url.url || url), 4991 url: root + (url.url || url),
4999 tooltip: url.tooltip || key 4992 tooltip: url.tooltip || key
5000 }); 4993 });
5001
5002 // Preload the emoticon
5003 if (options.emoticonsEnabled) {
5004 preLoadCache.push(createElement('img', {
5005 src: root + (url.url || url)
5006 }));
5007 }
5008 }); 4994 });
5009 }; 4995 };
5010 4996
5011 /** 4997 /**
5012 * Autofocus the editor 4998 * Autofocus the editor
5096 5082
5097 wysiwygBody.contentEditable = !readOnly; 5083 wysiwygBody.contentEditable = !readOnly;
5098 sourceEditor.readonly = !readOnly; 5084 sourceEditor.readonly = !readOnly;
5099 5085
5100 updateToolBar(readOnly); 5086 updateToolBar(readOnly);
5101
5102 return base;
5103 }; 5087 };
5104 5088
5105 /** 5089 /**
5106 * Gets if the editor is in RTL mode 5090 * Gets if the editor is in RTL mode
5107 * 5091 *
5136 addClass(editorContainer, dir); 5120 addClass(editorContainer, dir);
5137 5121
5138 if (icons.rtl) { 5122 if (icons.rtl) {
5139 icons.rtl(rtl); 5123 icons.rtl(rtl);
5140 } 5124 }
5141
5142 return base;
5143 }; 5125 };
5144 5126
5145 /** 5127 /**
5146 * Updates the toolbar to disable/enable the appropriate buttons 5128 * Updates the toolbar to disable/enable the appropriate buttons
5147 * @private 5129 * @private
5191 if (!width$1 && width$1 !== 0) { 5173 if (!width$1 && width$1 !== 0) {
5192 return width(editorContainer); 5174 return width(editorContainer);
5193 } 5175 }
5194 5176
5195 base.dimensions(width$1, null, saveWidth); 5177 base.dimensions(width$1, null, saveWidth);
5196
5197 return base;
5198 }; 5178 };
5199 5179
5200 /** 5180 /**
5201 * Returns an object with the properties width and height 5181 * Returns an object with the properties width and height
5202 * which are the width and height of the editor in px. 5182 * which are the width and height of the editor in px.
5260 options.height = height$1; 5240 options.height = height$1;
5261 } 5241 }
5262 5242
5263 height(editorContainer, height$1); 5243 height(editorContainer, height$1);
5264 } 5244 }
5265
5266 return base;
5267 }; 5245 };
5268 5246
5269 /** 5247 /**
5270 * Gets the height of the editor in px 5248 * Gets the height of the editor in px
5271 * 5249 *
5305 if (!height$1 && height$1 !== 0) { 5283 if (!height$1 && height$1 !== 0) {
5306 return height(editorContainer); 5284 return height(editorContainer);
5307 } 5285 }
5308 5286
5309 base.dimensions(null, height$1, saveHeight); 5287 base.dimensions(null, height$1, saveHeight);
5310
5311 return base;
5312 }; 5288 };
5313 5289
5314 /** 5290 /**
5315 * Gets if the editor is maximised or not 5291 * Gets if the editor is maximised or not
5316 * 5292 *
5352 if (!maximize) { 5328 if (!maximize) {
5353 globalWin.scrollTo(0, maximizeScrollPosition); 5329 globalWin.scrollTo(0, maximizeScrollPosition);
5354 } 5330 }
5355 5331
5356 autoExpand(); 5332 autoExpand();
5357
5358 return base;
5359 }; 5333 };
5360 5334
5361 autoExpand = function () { 5335 autoExpand = function () {
5362 if (options.autoExpand) { 5336 if (options.autoExpand) {
5363 base.expandToContent(); 5337 base.expandToContent();
5818 if (base.inSourceMode()) { 5792 if (base.inSourceMode()) {
5819 base.sourceEditorInsertText(text, endText); 5793 base.sourceEditorInsertText(text, endText);
5820 } else { 5794 } else {
5821 base.wysiwygEditorInsertText(text, endText); 5795 base.wysiwygEditorInsertText(text, endText);
5822 } 5796 }
5823
5824 return base;
5825 }; 5797 };
5826 5798
5827 /** 5799 /**
5828 * Like wysiwygEditorInsertHtml but inserts text into the 5800 * Like wysiwygEditorInsertHtml but inserts text into the
5829 * source mode editor instead. 5801 * source mode editor instead.
5902 sourceEditor.focus(); 5874 sourceEditor.focus();
5903 5875
5904 if (position) { 5876 if (position) {
5905 sourceEditor.selectionStart = position.start; 5877 sourceEditor.selectionStart = position.start;
5906 sourceEditor.selectionEnd = position.end; 5878 sourceEditor.selectionEnd = position.end;
5907 5879 return;
5908 return base;
5909 } 5880 }
5910 5881
5911 return { 5882 return {
5912 start: sourceEditor.selectionStart, 5883 start: sourceEditor.selectionStart,
5913 end: sourceEditor.selectionEnd 5884 end: sourceEditor.selectionEnd
5958 5929
5959 base.setWysiwygEditorValue(val); 5930 base.setWysiwygEditorValue(val);
5960 } else { 5931 } else {
5961 base.setSourceEditorValue(val); 5932 base.setSourceEditorValue(val);
5962 } 5933 }
5963
5964 return base;
5965 }; 5934 };
5966 5935
5967 /** 5936 /**
5968 * Inserts HTML/BBCode into the editor 5937 * Inserts HTML/BBCode into the editor
5969 * 5938 *
6014 base.insert = function ( 5983 base.insert = function (
6015 start, end, filter, convertEmoticons, allowMixed 5984 start, end, filter, convertEmoticons, allowMixed
6016 ) { 5985 ) {
6017 if (base.inSourceMode()) { 5986 if (base.inSourceMode()) {
6018 base.sourceEditorInsertText(start, end); 5987 base.sourceEditorInsertText(start, end);
6019 return base; 5988 return;
6020 } 5989 }
6021 5990
6022 // Add the selection between start and end 5991 // Add the selection between start and end
6023 if (end) { 5992 if (end) {
6024 var html = rangeHelper.selectedHtml(); 5993 var html = rangeHelper.selectedHtml();
6041 .replace(/&gt;/g, '>') 6010 .replace(/&gt;/g, '>')
6042 .replace(/&amp;/g, '&'); 6011 .replace(/&amp;/g, '&');
6043 } 6012 }
6044 6013
6045 base.wysiwygEditorInsertHtml(start); 6014 base.wysiwygEditorInsertHtml(start);
6046
6047 return base;
6048 }; 6015 };
6049 6016
6050 /** 6017 /**
6051 * Gets the WYSIWYG editors HTML value. 6018 * Gets the WYSIWYG editors HTML value.
6052 * 6019 *
6149 if (!value) { 6116 if (!value) {
6150 value = '<p><br /></p>'; 6117 value = '<p><br /></p>';
6151 } 6118 }
6152 6119
6153 wysiwygBody.innerHTML = value; 6120 wysiwygBody.innerHTML = value;
6154 replaceEmoticons(); 6121 //replaceEmoticons();
6155 6122
6156 appendNewLine(); 6123 appendNewLine();
6157 triggerValueChanged(); 6124 triggerValueChanged();
6158 autoExpand(); 6125 autoExpand();
6159 }; 6126 };
6190 * with their emoticon images 6157 * with their emoticon images
6191 * @private 6158 * @private
6192 */ 6159 */
6193 replaceEmoticons = function () { 6160 replaceEmoticons = function () {
6194 if (options.emoticonsEnabled) { 6161 if (options.emoticonsEnabled) {
6195 replace(wysiwygBody, allEmoticons, options.emoticonsCompat); 6162 doReplaceEmoticons(wysiwygBody, allEmoticons, options.emoticonsCompat);
6196 } 6163 }
6197 }; 6164 };
6198 6165
6199 /** 6166 /**
6200 * If the editor is in source code mode 6167 * If the editor is in source code mode
6233 } 6200 }
6234 6201
6235 if ((inSourceMode && !enable) || (!inSourceMode && enable)) { 6202 if ((inSourceMode && !enable) || (!inSourceMode && enable)) {
6236 base.toggleSourceMode(); 6203 base.toggleSourceMode();
6237 } 6204 }
6238
6239 return base;
6240 }; 6205 };
6241 6206
6242 /** 6207 /**
6243 * Switches between the WYSIWYG and source modes 6208 * Switches between the WYSIWYG and source modes
6244 * 6209 *
6736 if (events[i] === 'valuechanged') { 6701 if (events[i] === 'valuechanged') {
6737 triggerValueChanged.hasHandler = true; 6702 triggerValueChanged.hasHandler = true;
6738 } 6703 }
6739 } 6704 }
6740 } 6705 }
6741
6742 return base;
6743 }; 6706 };
6744 6707
6745 /** 6708 /**
6746 * Unbinds an event that was bound using bind(). 6709 * Unbinds an event that was bound using bind().
6747 * 6710 *
6773 arrayRemove( 6736 arrayRemove(
6774 eventHandlers['scesrc' + events[i]] || [], handler); 6737 eventHandlers['scesrc' + events[i]] || [], handler);
6775 } 6738 }
6776 } 6739 }
6777 } 6740 }
6778
6779 return base;
6780 }; 6741 };
6781 6742
6782 /** 6743 /**
6783 * Blurs the editors input area 6744 * Blurs the editors input area
6784 * 6745 *
6808 } else if (!base.sourceMode()) { 6769 } else if (!base.sourceMode()) {
6809 wysiwygBody.blur(); 6770 wysiwygBody.blur();
6810 } else { 6771 } else {
6811 sourceEditor.blur(); 6772 sourceEditor.blur();
6812 } 6773 }
6813
6814 return base;
6815 }; 6774 };
6816 6775
6817 /** 6776 /**
6818 * Focuses the editors input area 6777 * Focuses the editors input area
6819 * 6778 *
6873 } else { 6832 } else {
6874 sourceEditor.focus(); 6833 sourceEditor.focus();
6875 } 6834 }
6876 6835
6877 updateActiveButtons(); 6836 updateActiveButtons();
6878
6879 return base;
6880 }; 6837 };
6881 6838
6882 /** 6839 /**
6883 * Adds a handler to the key down event 6840 * Adds a handler to the key down event
6884 * 6841 *
7096 7053
7097 offEvent(wysiwygBody, 'keypress', emoticonsKeyPress); 7054 offEvent(wysiwygBody, 'keypress', emoticonsKeyPress);
7098 7055
7099 triggerValueChanged(); 7056 triggerValueChanged();
7100 } 7057 }
7101
7102 return base;
7103 }; 7058 };
7104 7059
7105 /** 7060 /**
7106 * Gets the current WYSIWYG editors inline CSS 7061 * Gets the current WYSIWYG editors inline CSS
7107 * 7062 *
7138 if (inlineCss.styleSheet) { 7093 if (inlineCss.styleSheet) {
7139 inlineCss.styleSheet.cssText = css; 7094 inlineCss.styleSheet.cssText = css;
7140 } else { 7095 } else {
7141 inlineCss.innerHTML = css; 7096 inlineCss.innerHTML = css;
7142 } 7097 }
7143
7144 return base;
7145 }; 7098 };
7146 7099
7147 /** 7100 /**
7148 * Handles the keydown event, used for shortcuts 7101 * Handles the keydown event, used for shortcuts
7149 * @private 7102 * @private
7303 }; 7256 };
7304 } else { 7257 } else {
7305 shortcutHandlers[shortcut] = cmd; 7258 shortcutHandlers[shortcut] = cmd;
7306 } 7259 }
7307 7260
7308 return base; 7261 return true;
7309 }; 7262 };
7310 7263
7311 /** 7264 /**
7312 * Removes a shortcut handler 7265 * Removes a shortcut handler
7313 * @param {string} shortcut 7266 * @param {string} shortcut
7314 * @return {sceditor} 7267 * @return {sceditor}
7315 */ 7268 */
7316 base.removeShortcut = function (shortcut) { 7269 base.removeShortcut = function (shortcut) {
7317 delete shortcutHandlers[shortcut.toLowerCase()]; 7270 delete shortcutHandlers[shortcut.toLowerCase()];
7318
7319 return base;
7320 }; 7271 };
7321 7272
7322 /** 7273 /**
7323 * Handles the backspace key press 7274 * Handles the backspace key press
7324 * 7275 *
7390 */ 7341 */
7391 base.clearBlockFormatting = function (block) { 7342 base.clearBlockFormatting = function (block) {
7392 block = block || currentStyledBlockNode(); 7343 block = block || currentStyledBlockNode();
7393 7344
7394 if (!block || is(block, 'body')) { 7345 if (!block || is(block, 'body')) {
7395 return base; 7346 return;
7396 } 7347 }
7397 7348
7398 rangeHelper.saveRange(); 7349 rangeHelper.saveRange();
7399 7350
7400 block.className = ''; 7351 block.className = '';
7404 if (!is(block, 'p,div,td')) { 7355 if (!is(block, 'p,div,td')) {
7405 convertElement(block, 'p'); 7356 convertElement(block, 'p');
7406 } 7357 }
7407 7358
7408 rangeHelper.restoreRange(); 7359 rangeHelper.restoreRange();
7409 return base;
7410 }; 7360 };
7411 7361
7412 /** 7362 /**
7413 * Triggers the valueChanged signal if there is 7363 * Triggers the valueChanged signal if there is
7414 * a plugin that handles it. 7364 * a plugin that handles it.
7538 base.updateOriginal(); 7488 base.updateOriginal();
7539 }; 7489 };
7540 7490
7541 // run the initializer 7491 // run the initializer
7542 init(); 7492 init();
7493
7494 base.allEmoticons = allEmoticons;
7543 7495
7544 return base; 7496 return base;
7545 } 7497 }
7546 7498
7547 /** 7499 /**