/** * plugin.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /*global tinymce:true */ tinymce.PluginManager.add('link', function(editor) { function createLinkList(callback) { return function() { var linkList = editor.settings.link_list; if (typeof(linkList) == "string") { tinymce.util.XHR.send({ url: linkList, success: function(text) { callback(tinymce.util.JSON.parse(text)); } }); } else { callback(linkList); } }; } function showDialog(linkList) { var data = {}, selection = editor.selection, dom = editor.dom, selectedElm, anchorElm, initialText; var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, classListCtrl; function linkListChangeHandler(e) { var textCtrl = win.find('#text'); if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) { textCtrl.value(e.control.text()); } win.find('#href').value(e.control.value()); } function buildLinkList() { var linkListItems = [{text: 'None', value: ''}]; tinymce.each(linkList, function(link) { linkListItems.push({ text: link.text || link.title, value: editor.convertURL(link.value || link.url, 'href'), menu: link.menu }); }); return linkListItems; } function buildValues(listSettingName, dataItemName, defaultItems) { var selectedItem, items = []; tinymce.each(editor.settings[listSettingName] || defaultItems, function(target) { var item = { text: target.text || target.title, value: target.value }; items.push(item); if (data[dataItemName] === target.value || (!selectedItem && target.selected)) { selectedItem = item; } }); if (selectedItem && !data[dataItemName]) { data[dataItemName] = selectedItem.value; selectedItem.selected = true; } return items; } function buildAnchorListControl(url) { var anchorList = []; tinymce.each(editor.dom.select('a:not([href])'), function(anchor) { var id = anchor.name || anchor.id; if (id) { anchorList.push({ text: id, value: '#' + id, selected: url.indexOf('#' + id) != -1 }); } }); if (anchorList.length) { anchorList.unshift({text: 'None', value: ''}); return { name: 'anchor', type: 'listbox', label: 'Anchors', values: anchorList, onselect: linkListChangeHandler }; } } function urlChange() { if (linkListCtrl) { linkListCtrl.value(editor.convertURL(this.value(), 'href')); } if (!initialText && data.text.length === 0 && onlyText) { this.parent().parent().find('#text')[0].value(this.value()); } } function isOnlyTextSelected(anchorElm) { var html = selection.getContent(); // Partial html and not a fully selected anchor element if (/]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') == -1)) { return false; } if (anchorElm) { var nodes = anchorElm.childNodes, i; if (nodes.length === 0) { return false; } for (i = nodes.length - 1; i >= 0; i--) { if (nodes[i].nodeType != 3) { return false; } } } return true; } selectedElm = selection.getNode(); anchorElm = dom.getParent(selectedElm, 'a[href]'); onlyText = isOnlyTextSelected(); data.text = initialText = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({format: 'text'}); data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : ''; data.target = anchorElm ? dom.getAttrib(anchorElm, 'target') : (editor.settings.default_link_target || null); data.rel = anchorElm ? dom.getAttrib(anchorElm, 'rel') : null; data['class'] = anchorElm ? dom.getAttrib(anchorElm, 'class') : null; if (onlyText) { textListCtrl = { name: 'text', type: 'textbox', size: 40, label: 'Text to display', onchange: function() { data.text = this.value(); } }; } if (linkList) { linkListCtrl = { type: 'listbox', label: 'Link list', values: buildLinkList(), onselect: linkListChangeHandler, value: editor.convertURL(data.href, 'href'), onPostRender: function() { linkListCtrl = this; } }; } if (editor.settings.target_list !== false) { targetListCtrl = { name: 'target', type: 'listbox', label: 'Target', values: buildValues('target_list', 'target', [{text: 'None', value: ''}, {text: 'New window', value: '_blank'}]) }; } if (editor.settings.rel_list) { relListCtrl = { name: 'rel', type: 'listbox', label: 'Rel', values: buildValues('rel_list', 'rel', [{text: 'None', value: ''}]) }; } if (editor.settings.link_class_list) { classListCtrl = { name: 'class', type: 'listbox', label: 'Class', values: buildValues('link_class_list', 'class') }; } win = editor.windowManager.open({ title: 'Insert link', data: data, body: [ { name: 'href', type: 'filepicker', filetype: 'file', size: 40, autofocus: true, label: 'Url', onchange: urlChange, onkeyup: urlChange }, textListCtrl, buildAnchorListControl(data.href), linkListCtrl, relListCtrl, targetListCtrl, classListCtrl ], onSubmit: function(e) { var href; data = tinymce.extend(data, e.data); href = data.href; // Delay confirm since onSubmit will move focus function delayedConfirm(message, callback) { var rng = editor.selection.getRng(); window.setTimeout(function() { editor.windowManager.confirm(message, function(state) { editor.selection.setRng(rng); callback(state); }); }, 0); } function insertLink() { if (anchorElm) { editor.focus(); if (onlyText && data.text != initialText) { anchorElm.innerText = data.text; } dom.setAttribs(anchorElm, { href: href, target: data.target ? data.target : null, rel: data.rel ? data.rel : null, "class": data["class"] ? data["class"] : null }); selection.select(anchorElm); editor.undoManager.add(); } else { if (onlyText) { editor.insertContent(dom.createHTML('a', { href: href, target: data.target ? data.target : null, rel: data.rel ? data.rel : null, "class": data["class"] ? data["class"] : null }, dom.encode(data.text))); } else { editor.execCommand('mceInsertLink', false, { href: href, target: data.target, rel: data.rel ? data.rel : null }); } } } if (!href) { editor.execCommand('unlink'); return; } // Is email and not //user@domain.com if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) { delayedConfirm( 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?', function(state) { if (state) { href = 'mailto:' + href; } insertLink(); } ); return; } // Is www. prefixed if (/^\s*www\./i.test(href)) { delayedConfirm( 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?', function(state) { if (state) { href = 'http://' + href; } insertLink(); } ); return; } insertLink(); } }); } editor.addButton('link', { icon: 'link', tooltip: 'Insert/edit link', shortcut: 'Ctrl+K', onclick: createLinkList(showDialog), stateSelector: 'a[href]' }); editor.addButton('unlink', { icon: 'unlink', tooltip: 'Remove link', cmd: 'unlink', stateSelector: 'a[href]' }); editor.addShortcut('Ctrl+K', '', createLinkList(showDialog)); this.showDialog = showDialog; editor.addMenuItem('link', { icon: 'link', text: 'Insert link', shortcut: 'Ctrl+K', onclick: createLinkList(showDialog), stateSelector: 'a[href]', context: 'insert', prependToContext: true }); });