File: src/sm-editor/js/extensions/editor-link.js
- /*jshint expr:true, onevar:false */
-
- /**
- Provides the `Editor.Link` extension.
-
- @module gallery-sm-editor
- @submodule gallery-sm-editor-link
- **/
-
- /**
- Extension for `Editor.Base` that enables inserting links
-
- Provides support for the following commands:
-
- - createLink
- - unlink
-
- @class Editor.Link
- @extends Base
- @extensionfor Editor.Base
- **/
-
- (function() {
- var EditorLink = Y.Base.create('editorLink', Y.Base, [], {
- // -- Public Properties ----------------------------------------------------
-
- /**
- Hash of link commands supported by this editor.
-
- Names should correspond with valid `execCommand()` command names. Values
- are properties in the following format:
-
- @property {Object} linkCommands
- @param {Function|String} commandFn
- @param {Function|String} [queryFn]
- **/
- linkCommands: {
- createLink: {
- commandFn: '_createLink',
- queryFn: 'isLink'
- },
-
- unlink: {
- commandFn: '_unlink',
- queryFn: 'isLink'
- }
- },
-
- /**
- HTML tags supported by this editor. Unsupported tags will be treated
- as text
-
- @property {String} supportedTags
- **/
- linkTags: 'a',
-
- /**
- HTML Template for building an anchor node
-
- @property {Object} linkTemplate
- **/
- linkTemplate: '<a href="{href}" target="{target}"></a>',
-
-
- // -- Lifecycle ------------------------------------------------------------
-
- initializer: function () {
- this.commands = Y.merge(this.commands, this.linkCommands);
-
- if (this.supportedTags) {
- this.supportedTags += ',' + this.linkTags;
- } else {
- this.supportedTags = this.linkTags;
- }
- },
-
-
- // -- Public Methods -------------------------------------------------------
-
- /**
- Returns whether or not the current range is entirely in an anchor element
-
- @method isLink
- @return {boolean} `true` if the range is contained in an anchor element,
- `false` otherwise
- **/
- isLink: function () {
- return !!this._getAnchorNode();
- },
-
-
- // -- Protected Methods ----------------------------------------------------
-
- /**
- Returns the nearest ancestor anchor that entirely contains
- the current range
-
- @method _getAnchorNode
- @return {Node} The containing anchor element
- @protected
- **/
- _getAnchorNode: function() {
- this.focus();
-
- var parentNode = this.selection.range().shrink().parentNode();
-
- return parentNode.ancestor(this.linkTags, true);
- },
-
-
- /**
- Implementation for the `createLink` command
-
- Wraps the currently selected range in an anchor `<a>` tag
-
- @method _createLink
- @param {Object} options
- @param {String} options.href
- @param {String} [options.target=_self]
- @param {String} [options.text]
- @protected
- **/
- _createLink: function(options){
- var range = this.selection.range(),
- anchorNode, styleNodes;
-
- if (!range) {
- return;
- }
-
- if (this.isLink()) {
- this._unlink();
- range = this.selection.range();
- }
-
- options || (options = {});
- options.href = encodeURI(options.href || '');
- options.target = encodeURIComponent(options.target || '_self');
-
- anchorNode = Y.Node.create(Y.Lang.sub(this.linkTemplate, options));
- styleNodes = this._getStyleNodes(range);
-
- anchorNode.append(styleNodes);
-
- range.insertNode(anchorNode);
-
- if (options.text && options.text !== range.toString()) {
- var firstChild = anchorNode.get('firstChild');
-
- if (this._isStyleNode(firstChild)) {
- firstChild.set('text', options.text);
- anchorNode.setHTML(firstChild);
- } else {
- anchorNode.set('text', options.text);
- }
- }
-
- range.selectNode(anchorNode).collapse();
-
- this.selection.select(range);
- },
-
-
- /**
- Removes link by replacing the anchor element with the child nodes
- of the anchor
-
- The anchor element will be removed from the DOM and destroyed.
-
- @method _unlink
- @protected
- **/
- _unlink: function() {
- var selection = this.selection,
- anchorNode;
-
- // we can use the native unlink command once we have bookmarking
- // in place, but firefox selects adjacent text nodes after unlink
-
- if (anchorNode = this._getAnchorNode()) {
- var firstChild = anchorNode.get('firstChild'),
- lastChild = anchorNode.get('lastChild'),
- range = selection.range();
-
- // only need to unwrap one of the children to unwrap the
- // whole anchorNode
- firstChild.unwrap();
-
- anchorNode.destroy();
-
- range.startNode(firstChild, 0);
- range.endNode(lastChild, 'after');
-
- selection.select(range.shrink({trim: true}));
- }
- }
- });
-
- Y.namespace('Editor').Link = EditorLink;
-
- }());
-
-