tinymce.PluginManager.add('smileys', function (editor, url) { /*var defaultSmileys = [ [ { shortcut: '(^^^)', url: url + '/img/shark.gif', title: 'shark' }, { shortcut: 'O:)', url: url + '/img/angel.png', title: 'angel' }, { shortcut: 'o.O', url: url + '/img/confused.png', title: 'confused' }, { shortcut: '3:)', url: url + '/img/devil.png', title: 'devil' }, { shortcut: ':-O', url: url + '/img/gasp.png', title: 'gasp' }, { shortcut: '8-)', url: url + '/img/glasses.png', title: 'glasses' }, { shortcut: ':-D', url: url + '/img/grin.png', title: 'grin' } ], [ { shortcut: ':-)', url: url + '/img/smile.png', title: 'smile' }, { shortcut: ":'(", url: url + '/img/cry.png', title: 'cry' }, { shortcut: '<3', url: url + '/img/heart.png', title: 'heart' }, { shortcut: '^_^', url: url + '/img/kiki.png', title: 'kiki' }, { shortcut: ':-*', url: url + '/img/kiss.png', title: 'kiss' }, { shortcut: ':v', url: url + '/img/pacman.png', title: 'pacman' }, { shortcut: '<(�)', url: url + '/img/penguin.gif', title: 'penguin' } ], [ { shortcut: ':|]', url: url + '/img/robot.gif', title: 'robot' }, { shortcut: '-_-', url: url + '/img/squint.png', title: 'squint' }, { shortcut: '8-|', url: url + '/img/sunglasses.png', title: 'sunglasses' }, { shortcut: ':-P', url: url + '/img/tongue.png', title: 'tongue' }, { shortcut: ':/', url: url + '/img/unsure.png', title: 'unsure' }, { shortcut: '>:O', url: url + '/img/upset.png', title: 'upset' }, { shortcut: '>:(', url: url + '/img/grumpy.png', title: 'grumpy' } ] ];*/ var defaultSmileys = []; var smileys = editor.settings.smileys || defaultSmileys, fullSmileysList = editor.settings.extended_smileys ? smileys.concat(editor.settings.extended_smileys) : smileys; function getHtml() { var smileysHtml; smileysHtml = ''; tinymce.each(fullSmileysList, function (row) { smileysHtml += ''; tinymce.each(row, function (icon) { smileysHtml += ''; }); smileysHtml += ''; }); smileysHtml += ''; return smileysHtml; } function concatArray(array) { var each = tinymce.each, result = []; each(array, function (item) { result = result.concat(item); }); return result.length > 0 ? result : array; } function findAndReplaceDOMText(regex, node, replacementNode, captureGroup, schema) { var m, matches = [], text, count = 0, doc; var blockElementsMap, hiddenTextElementsMap, shortEndedElementsMap; doc = node.ownerDocument; blockElementsMap = schema.getBlockElements(); // H1-H6, P, TD etc hiddenTextElementsMap = schema.getWhiteSpaceElements(); // TEXTAREA, PRE, STYLE, SCRIPT shortEndedElementsMap = schema.getShortEndedElements(); // BR, IMG, INPUT function getMatchIndexes(m, captureGroup) { captureGroup = captureGroup || 0; var index = m.index; if (captureGroup > 0) { var cg = m[captureGroup]; index += m[0].indexOf(cg); m[0] = cg; } return [index, index + m[0].length, [m[0]]]; } function getText(node) { var txt; if (node.nodeType === 3) { return node.data; } if (hiddenTextElementsMap[node.nodeName] && !blockElementsMap[node.nodeName]) { return ''; } txt = ''; if (blockElementsMap[node.nodeName] || shortEndedElementsMap[node.nodeName]) { txt += '\n'; } if ((node = node.firstChild)) { do { txt += getText(node); } while ((node = node.nextSibling)); } return txt; } function stepThroughMatches(node, matches, replaceFn) { var startNode, endNode, startNodeIndex, endNodeIndex, innerNodes = [], atIndex = 0, curNode = node, matchLocation = matches.shift(), matchIndex = 0; out: while (true) { if (blockElementsMap[curNode.nodeName] || shortEndedElementsMap[curNode.nodeName]) { atIndex++; } if (curNode.nodeType === 3) { if (!endNode && curNode.length + atIndex >= matchLocation[1]) { // We've found the ending endNode = curNode; endNodeIndex = matchLocation[1] - atIndex; } else if (startNode) { // Intersecting node innerNodes.push(curNode); } if (!startNode && curNode.length + atIndex > matchLocation[0]) { // We've found the match start startNode = curNode; startNodeIndex = matchLocation[0] - atIndex; } atIndex += curNode.length; } if (startNode && endNode) { curNode = replaceFn({ startNode: startNode, startNodeIndex: startNodeIndex, endNode: endNode, endNodeIndex: endNodeIndex, innerNodes: innerNodes, match: matchLocation[2], matchIndex: matchIndex }); // replaceFn has to return the node that replaced the endNode // and then we step back so we can continue from the end of the // match: atIndex -= (endNode.length - endNodeIndex); startNode = null; endNode = null; innerNodes = []; matchLocation = matches.shift(); matchIndex++; if (!matchLocation) { break; // no more matches } } else if ((!hiddenTextElementsMap[curNode.nodeName] || blockElementsMap[curNode.nodeName]) && curNode.firstChild) { // Move down curNode = curNode.firstChild; continue; } else if (curNode.nextSibling) { // Move forward: curNode = curNode.nextSibling; continue; } // Move forward or up: while (true) { if (curNode.nextSibling) { curNode = curNode.nextSibling; break; } else if (curNode.parentNode !== node) { curNode = curNode.parentNode; } else { break out; } } } } /** * Generates the actual replaceFn which splits up text nodes * and inserts the replacement element. */ function genReplacer(nodeName) { var makeReplacementNode; if (typeof nodeName != 'function') { var stencilNode = nodeName.nodeType ? nodeName : doc.createElement(nodeName); makeReplacementNode = function () { var clone = stencilNode.cloneNode(false); return clone; }; } else { makeReplacementNode = nodeName; } return function replace(range) { var before, after, parentNode, startNode = range.startNode, endNode = range.endNode; if (startNode === endNode) { var node = startNode; parentNode = node.parentNode; if (range.startNodeIndex > 0) { // Add `before` text node (before the match) before = doc.createTextNode(node.data.substring(0, range.startNodeIndex)); parentNode.insertBefore(before, node); } // Create the replacement node: var el = makeReplacementNode(); parentNode.insertBefore(el, node); if (range.endNodeIndex < node.length) { // Add `after` text node (after the match) after = doc.createTextNode(node.data.substring(range.endNodeIndex)); parentNode.insertBefore(after, node); } node.parentNode.removeChild(node); return el; } }; } text = getText(node); if (!text) { return; } while ((m = regex.exec(text))) { matches.push(getMatchIndexes(m, captureGroup)); } if (matches.length) { count = matches.length; stepThroughMatches(node, matches, genReplacer(replacementNode)); } return count; } function replaceAllMatches(smiley) { var each = tinymce.each, node = editor.selection.getNode(), marker, text; if (typeof (smiley.shortcut) === 'string') { text = smiley.shortcut.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); marker = editor.dom.create('img', { "src": smiley.url, "title": smiley.title }); return findAndReplaceDOMText(new RegExp(text, 'gi'), node, marker, false, editor.schema); } else if (Array.isArray(smiley.shortcut)) { each(smiley.shortcut, function(item) { marker = editor.dom.create('img', { "src": smiley.url, "title": smiley.title }); return findAndReplaceDOMText(new RegExp(item.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), 'gi'), node, marker, false, editor.schema); }); } } editor.on("keyup", function (e) { if (!!editor.settings.auto_convert_smileys) { var each = tinymce.each, selection = editor.selection, node = selection.getNode(); if (node) { each(concatArray(fullSmileysList), function (smiley) { replaceAllMatches(smiley); }); } } }); editor.addButton('smileys', { type: 'panelbutton', icon: 'emoticons', panel: { autohide: true, html: getHtml, onclick: function (e) { var linkElm = editor.dom.getParent(e.target, 'a'); if (linkElm) { editor.insertContent(''); this.hide(); } } }, tooltip: 'Smileys' }); });