Version 3.18.1

APIs

  • Begin typing in the search box above to see results.
Show:

File: editor/js/exec-command.js

 
 /**
 * Plugin for the frame module to handle execCommands for Editor
 * @class Plugin.ExecCommand
 * @extends Base
 * @constructor
 * @module editor
 * @submodule exec-command
 */
 var ExecCommand = function() {
 ExecCommand.superclass.constructor.apply(this, arguments);
 },
 /**
 * This method is meant to normalize IE's in ability to exec the proper command on elements with CSS styling.
 * @method fixIETags
 * @protected
 * @param {String} cmd The command to execute
 * @param {String} tag The tag to create
 * @param {String} rule The rule that we are looking for.
 */
 fixIETags = function(cmd, tag, rule) {
 var inst = this.getInstance(),
 doc = inst.config.doc,
 sel = doc.selection.createRange(),
 o = doc.queryCommandValue(cmd),
 html, reg, m, p, d, s, c;
 
 if (o) {
 html = sel.htmlText;
 reg = new RegExp(rule, 'g');
 m = html.match(reg);
 
 if (m) {
 html = html.replace(rule + ';', '').replace(rule, '');
 
 sel.pasteHTML('<var id="yui-ie-bs">');
 
 p = doc.getElementById('yui-ie-bs');
 d = doc.createElement('div');
 s = doc.createElement(tag);
 
 d.innerHTML = html;
 if (p.parentNode !== inst.config.doc.body) {
 p = p.parentNode;
 }
 
 c = d.childNodes;
 
 p.parentNode.replaceChild(s, p);
 
 Y.each(c, function(f) {
 s.appendChild(f);
 });
 sel.collapse();
 if (sel.moveToElementText) {
 sel.moveToElementText(s);
 }
 sel.select();
 }
 }
 this._command(cmd);
 };
 
 Y.extend(ExecCommand, Y.Base, {
 /**
 * An internal reference to the keyCode of the last key that was pressed.
 * @private
 * @property _lastKey
 */
 _lastKey: null,
 /**
 * An internal reference to the instance of the frame plugged into.
 * @private
 * @property _inst
 */
 _inst: null,
 /**
 * Execute a command on the frame's document.
 * @method command
 * @param {String} action The action to perform (bold, italic, fontname)
 * @param {String} value The optional value (helvetica)
 * @return {Node/NodeList} Should return the Node/Nodelist affected
 */
 command: function(action, value) {
 var fn = ExecCommand.COMMANDS[action];
 
 Y.log('execCommand(' + action + '): "' + value + '"', 'info', 'exec-command');
 if (fn) {
 Y.log('OVERIDE execCommand(' + action + '): "' + value + '"', 'info', 'exec-command');
 return fn.call(this, action, value);
 } else {
 return this._command(action, value);
 }
 },
 /**
 * The private version of execCommand that doesn't filter for overrides.
 * @private
 * @method _command
 * @param {String} action The action to perform (bold, italic, fontname)
 * @param {String} value The optional value (helvetica)
 */
 _command: function(action, value) {
 var inst = this.getInstance();
 try {
 try {
 inst.config.doc.execCommand('styleWithCSS', null, 1);
 } catch (e1) {
 try {
 inst.config.doc.execCommand('useCSS', null, 0);
 } catch (e2) {
 }
 }
 Y.log('Using default browser execCommand(' + action + '): "' + value + '"', 'info', 'exec-command');
 inst.config.doc.execCommand(action, null, value);
 } catch (e) {
 Y.log(e.message, 'warn', 'exec-command');
 }
 },
 /**
 * Get's the instance of YUI bound to the parent frame
 * @method getInstance
 * @return {YUI} The YUI instance bound to the parent frame
 */
 getInstance: function() {
 if (!this._inst) {
 this._inst = this.get('host').getInstance();
 }
 return this._inst;
 },
 initializer: function() {
 Y.mix(this.get('host'), {
 execCommand: function(action, value) {
 return this.exec.command(action, value);
 },
 _execCommand: function(action, value) {
 return this.exec._command(action, value);
 }
 });
 
 this.get('host').on('dom:keypress', Y.bind(function(e) {
 this._lastKey = e.keyCode;
 }, this));
 },
 _wrapContent: function(str, override) {
 var useP = (this.getInstance().host.editorPara && !override ? true : false);
 
 if (useP) {
 str = '<p>' + str + '</p>';
 } else {
 str = str + '<br>';
 }
 return str;
 }
 }, {
 /**
 * execCommand
 * @property NAME
 * @static
 */
 NAME: 'execCommand',
 /**
 * exec
 * @property NS
 * @static
 */
 NS: 'exec',
 ATTRS: {
 host: {
 value: false
 }
 },
 /**
 * Static object literal of execCommand overrides
 * @class Plugin.ExecCommand.COMMANDS
 * @static
 */
 COMMANDS: {
 /**
 * Wraps the content with a new element of type (tag)
 * @method wrap
 * @static
 * @param {String} cmd The command executed: wrap
 * @param {String} tag The tag to wrap the selection with
 * @return {NodeList} NodeList of the items touched by this command.
 */
 wrap: function(cmd, tag) {
 var inst = this.getInstance();
 return (new inst.EditorSelection()).wrapContent(tag);
 },
 /**
 * Inserts the provided HTML at the cursor, should be a single element.
 * @method inserthtml
 * @static
 * @param {String} cmd The command executed: inserthtml
 * @param {String} html The html to insert
 * @return {Node} Node instance of the item touched by this command.
 */
 inserthtml: function(cmd, html) {
 var inst = this.getInstance();
 if (inst.EditorSelection.hasCursor() || Y.UA.ie) {
 return (new inst.EditorSelection()).insertContent(html);
 } else {
 this._command('inserthtml', html);
 }
 },
 /**
 * Inserts the provided HTML at the cursor, and focuses the cursor afterwards.
 * @method insertandfocus
 * @static
 * @param {String} cmd The command executed: insertandfocus
 * @param {String} html The html to insert
 * @return {Node} Node instance of the item touched by this command.
 */
 insertandfocus: function(cmd, html) {
 var inst = this.getInstance(), out, sel;
 if (inst.EditorSelection.hasCursor()) {
 html += inst.EditorSelection.CURSOR;
 out = this.command('inserthtml', html);
 sel = new inst.EditorSelection();
 sel.focusCursor(true, true);
 } else {
 this.command('inserthtml', html);
 }
 return out;
 },
 /**
 * Inserts a BR at the current cursor position
 * @method insertbr
 * @static
 * @param {String} cmd The command executed: insertbr
 */
 insertbr: function() {
 var inst = this.getInstance(),
 sel = new inst.EditorSelection(),
 html = '<var>|</var>', last = null,
 root = inst.EditorSelection.ROOT,
 q = (Y.UA.webkit) ? 'span.Apple-style-span,var' : 'var',
 insert = function(n) {
 var c = inst.Node.create('<br>');
 n.insert(c, 'before');
 return c;
 };
 
 if (sel._selection.pasteHTML) {
 sel._selection.pasteHTML(html);
 } else {
 this._command('inserthtml', html);
 }
 
 
 root.all(q).each(function(n) {
 var g = true, s;
 if (Y.UA.webkit) {
 g = false;
 if (n.get('innerHTML') === '|') {
 g = true;
 }
 }
 if (g) {
 last = insert(n);
 if ((!last.previous() || !last.previous().test('br')) && Y.UA.gecko) {
 s = last.cloneNode();
 last.insert(s, 'after');
 last = s;
 }
 n.remove();
 }
 });
 if (Y.UA.webkit && last) {
 insert(last);
 sel.selectNode(last);
 }
 },
 /**
 * Inserts an image at the cursor position
 * @method insertimage
 * @static
 * @param {String} cmd The command executed: insertimage
 * @param {String} img The url of the image to be inserted
 * @return {Node} Node instance of the item touched by this command.
 */
 insertimage: function(cmd, img) {
 return this.command('inserthtml', '<img src="' + img + '">');
 },
 /**
 * Add a class to all of the elements in the selection
 * @method addclass
 * @static
 * @param {String} cmd The command executed: addclass
 * @param {String} cls The className to add
 * @return {NodeList} NodeList of the items touched by this command.
 */
 addclass: function(cmd, cls) {
 var inst = this.getInstance();
 return (new inst.EditorSelection()).getSelected().addClass(cls);
 },
 /**
 * Remove a class from all of the elements in the selection
 * @method removeclass
 * @static
 * @param {String} cmd The command executed: removeclass
 * @param {String} cls The className to remove
 * @return {NodeList} NodeList of the items touched by this command.
 */
 removeclass: function(cmd, cls) {
 var inst = this.getInstance();
 return (new inst.EditorSelection()).getSelected().removeClass(cls);
 },
 /**
 * Adds a forecolor to the current selection, or creates a new element and applies it
 * @method forecolor
 * @static
 * @param {String} cmd The command executed: forecolor
 * @param {String} val The color value to apply
 * @return {NodeList} NodeList of the items touched by this command.
 */
 forecolor: function(cmd, val) {
 var inst = this.getInstance(),
 sel = new inst.EditorSelection(), n;
 
 if (!Y.UA.ie) {
 this._command('useCSS', false);
 }
 if (inst.EditorSelection.hasCursor()) {
 if (sel.isCollapsed) {
 if (sel.anchorNode && (sel.anchorNode.get('innerHTML') === '&nbsp;')) {
 sel.anchorNode.setStyle('color', val);
 n = sel.anchorNode;
 } else {
 n = this.command('inserthtml', '<span style="color: ' + val + '">' + inst.EditorSelection.CURSOR + '</span>');
 sel.focusCursor(true, true);
 }
 return n;
 } else {
 return this._command(cmd, val);
 }
 } else {
 this._command(cmd, val);
 }
 },
 /**
 * Adds a background color to the current selection, or creates a new element and applies it
 * @method backcolor
 * @static
 * @param {String} cmd The command executed: backcolor
 * @param {String} val The color value to apply
 * @return {NodeList} NodeList of the items touched by this command.
 */
 backcolor: function(cmd, val) {
 var inst = this.getInstance(),
 sel = new inst.EditorSelection(), n;
 
 if (Y.UA.gecko || Y.UA.opera) {
 cmd = 'hilitecolor';
 }
 if (!Y.UA.ie) {
 this._command('useCSS', false);
 }
 if (inst.EditorSelection.hasCursor()) {
 if (sel.isCollapsed) {
 if (sel.anchorNode && (sel.anchorNode.get('innerHTML') === '&nbsp;')) {
 sel.anchorNode.setStyle('backgroundColor', val);
 n = sel.anchorNode;
 } else {
 n = this.command('inserthtml',
 '<span style="background-color: ' + val + '">' + inst.EditorSelection.CURSOR + '</span>');
 sel.focusCursor(true, true);
 }
 return n;
 } else {
 return this._command(cmd, val);
 }
 } else {
 this._command(cmd, val);
 }
 },
 /**
 * Sugar method, calles backcolor
 * @method hilitecolor
 * @static
 * @param {String} cmd The command executed: backcolor
 * @param {String} val The color value to apply
 * @return {NodeList} NodeList of the items touched by this command.
 */
 hilitecolor: function() {
 return ExecCommand.COMMANDS.backcolor.apply(this, arguments);
 },
 /**
 * Adds a font name to the current selection, or creates a new element and applies it
 * @method fontname2
 * @deprecated
 * @static
 * @param {String} cmd The command executed: fontname
 * @param {String} val The font name to apply
 * @return {NodeList} NodeList of the items touched by this command.
 */
 fontname2: function(cmd, val) {
 this._command('fontname', val);
 var inst = this.getInstance(),
 sel = new inst.EditorSelection();
 
 if (sel.isCollapsed && (this._lastKey !== 32)) {
 if (sel.anchorNode.test('font')) {
 sel.anchorNode.set('face', val);
 }
 }
 },
 /**
 * Adds a fontsize to the current selection, or creates a new element and applies it
 * @method fontsize2
 * @deprecated
 * @static
 * @param {String} cmd The command executed: fontsize
 * @param {String} val The font size to apply
 * @return {NodeList} NodeList of the items touched by this command.
 */
 fontsize2: function(cmd, val) {
 this._command('fontsize', val);
 
 var inst = this.getInstance(),
 sel = new inst.EditorSelection(), p;
 
 if (sel.isCollapsed && sel.anchorNode && (this._lastKey !== 32)) {
 if (Y.UA.webkit) {
 if (sel.anchorNode.getStyle('lineHeight')) {
 sel.anchorNode.setStyle('lineHeight', '');
 }
 }
 if (sel.anchorNode.test('font')) {
 sel.anchorNode.set('size', val);
 } else if (Y.UA.gecko) {
 p = sel.anchorNode.ancestor(inst.EditorSelection.DEFAULT_BLOCK_TAG);
 if (p) {
 p.setStyle('fontSize', '');
 }
 }
 }
 },
 /**
 * Overload for list
 * @method insertorderedlist
 * @static
 * @param {String} cmd The command executed: list, ul
 */
 insertunorderedlist: function() {
 this.command('list', 'ul');
 },
 /**
 * Overload for list
 * @method insertunorderedlist
 * @static
 * @param {String} cmd The command executed: list, ol
 */
 insertorderedlist: function() {
 this.command('list', 'ol');
 },
 /**
 * Noramlizes lists creation/destruction for IE. All others pass through to native calls
 * @method list
 * @static
 * @param {String} cmd The command executed: list (not used)
 * @param {String} tag The tag to deal with
 */
 list: function(cmd, tag) {
 var inst = this.getInstance(), html, self = this,
 /*
 The yui3- class name below is not a skinnable class,
 it's a utility class used internally by editor and
 stripped when completed, calling getClassName on this
 is a waste of resources.
 */
 DIR = 'dir', cls = 'yui3-touched',
 dir, range, div, elm, n, str, s, par, list, lis,
 useP = (inst.host.editorPara ? true : false), tmp,
 sdir, hasPParent, fc,
 root = inst.EditorSelection.ROOT,
 sel = new inst.EditorSelection();
 
 cmd = 'insert' + ((tag === 'ul') ? 'un' : '') + 'orderedlist';
 
 if (Y.UA.ie && Y.UA.ie < 11 && !sel.isCollapsed) {
 range = sel._selection;
 html = range.htmlText;
 div = inst.Node.create(html) || root;
 
 if (div.test('li') || div.one('li')) {
 this._command(cmd, null);
 return;
 }
 if (div.test(tag)) {
 elm = range.item ? range.item(0) : range.parentElement();
 n = inst.one(elm);
 lis = n.all('li');
 
 str = '<div>';
 lis.each(function(l) {
 str = self._wrapContent(l.get('innerHTML'));
 });
 str += '</div>';
 s = inst.Node.create(str);
 if (n.get('parentNode').test('div')) {
 n = n.get('parentNode');
 }
 if (n && n.hasAttribute(DIR)) {
 if (useP) {
 s.all('p').setAttribute(DIR, n.getAttribute(DIR));
 } else {
 s.setAttribute(DIR, n.getAttribute(DIR));
 }
 }
 if (useP) {
 n.replace(s.get('innerHTML'));
 } else {
 n.replace(s);
 }
 if (range.moveToElementText) {
 range.moveToElementText(s._node);
 }
 range.select();
 } else {
 par = Y.one(range.parentElement());
 if (!par.test(inst.EditorSelection.BLOCKS)) {
 par = par.ancestor(inst.EditorSelection.BLOCKS);
 }
 if (par) {
 if (par.hasAttribute(DIR)) {
 dir = par.getAttribute(DIR);
 }
 }
 if (html.indexOf('<br>') > -1) {
 html = html.split(/<br>/i);
 } else {
 tmp = inst.Node.create(html);
 ps = tmp ? tmp.all('p') : null;
 
 if (ps && ps.size()) {
 html = [];
 ps.each(function(n) {
 html.push(n.get('innerHTML'));
 });
 } else {
 html = [html];
 }
 }
 list = '<' + tag + ' id="ie-list">';
 Y.each(html, function(v) {
 var a = inst.Node.create(v);
 if (a && a.test('p')) {
 if (a.hasAttribute(DIR)) {
 dir = a.getAttribute(DIR);
 }
 v = a.get('innerHTML');
 }
 list += '<li>' + v + '</li>';
 });
 list += '</' + tag + '>';
 range.pasteHTML(list);
 elm = inst.config.doc.getElementById('ie-list');
 elm.id = '';
 if (dir) {
 elm.setAttribute(DIR, dir);
 }
 if (range.moveToElementText) {
 range.moveToElementText(elm);
 }
 range.select();
 }
 } else if (Y.UA.ie && Y.UA.ie < 11) {
 par = inst.one(sel._selection.parentElement());
 if (par.test('p')) {
 if (par && par.hasAttribute(DIR)) {
 dir = par.getAttribute(DIR);
 }
 html = Y.EditorSelection.getText(par);
 if (html === '') {
 sdir = '';
 if (dir) {
 sdir = ' dir="' + dir + '"';
 }
 list = inst.Node.create(Y.Lang.sub('<{tag}{dir}><li></li></{tag}>', { tag: tag, dir: sdir }));
 par.replace(list);
 sel.selectNode(list.one('li'));
 } else {
 this._command(cmd, null);
 }
 } else {
 this._command(cmd, null);
 }
 } else {
 root.all(tag).addClass(cls);
 if (sel.anchorNode.test(inst.EditorSelection.BLOCKS)) {
 par = sel.anchorNode;
 } else {
 par = sel.anchorNode.ancestor(inst.EditorSelection.BLOCKS);
 }
 if (!par) { //No parent, find the first block under the anchorNode
 par = sel.anchorNode.one(inst.EditorSelection.BLOCKS);
 }
 
 if (par && par.hasAttribute(DIR)) {
 dir = par.getAttribute(DIR);
 }
 if (par && par.test(tag)) {
 hasPParent = par.ancestor('p');
 html = inst.Node.create('<div/>');
 elm = par.all('li');
 elm.each(function(h) {
 html.append(self._wrapContent(h.get('innerHTML'), hasPParent));
 });
 if (dir) {
 if (useP) {
 html.all('p').setAttribute(DIR, dir);
 } else {
 html.setAttribute(DIR, dir);
 }
 }
 if (useP) {
 html = inst.Node.create(html.get('innerHTML'));
 }
 fc = html.get('firstChild');
 par.replace(html);
 sel.selectNode(fc);
 } else {
 this._command(cmd, null);
 }
 list = root.all(tag);
 if (dir) {
 if (list.size()) {
 //Changed to a List
 list.each(function(n) {
 if (!n.hasClass(cls)) {
 n.setAttribute(DIR, dir);
 }
 });
 }
 }
 
 list.removeClass(cls);
 }
 },
 /**
 * Noramlizes alignment for Webkit Browsers
 * @method justify
 * @static
 * @param {String} cmd The command executed: justify (not used)
 * @param {String} val The actual command from the justify{center,all,left,right} stubs
 */
 justify: function(cmd, val) {
 if (Y.UA.webkit) {
 var inst = this.getInstance(),
 sel = new inst.EditorSelection(),
 aNode = sel.anchorNode, html,
 bgColor = aNode.getStyle('backgroundColor');
 
 this._command(val);
 sel = new inst.EditorSelection();
 if (sel.anchorNode.test('div')) {
 html = '<span>' + sel.anchorNode.get('innerHTML') + '</span>';
 sel.anchorNode.set('innerHTML', html);
 sel.anchorNode.one('span').setStyle('backgroundColor', bgColor);
 sel.selectNode(sel.anchorNode.one('span'));
 }
 } else {
 this._command(val);
 }
 },
 /**
 * Override method for justify
 * @method justifycenter
 * @static
 */
 justifycenter: function() {
 this.command('justify', 'justifycenter');
 },
 /**
 * Override method for justify
 * @method justifyleft
 * @static
 */
 justifyleft: function() {
 this.command('justify', 'justifyleft');
 },
 /**
 * Override method for justify
 * @method justifyright
 * @static
 */
 justifyright: function() {
 this.command('justify', 'justifyright');
 },
 /**
 * Override method for justify
 * @method justifyfull
 * @static
 */
 justifyfull: function() {
 this.command('justify', 'justifyfull');
 }
 }
 });
 
 if (Y.UA.ie && Y.UA.ie < 11) {
 ExecCommand.COMMANDS.bold = function() {
 fixIETags.call(this, 'bold', 'b', 'FONT-WEIGHT: bold');
 };
 ExecCommand.COMMANDS.italic = function() {
 fixIETags.call(this, 'italic', 'i', 'FONT-STYLE: italic');
 };
 ExecCommand.COMMANDS.underline = function() {
 fixIETags.call(this, 'underline', 'u', 'TEXT-DECORATION: underline');
 };
 }
 
 Y.namespace('Plugin');
 Y.Plugin.ExecCommand = ExecCommand;
 
 
 

AltStyle によって変換されたページ (->オリジナル) /