diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/editor/plugins/blockquote.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/editor/plugins/blockquote.js | 479 |
1 files changed, 0 insertions, 479 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/editor/plugins/blockquote.js b/contexts/data/lib/closure-library/closure/goog/editor/plugins/blockquote.js deleted file mode 100644 index d73719c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/editor/plugins/blockquote.js +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview goog.editor plugin to handle splitting block quotes. - * - */ - -goog.provide('goog.editor.plugins.Blockquote'); - -goog.require('goog.debug.Logger'); -goog.require('goog.dom'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.classes'); -goog.require('goog.editor.BrowserFeature'); -goog.require('goog.editor.Command'); -goog.require('goog.editor.Plugin'); -goog.require('goog.editor.node'); -goog.require('goog.functions'); - - - -/** - * Plugin to handle splitting block quotes. This plugin does nothing on its - * own and should be used in conjunction with EnterHandler or one of its - * subclasses. - * @param {boolean} requiresClassNameToSplit Whether to split only blockquotes - * that have the given classname. - * @param {string=} opt_className The classname to apply to generated - * blockquotes. Defaults to 'tr_bq'. - * @constructor - * @extends {goog.editor.Plugin} - */ -goog.editor.plugins.Blockquote = function(requiresClassNameToSplit, - opt_className) { - goog.editor.Plugin.call(this); - - /** - * Whether we only split blockquotes that have {@link classname}, or whether - * all blockquote tags should be split on enter. - * @type {boolean} - * @private - */ - this.requiresClassNameToSplit_ = requiresClassNameToSplit; - - /** - * Classname to put on blockquotes that are generated via the toolbar for - * blockquote, so that we can internally distinguish these from blockquotes - * that are used for indentation. This classname can be over-ridden by - * clients for styling or other purposes. - * @type {string} - * @private - */ - this.className_ = opt_className || goog.getCssName('tr_bq'); -}; -goog.inherits(goog.editor.plugins.Blockquote, goog.editor.Plugin); - - -/** - * Command implemented by this plugin. - * @type {string} - */ -goog.editor.plugins.Blockquote.SPLIT_COMMAND = '+splitBlockquote'; - - -/** - * Class ID used to identify this plugin. - * @type {string} - */ -goog.editor.plugins.Blockquote.CLASS_ID = 'Blockquote'; - - -/** - * Logging object. - * @type {goog.debug.Logger} - * @protected - * @override - */ -goog.editor.plugins.Blockquote.prototype.logger = - goog.debug.Logger.getLogger('goog.editor.plugins.Blockquote'); - - -/** @override */ -goog.editor.plugins.Blockquote.prototype.getTrogClassId = function() { - return goog.editor.plugins.Blockquote.CLASS_ID; -}; - - -/** - * Since our exec command is always called from elsewhere, we make it silent. - * @override - */ -goog.editor.plugins.Blockquote.prototype.isSilentCommand = goog.functions.TRUE; - - -/** - * Checks if a node is a blockquote node. If isAlreadySetup is set, it also - * makes sure the node has the blockquote classname applied. Otherwise, it - * ensures that the blockquote does not already have the classname applied. - * @param {Node} node DOM node to check. - * @param {boolean} isAlreadySetup True to enforce that the classname must be - * set in order for it to count as a blockquote, false to - * enforce that the classname must not be set in order for - * it to count as a blockquote. - * @param {boolean} requiresClassNameToSplit Whether only blockquotes with the - * class name should be split. - * @param {string} className The official blockquote class name. - * @return {boolean} Whether node is a blockquote and if isAlreadySetup is - * true, then whether this is a setup blockquote. - * @deprecated Use {@link #isSplittableBlockquote}, - * {@link #isSetupBlockquote}, or {@link #isUnsetupBlockquote} instead - * since this has confusing behavior. - */ -goog.editor.plugins.Blockquote.isBlockquote = function(node, isAlreadySetup, - requiresClassNameToSplit, className) { - if (node.tagName != goog.dom.TagName.BLOCKQUOTE) { - return false; - } - if (!requiresClassNameToSplit) { - return isAlreadySetup; - } - var hasClassName = goog.dom.classes.has(/** @type {Element} */ (node), - className); - return isAlreadySetup ? hasClassName : !hasClassName; -}; - - -/** - * Checks if a node is a blockquote which can be split. A splittable blockquote - * meets the following criteria: - * <ol> - * <li>Node is a blockquote element</li> - * <li>Node has the blockquote classname if the classname is required to - * split</li> - * </ol> - * - * @param {Node} node DOM node in question. - * @return {boolean} Whether the node is a splittable blockquote. - */ -goog.editor.plugins.Blockquote.prototype.isSplittableBlockquote = - function(node) { - if (node.tagName != goog.dom.TagName.BLOCKQUOTE) { - return false; - } - - if (!this.requiresClassNameToSplit_) { - return true; - } - - return goog.dom.classes.has(node, this.className_); -}; - - -/** - * Checks if a node is a blockquote element which has been setup. - * @param {Node} node DOM node to check. - * @return {boolean} Whether the node is a blockquote with the required class - * name applied. - */ -goog.editor.plugins.Blockquote.prototype.isSetupBlockquote = - function(node) { - return node.tagName == goog.dom.TagName.BLOCKQUOTE && - goog.dom.classes.has(node, this.className_); -}; - - -/** - * Checks if a node is a blockquote element which has not been setup yet. - * @param {Node} node DOM node to check. - * @return {boolean} Whether the node is a blockquote without the required - * class name applied. - */ -goog.editor.plugins.Blockquote.prototype.isUnsetupBlockquote = - function(node) { - return node.tagName == goog.dom.TagName.BLOCKQUOTE && - !this.isSetupBlockquote(node); -}; - - -/** - * Gets the class name required for setup blockquotes. - * @return {string} The blockquote class name. - */ -goog.editor.plugins.Blockquote.prototype.getBlockquoteClassName = function() { - return this.className_; -}; - - -/** - * Helper routine which walks up the tree to find the topmost - * ancestor with only a single child. The ancestor node or the original - * node (if no ancestor was found) is then removed from the DOM. - * - * @param {Node} node The node whose ancestors have to be searched. - * @param {Node} root The root node to stop the search at. - * @private - */ -goog.editor.plugins.Blockquote.findAndRemoveSingleChildAncestor_ = function( - node, root) { - var predicateFunc = function(parentNode) { - return parentNode != root && parentNode.childNodes.length == 1; - } - var ancestor = goog.editor.node.findHighestMatchingAncestor(node, - predicateFunc); - if (!ancestor) { - ancestor = node; - } - goog.dom.removeNode(ancestor); -}; - - -/** - * Remove every nodes from the DOM tree that are all white space nodes. - * @param {Array.<Node>} nodes Nodes to be checked. - * @private - */ -goog.editor.plugins.Blockquote.removeAllWhiteSpaceNodes_ = function(nodes) { - for (var i = 0; i < nodes.length; ++i) { - if (goog.editor.node.isEmpty(nodes[i], true)) { - goog.dom.removeNode(nodes[i]); - } - } -}; - - -/** @override */ -goog.editor.plugins.Blockquote.prototype.isSupportedCommand = function( - command) { - return command == goog.editor.plugins.Blockquote.SPLIT_COMMAND; -}; - - -/** - * Splits a quoted region if any. To be called on a key press event. When this - * function returns true, the event that caused it to be called should be - * canceled. - * @param {string} command The command to execute. - * @param {...*} var_args Single additional argument representing the - * current cursor position. In IE, it is a single node. In any other - * browser, it is an object with a {@code node} key and an {@code offset} - * key. - * @return {boolean|undefined} Boolean true when the quoted region has been - * split, false or undefined otherwise. - * @override - */ -goog.editor.plugins.Blockquote.prototype.execCommandInternal = function( - command, var_args) { - var pos = arguments[1]; - if (command == goog.editor.plugins.Blockquote.SPLIT_COMMAND && pos && - (this.className_ || !this.requiresClassNameToSplit_)) { - return goog.editor.BrowserFeature.HAS_W3C_RANGES ? - this.splitQuotedBlockW3C_(pos) : - this.splitQuotedBlockIE_(/** @type {Node} */ (pos)); - } -}; - - -/** - * Version of splitQuotedBlock_ that uses W3C ranges. - * @param {Object} anchorPos The current cursor position. - * @return {boolean} Whether the blockquote was split. - * @private - */ -goog.editor.plugins.Blockquote.prototype.splitQuotedBlockW3C_ = - function(anchorPos) { - var cursorNode = anchorPos.node; - var quoteNode = goog.editor.node.findTopMostEditableAncestor( - cursorNode.parentNode, goog.bind(this.isSplittableBlockquote, this)); - - var secondHalf, textNodeToRemove; - var insertTextNode = false; - // There are two special conditions that we account for here. - // - // 1. Whenever the cursor is after (one<BR>|) or just before a BR element - // (one|<BR>) and the user presses enter, the second quoted block starts - // with a BR which appears to the user as an extra newline. This stems - // from the fact that we create two text nodes as our split boundaries - // and the BR becomes a part of the second half because of this. - // - // 2. When the cursor is at the end of a text node with no siblings and - // the user presses enter, the second blockquote might contain a - // empty subtree that ends in a 0 length text node. We account for that - // as a post-splitting operation. - if (quoteNode) { - - // selection is in a line that has text in it - if (cursorNode.nodeType == goog.dom.NodeType.TEXT) { - if (anchorPos.offset == cursorNode.length) { - var siblingNode = cursorNode.nextSibling; - - // This accounts for the condition where the cursor appears at the - // end of a text node and right before the BR eg: one|<BR>. We ensure - // that we split on the BR in that case. - if (siblingNode && siblingNode.tagName == goog.dom.TagName.BR) { - cursorNode = siblingNode; - // This might be null but splitDomTreeAt accounts for the null case. - secondHalf = siblingNode.nextSibling; - } else { - textNodeToRemove = cursorNode.splitText(anchorPos.offset); - secondHalf = textNodeToRemove; - } - } else { - secondHalf = cursorNode.splitText(anchorPos.offset); - } - } else if (cursorNode.tagName == goog.dom.TagName.BR) { - // This might be null but splitDomTreeAt accounts for the null case. - secondHalf = cursorNode.nextSibling; - } else { - // The selection is in a line that is empty, with more than 1 level - // of quote. - insertTextNode = true; - } - } else { - // Check if current node is a quote node. - // This will happen if user clicks in an empty line in the quote, - // when there is 1 level of quote. - if (this.isSetupBlockquote(cursorNode)) { - quoteNode = cursorNode; - insertTextNode = true; - } - } - - if (insertTextNode) { - // Create two empty text nodes to split between. - cursorNode = this.insertEmptyTextNodeBeforeRange_(); - secondHalf = this.insertEmptyTextNodeBeforeRange_(); - } - - if (!quoteNode) { - return false; - } - - secondHalf = goog.editor.node.splitDomTreeAt(cursorNode, secondHalf, - quoteNode); - goog.dom.insertSiblingAfter(secondHalf, quoteNode); - - // Set the insertion point. - var dh = this.getFieldDomHelper(); - var tagToInsert = - this.getFieldObject().queryCommandValue( - goog.editor.Command.DEFAULT_TAG) || - goog.dom.TagName.DIV; - var container = dh.createElement(/** @type {string} */ (tagToInsert)); - container.innerHTML = ' '; // Prevent the div from collapsing. - quoteNode.parentNode.insertBefore(container, secondHalf); - dh.getWindow().getSelection().collapse(container, 0); - - // We need to account for the condition where the second blockquote - // might contain an empty DOM tree. This arises from trying to split - // at the end of an empty text node. We resolve this by walking up the tree - // till we either reach the blockquote or till we hit a node with more - // than one child. The resulting node is then removed from the DOM. - if (textNodeToRemove) { - goog.editor.plugins.Blockquote.findAndRemoveSingleChildAncestor_( - textNodeToRemove, secondHalf); - } - - goog.editor.plugins.Blockquote.removeAllWhiteSpaceNodes_( - [quoteNode, secondHalf]); - return true; -}; - - -/** - * Inserts an empty text node before the field's range. - * @return {!Node} The empty text node. - * @private - */ -goog.editor.plugins.Blockquote.prototype.insertEmptyTextNodeBeforeRange_ = - function() { - var range = this.getFieldObject().getRange(); - var node = this.getFieldDomHelper().createTextNode(''); - range.insertNode(node, true); - return node; -}; - - -/** - * IE version of splitQuotedBlock_. - * @param {Node} splitNode The current cursor position. - * @return {boolean} Whether the blockquote was split. - * @private - */ -goog.editor.plugins.Blockquote.prototype.splitQuotedBlockIE_ = - function(splitNode) { - var dh = this.getFieldDomHelper(); - var quoteNode = goog.editor.node.findTopMostEditableAncestor( - splitNode.parentNode, goog.bind(this.isSplittableBlockquote, this)); - - if (!quoteNode) { - return false; - } - - var clone = splitNode.cloneNode(false); - - // Whenever the cursor is just before a BR element (one|<BR>) and the user - // presses enter, the second quoted block starts with a BR which appears - // to the user as an extra newline. This stems from the fact that the - // dummy span that we create (splitNode) occurs before the BR and we split - // on that. - if (splitNode.nextSibling && - splitNode.nextSibling.tagName == goog.dom.TagName.BR) { - splitNode = splitNode.nextSibling; - } - var secondHalf = goog.editor.node.splitDomTreeAt(splitNode, clone, quoteNode); - goog.dom.insertSiblingAfter(secondHalf, quoteNode); - - // Set insertion point. - var tagToInsert = - this.getFieldObject().queryCommandValue( - goog.editor.Command.DEFAULT_TAG) || - goog.dom.TagName.DIV; - var div = dh.createElement(/** @type {string} */ (tagToInsert)); - quoteNode.parentNode.insertBefore(div, secondHalf); - - // The div needs non-whitespace contents in order for the insertion point - // to get correctly inserted. - div.innerHTML = ' '; - - // Moving the range 1 char isn't enough when you have markup. - // This moves the range to the end of the nbsp. - var range = dh.getDocument().selection.createRange(); - range.moveToElementText(splitNode); - range.move('character', 2); - range.select(); - - // Remove the no-longer-necessary nbsp. - div.innerHTML = ''; - - // Clear the original selection. - range.pasteHTML(''); - - // We need to remove clone from the DOM but just removing clone alone will - // not suffice. Let's assume we have the following DOM structure and the - // cursor is placed after the first numbered list item "one". - // - // <blockquote class="gmail-quote"> - // <div><div>a</div><ol><li>one|</li></ol></div> - // <div>b</div> - // </blockquote> - // - // After pressing enter, we have the following structure. - // - // <blockquote class="gmail-quote"> - // <div><div>a</div><ol><li>one|</li></ol></div> - // </blockquote> - // <div> </div> - // <blockquote class="gmail-quote"> - // <div><ol><li><span id=""></span></li></ol></div> - // <div>b</div> - // </blockquote> - // - // The clone is contained in a subtree which should be removed. This stems - // from the fact that we invoke splitDomTreeAt with the dummy span - // as the starting splitting point and this results in the empty subtree - // <div><ol><li><span id=""></span></li></ol></div>. - // - // We resolve this by walking up the tree till we either reach the - // blockquote or till we hit a node with more than one child. The resulting - // node is then removed from the DOM. - goog.editor.plugins.Blockquote.findAndRemoveSingleChildAncestor_( - clone, secondHalf); - - goog.editor.plugins.Blockquote.removeAllWhiteSpaceNodes_( - [quoteNode, secondHalf]); - return true; -}; |