### @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.md or http://ckeditor.com/license ### CKEDITOR.plugins.add "adv_link", requires: "dialog,fakeobjects" lang: "en,es,fr,it" # %REMOVE_LINE_CORE% icons: "anchor,anchor-rtl,link,unlink" # %REMOVE_LINE_CORE% hidpi: true # %REMOVE_LINE_CORE% onLoad: -> cssWithDir = (dir) -> template.replace(/%1/g, (if dir is "rtl" then "right" else "left")).replace /%2/g, "cke_contents_" + dir iconPath = CKEDITOR.getUrl(@path + "images" + ((if CKEDITOR.env.hidpi then "/hidpi" else "")) + "/anchor.png") baseStyle = "background:url(" + iconPath + ") no-repeat %1 center;border:1px dotted #00f;background-size:16px;" template = ".%2 a.cke_anchor," + ".%2 a.cke_anchor_empty" + ",.cke_editable.%2 a[name]" + ",.cke_editable.%2 a[data-cke-saved-name]" + "{" + baseStyle + "padding-%1:18px;" + "cursor:auto;" + "}" + ((if CKEDITOR.env.ie then ("a.cke_anchor_empty" + "{" + "display:inline-block;" + "}") else "")) + ".%2 img.cke_anchor" + "{" + baseStyle + "width:16px;" + "min-height:15px;" + "height:1.15em;" + "vertical-align:" + ((if CKEDITOR.env.opera then "middle" else "text-bottom")) + ";" + "}" CKEDITOR.addCss cssWithDir("ltr") + cssWithDir("rtl") return init: (editor) -> allowed = "a[!href]" required = "a[href]" allowed = allowed.replace("]", ",accesskey,charset,dir,id,lang,name,rel,tabindex,title,type]{*}(*)") if CKEDITOR.dialog.isTabEnabled(editor, "link", "advanced") allowed = allowed.replace("]", ",target,onclick]") if CKEDITOR.dialog.isTabEnabled(editor, "link", "target") # Add the link and unlink buttons. editor.addCommand "link", new CKEDITOR.dialogCommand("link", allowedContent: allowed requiredContent: required ) editor.addCommand "anchor", new CKEDITOR.dialogCommand("anchor", allowedContent: "a[!name,id]" requiredContent: "a[name]" ) editor.addCommand "unlink", new CKEDITOR.unlinkCommand() editor.addCommand "removeAnchor", new CKEDITOR.removeAnchorCommand() editor.setKeystroke CKEDITOR.CTRL + 76, "link" #L if editor.ui.addButton editor.ui.addButton "Link", label: editor.lang.link.toolbar command: "link" toolbar: "links,10" editor.ui.addButton "Unlink", label: editor.lang.link.unlink command: "unlink" toolbar: "links,20" editor.ui.addButton "Anchor", label: editor.lang.link.anchor.toolbar command: "anchor" toolbar: "links,30" CKEDITOR.dialog.add "link", @path + "dialogs/link.js" CKEDITOR.dialog.add "anchor", @path + "dialogs/anchor.js" editor.on "doubleclick", (evt) -> element = CKEDITOR.plugins.link.getSelectedLink(editor) or evt.data.element unless element.isReadOnly() if element.is("a") evt.data.dialog = (if (element.getAttribute("name") and (not element.getAttribute("href") or not element.getChildCount())) then "anchor" else "link") editor.getSelection().selectElement element else evt.data.dialog = "anchor" if CKEDITOR.plugins.link.tryRestoreFakeAnchor(editor, element) return # If the "menu" plugin is loaded, register the menu items. if editor.addMenuItems editor.addMenuItems anchor: label: editor.lang.link.anchor.menu command: "anchor" group: "anchor" order: 1 removeAnchor: label: editor.lang.link.anchor.remove command: "removeAnchor" group: "anchor" order: 5 link: label: editor.lang.link.menu command: "link" group: "link" order: 1 unlink: label: editor.lang.link.unlink command: "unlink" group: "link" order: 5 # If the "contextmenu" plugin is loaded, register the listeners. if editor.contextMenu editor.contextMenu.addListener (element, selection) -> return null if not element or element.isReadOnly() anchor = CKEDITOR.plugins.link.tryRestoreFakeAnchor(editor, element) return null if not anchor and not (anchor = CKEDITOR.plugins.link.getSelectedLink(editor)) menu = {} if anchor.getAttribute("href") and anchor.getChildCount() menu = link: CKEDITOR.TRISTATE_OFF unlink: CKEDITOR.TRISTATE_OFF menu.anchor = menu.removeAnchor = CKEDITOR.TRISTATE_OFF if anchor and anchor.hasAttribute("name") menu return afterInit: (editor) -> # Register a filter to displaying placeholders after mode change. dataProcessor = editor.dataProcessor dataFilter = dataProcessor and dataProcessor.dataFilter htmlFilter = dataProcessor and dataProcessor.htmlFilter pathFilters = editor._.elementsPath and editor._.elementsPath.filters if dataFilter dataFilter.addRules elements: a: (element) -> attributes = element.attributes return null unless attributes.name isEmpty = not element.children.length if CKEDITOR.plugins.link.synAnchorSelector # IE needs a specific class name to be applied # to the anchors, for appropriate styling. ieClass = (if isEmpty then "cke_anchor_empty" else "cke_anchor") cls = attributes["class"] attributes["class"] = (cls or "") + " " + ieClass if attributes.name and (not cls or cls.indexOf(ieClass) < 0) if isEmpty and CKEDITOR.plugins.link.emptyAnchorFix attributes.contenteditable = "false" attributes["data-cke-editable"] = 1 else return editor.createFakeParserElement(element, "cke_anchor", "anchor") if CKEDITOR.plugins.link.fakeAnchor and isEmpty null if CKEDITOR.plugins.link.emptyAnchorFix and htmlFilter htmlFilter.addRules elements: a: (element) -> delete element.attributes.contenteditable return if pathFilters pathFilters.push (element, name) -> "anchor" if CKEDITOR.plugins.link.tryRestoreFakeAnchor(editor, element) or (element.getAttribute("name") and (not element.getAttribute("href") or not element.getChildCount())) if name is "a" return ### Set of link plugin's helpers. @class @singleton ### CKEDITOR.plugins.link = ### Get the surrounding link element of current selection. CKEDITOR.plugins.link.getSelectedLink( editor ); // The following selection will all return the link element. li^nk [link] text[link] li[nk] [li]nk] [li]nk @since 3.2.1 @param {CKEDITOR.editor} editor ### getSelectedLink: (editor) -> selection = editor.getSelection() selectedElement = selection.getSelectedElement() return selectedElement if selectedElement and selectedElement.is("a") range = selection.getRanges(true)[0] if range range.shrink CKEDITOR.SHRINK_TEXT return editor.elementPath(range.getCommonAncestor()).contains("a", 1) null ### Opera and WebKit don't make it possible to select empty anchors. Fake elements must be used for them. @readonly @property {Boolean} ### fakeAnchor: CKEDITOR.env.opera or CKEDITOR.env.webkit ### For browsers that don't support CSS3 `a[name]:empty()`, note IE9 is included because of #7783. @readonly @property {Boolean} ### synAnchorSelector: CKEDITOR.env.ie ### For browsers that have editing issue with empty anchor. @readonly @property {Boolean} ### emptyAnchorFix: CKEDITOR.env.ie and CKEDITOR.env.version < 8 ### @param {CKEDITOR.editor} editor @param {CKEDITOR.dom.element} element @todo ### tryRestoreFakeAnchor: (editor, element) -> if element and element.data("cke-real-element-type") and element.data("cke-real-element-type") is "anchor" link = editor.restoreRealElement(element) link if link.data("cke-saved-name") # TODO Much probably there's no need to expose these as public objects. CKEDITOR.unlinkCommand = -> CKEDITOR.unlinkCommand:: = exec: (editor) -> style = new CKEDITOR.style( element: "a" type: CKEDITOR.STYLE_INLINE alwaysRemoveElement: 1 ) editor.removeStyle style return refresh: (editor, path) -> # Despite our initial hope, document.queryCommandEnabled() does not work # for this in Firefox. So we must detect the state by element paths. element = path.lastElement and path.lastElement.getAscendant("a", true) if element and element.getName() is "a" and element.getAttribute("href") and element.getChildCount() @setState CKEDITOR.TRISTATE_OFF else @setState CKEDITOR.TRISTATE_DISABLED return contextSensitive: 1 startDisabled: 1 requiredContent: "a[href]" CKEDITOR.removeAnchorCommand = -> CKEDITOR.removeAnchorCommand:: = exec: (editor) -> sel = editor.getSelection() bms = sel.createBookmarks() anchor = undefined if sel and (anchor = sel.getSelectedElement()) and ((if CKEDITOR.plugins.link.fakeAnchor and not anchor.getChildCount() then CKEDITOR.plugins.link.tryRestoreFakeAnchor(editor, anchor) else anchor.is("a"))) anchor.remove 1 else if anchor = CKEDITOR.plugins.link.getSelectedLink(editor) if anchor.hasAttribute("href") anchor.removeAttributes name: 1 "data-cke-saved-name": 1 anchor.removeClass "cke_anchor" else anchor.remove 1 sel.selectBookmarks bms return requiredContent: "a[name]" CKEDITOR.tools.extend CKEDITOR.config, ### @cfg {Boolean} [linkShowAdvancedTab=true] @member CKEDITOR.config @todo ### linkShowAdvancedTab: true ### @cfg {Boolean} [linkShowTargetTab=true] @member CKEDITOR.config @todo ### linkShowTargetTab: true