http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/tagname.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/tagname.js b/externs/GCL/externs/goog/dom/tagname.js new file mode 100644 index 0000000..ad44d85 --- /dev/null +++ b/externs/GCL/externs/goog/dom/tagname.js @@ -0,0 +1,160 @@ +// Copyright 2007 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 Defines the goog.dom.TagName enum. This enumerates + * all HTML tag names specified in either the the W3C HTML 4.01 index of + * elements or the HTML5 draft specification. + * + * References: + * http://www.w3.org/TR/html401/index/elements.html + * http://dev.w3.org/html5/spec/section-index.html + * + */ +goog.provide('goog.dom.TagName'); + + +/** + * Enum of all html tag names specified by the W3C HTML4.01 and HTML5 + * specifications. + * @enum {string} + */ +goog.dom.TagName = { + A: 'A', + ABBR: 'ABBR', + ACRONYM: 'ACRONYM', + ADDRESS: 'ADDRESS', + APPLET: 'APPLET', + AREA: 'AREA', + ARTICLE: 'ARTICLE', + ASIDE: 'ASIDE', + AUDIO: 'AUDIO', + B: 'B', + BASE: 'BASE', + BASEFONT: 'BASEFONT', + BDI: 'BDI', + BDO: 'BDO', + BIG: 'BIG', + BLOCKQUOTE: 'BLOCKQUOTE', + BODY: 'BODY', + BR: 'BR', + BUTTON: 'BUTTON', + CANVAS: 'CANVAS', + CAPTION: 'CAPTION', + CENTER: 'CENTER', + CITE: 'CITE', + CODE: 'CODE', + COL: 'COL', + COLGROUP: 'COLGROUP', + COMMAND: 'COMMAND', + DATA: 'DATA', + DATALIST: 'DATALIST', + DD: 'DD', + DEL: 'DEL', + DETAILS: 'DETAILS', + DFN: 'DFN', + DIALOG: 'DIALOG', + DIR: 'DIR', + DIV: 'DIV', + DL: 'DL', + DT: 'DT', + EM: 'EM', + EMBED: 'EMBED', + FIELDSET: 'FIELDSET', + FIGCAPTION: 'FIGCAPTION', + FIGURE: 'FIGURE', + FONT: 'FONT', + FOOTER: 'FOOTER', + FORM: 'FORM', + FRAME: 'FRAME', + FRAMESET: 'FRAMESET', + H1: 'H1', + H2: 'H2', + H3: 'H3', + H4: 'H4', + H5: 'H5', + H6: 'H6', + HEAD: 'HEAD', + HEADER: 'HEADER', + HGROUP: 'HGROUP', + HR: 'HR', + HTML: 'HTML', + I: 'I', + IFRAME: 'IFRAME', + IMG: 'IMG', + INPUT: 'INPUT', + INS: 'INS', + ISINDEX: 'ISINDEX', + KBD: 'KBD', + KEYGEN: 'KEYGEN', + LABEL: 'LABEL', + LEGEND: 'LEGEND', + LI: 'LI', + LINK: 'LINK', + MAP: 'MAP', + MARK: 'MARK', + MATH: 'MATH', + MENU: 'MENU', + META: 'META', + METER: 'METER', + NAV: 'NAV', + NOFRAMES: 'NOFRAMES', + NOSCRIPT: 'NOSCRIPT', + OBJECT: 'OBJECT', + OL: 'OL', + OPTGROUP: 'OPTGROUP', + OPTION: 'OPTION', + OUTPUT: 'OUTPUT', + P: 'P', + PARAM: 'PARAM', + PRE: 'PRE', + PROGRESS: 'PROGRESS', + Q: 'Q', + RP: 'RP', + RT: 'RT', + RUBY: 'RUBY', + S: 'S', + SAMP: 'SAMP', + SCRIPT: 'SCRIPT', + SECTION: 'SECTION', + SELECT: 'SELECT', + SMALL: 'SMALL', + SOURCE: 'SOURCE', + SPAN: 'SPAN', + STRIKE: 'STRIKE', + STRONG: 'STRONG', + STYLE: 'STYLE', + SUB: 'SUB', + SUMMARY: 'SUMMARY', + SUP: 'SUP', + SVG: 'SVG', + TABLE: 'TABLE', + TBODY: 'TBODY', + TD: 'TD', + TEMPLATE: 'TEMPLATE', + TEXTAREA: 'TEXTAREA', + TFOOT: 'TFOOT', + TH: 'TH', + THEAD: 'THEAD', + TIME: 'TIME', + TITLE: 'TITLE', + TR: 'TR', + TRACK: 'TRACK', + TT: 'TT', + U: 'U', + UL: 'UL', + VAR: 'VAR', + VIDEO: 'VIDEO', + WBR: 'WBR' +};
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/tags.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/tags.js b/externs/GCL/externs/goog/dom/tags.js new file mode 100644 index 0000000..159abe0 --- /dev/null +++ b/externs/GCL/externs/goog/dom/tags.js @@ -0,0 +1,42 @@ +// Copyright 2014 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 Utilities for HTML element tag names. + */ +goog.provide('goog.dom.tags'); + +goog.require('goog.object'); + + +/** + * The void elements specified by + * http://www.w3.org/TR/html-markup/syntax.html#void-elements. + * @const + * @type {!Object} + * @private + */ +goog.dom.tags.VOID_TAGS_ = goog.object.createSet(('area,base,br,col,command,' + + 'embed,hr,img,input,keygen,link,meta,param,source,track,wbr').split(',')); + + +/** + * Checks whether the tag is void (with no contents allowed and no legal end + * tag), for example 'br'. + * @param {string} tagName The tag name in lower case. + * @return {boolean} + */ +goog.dom.tags.isVoidTag = function(tagName) { + return goog.dom.tags.VOID_TAGS_[tagName] === true; +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/textrange.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/textrange.js b/externs/GCL/externs/goog/dom/textrange.js new file mode 100644 index 0000000..f5cfee0 --- /dev/null +++ b/externs/GCL/externs/goog/dom/textrange.js @@ -0,0 +1,615 @@ +// Copyright 2007 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 Utilities for working with text ranges in HTML documents. + * + * @author [email protected] (Robby Walker) + */ + + +goog.provide('goog.dom.TextRange'); + +goog.require('goog.array'); +goog.require('goog.dom'); +goog.require('goog.dom.AbstractRange'); +goog.require('goog.dom.RangeType'); +goog.require('goog.dom.SavedRange'); +goog.require('goog.dom.TagName'); +goog.require('goog.dom.TextRangeIterator'); +goog.require('goog.dom.browserrange'); +goog.require('goog.string'); +goog.require('goog.userAgent'); + + + +/** + * Create a new text selection with no properties. Do not use this constructor: + * use one of the goog.dom.Range.createFrom* methods instead. + * @constructor + * @extends {goog.dom.AbstractRange} + * @final + */ +goog.dom.TextRange = function() { + /** + * The browser specific range wrapper. This can be null if one of the other + * representations of the range is specified. + * @private {goog.dom.browserrange.AbstractRange?} + */ + this.browserRangeWrapper_ = null; + + /** + * The start node of the range. This can be null if one of the other + * representations of the range is specified. + * @private {Node} + */ + this.startNode_ = null; + + /** + * The start offset of the range. This can be null if one of the other + * representations of the range is specified. + * @private {?number} + */ + this.startOffset_ = null; + + /** + * The end node of the range. This can be null if one of the other + * representations of the range is specified. + * @private {Node} + */ + this.endNode_ = null; + + /** + * The end offset of the range. This can be null if one of the other + * representations of the range is specified. + * @private {?number} + */ + this.endOffset_ = null; + + /** + * Whether the focus node is before the anchor node. + * @private {boolean} + */ + this.isReversed_ = false; +}; +goog.inherits(goog.dom.TextRange, goog.dom.AbstractRange); + + +/** + * Create a new range wrapper from the given browser range object. Do not use + * this method directly - please use goog.dom.Range.createFrom* instead. + * @param {Range|TextRange} range The browser range object. + * @param {boolean=} opt_isReversed Whether the focus node is before the anchor + * node. + * @return {!goog.dom.TextRange} A range wrapper object. + */ +goog.dom.TextRange.createFromBrowserRange = function(range, opt_isReversed) { + return goog.dom.TextRange.createFromBrowserRangeWrapper_( + goog.dom.browserrange.createRange(range), opt_isReversed); +}; + + +/** + * Create a new range wrapper from the given browser range wrapper. + * @param {goog.dom.browserrange.AbstractRange} browserRange The browser range + * wrapper. + * @param {boolean=} opt_isReversed Whether the focus node is before the anchor + * node. + * @return {!goog.dom.TextRange} A range wrapper object. + * @private + */ +goog.dom.TextRange.createFromBrowserRangeWrapper_ = function(browserRange, + opt_isReversed) { + var range = new goog.dom.TextRange(); + + // Initialize the range as a browser range wrapper type range. + range.browserRangeWrapper_ = browserRange; + range.isReversed_ = !!opt_isReversed; + + return range; +}; + + +/** + * Create a new range wrapper that selects the given node's text. Do not use + * this method directly - please use goog.dom.Range.createFrom* instead. + * @param {Node} node The node to select. + * @param {boolean=} opt_isReversed Whether the focus node is before the anchor + * node. + * @return {!goog.dom.TextRange} A range wrapper object. + */ +goog.dom.TextRange.createFromNodeContents = function(node, opt_isReversed) { + return goog.dom.TextRange.createFromBrowserRangeWrapper_( + goog.dom.browserrange.createRangeFromNodeContents(node), + opt_isReversed); +}; + + +/** + * Create a new range wrapper that selects the area between the given nodes, + * accounting for the given offsets. Do not use this method directly - please + * use goog.dom.Range.createFrom* instead. + * @param {Node} anchorNode The node to start with. + * @param {number} anchorOffset The offset within the node to start. + * @param {Node} focusNode The node to end with. + * @param {number} focusOffset The offset within the node to end. + * @return {!goog.dom.TextRange} A range wrapper object. + */ +goog.dom.TextRange.createFromNodes = function(anchorNode, anchorOffset, + focusNode, focusOffset) { + var range = new goog.dom.TextRange(); + range.isReversed_ = /** @suppress {missingRequire} */ ( + goog.dom.Range.isReversed(anchorNode, anchorOffset, + focusNode, focusOffset)); + + // Avoid selecting terminal elements directly + if (goog.dom.isElement(anchorNode) && !goog.dom.canHaveChildren(anchorNode)) { + var parent = anchorNode.parentNode; + anchorOffset = goog.array.indexOf(parent.childNodes, anchorNode); + anchorNode = parent; + } + + if (goog.dom.isElement(focusNode) && !goog.dom.canHaveChildren(focusNode)) { + var parent = focusNode.parentNode; + focusOffset = goog.array.indexOf(parent.childNodes, focusNode); + focusNode = parent; + } + + // Initialize the range as a W3C style range. + if (range.isReversed_) { + range.startNode_ = focusNode; + range.startOffset_ = focusOffset; + range.endNode_ = anchorNode; + range.endOffset_ = anchorOffset; + } else { + range.startNode_ = anchorNode; + range.startOffset_ = anchorOffset; + range.endNode_ = focusNode; + range.endOffset_ = focusOffset; + } + + return range; +}; + + +// Method implementations + + +/** + * @return {!goog.dom.TextRange} A clone of this range. + * @override + */ +goog.dom.TextRange.prototype.clone = function() { + var range = new goog.dom.TextRange(); + range.browserRangeWrapper_ = + this.browserRangeWrapper_ && this.browserRangeWrapper_.clone(); + range.startNode_ = this.startNode_; + range.startOffset_ = this.startOffset_; + range.endNode_ = this.endNode_; + range.endOffset_ = this.endOffset_; + range.isReversed_ = this.isReversed_; + + return range; +}; + + +/** @override */ +goog.dom.TextRange.prototype.getType = function() { + return goog.dom.RangeType.TEXT; +}; + + +/** @override */ +goog.dom.TextRange.prototype.getBrowserRangeObject = function() { + return this.getBrowserRangeWrapper_().getBrowserRange(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.setBrowserRangeObject = function(nativeRange) { + // Test if it's a control range by seeing if a control range only method + // exists. + if (goog.dom.AbstractRange.isNativeControlRange(nativeRange)) { + return false; + } + this.browserRangeWrapper_ = goog.dom.browserrange.createRange( + nativeRange); + this.clearCachedValues_(); + return true; +}; + + +/** + * Clear all cached values. + * @private + */ +goog.dom.TextRange.prototype.clearCachedValues_ = function() { + this.startNode_ = this.startOffset_ = this.endNode_ = this.endOffset_ = null; +}; + + +/** @override */ +goog.dom.TextRange.prototype.getTextRangeCount = function() { + return 1; +}; + + +/** @override */ +goog.dom.TextRange.prototype.getTextRange = function(i) { + return this; +}; + + +/** + * @return {!goog.dom.browserrange.AbstractRange} The range wrapper object. + * @private + */ +goog.dom.TextRange.prototype.getBrowserRangeWrapper_ = function() { + return this.browserRangeWrapper_ || + (this.browserRangeWrapper_ = goog.dom.browserrange.createRangeFromNodes( + this.getStartNode(), this.getStartOffset(), + this.getEndNode(), this.getEndOffset())); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getContainer = function() { + return this.getBrowserRangeWrapper_().getContainer(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getStartNode = function() { + return this.startNode_ || + (this.startNode_ = this.getBrowserRangeWrapper_().getStartNode()); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getStartOffset = function() { + return this.startOffset_ != null ? this.startOffset_ : + (this.startOffset_ = this.getBrowserRangeWrapper_().getStartOffset()); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getStartPosition = function() { + return this.isReversed() ? + this.getBrowserRangeWrapper_().getEndPosition() : + this.getBrowserRangeWrapper_().getStartPosition(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getEndNode = function() { + return this.endNode_ || + (this.endNode_ = this.getBrowserRangeWrapper_().getEndNode()); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getEndOffset = function() { + return this.endOffset_ != null ? this.endOffset_ : + (this.endOffset_ = this.getBrowserRangeWrapper_().getEndOffset()); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getEndPosition = function() { + return this.isReversed() ? + this.getBrowserRangeWrapper_().getStartPosition() : + this.getBrowserRangeWrapper_().getEndPosition(); +}; + + +/** + * Moves a TextRange to the provided nodes and offsets. + * @param {Node} startNode The node to start with. + * @param {number} startOffset The offset within the node to start. + * @param {Node} endNode The node to end with. + * @param {number} endOffset The offset within the node to end. + * @param {boolean} isReversed Whether the range is reversed. + */ +goog.dom.TextRange.prototype.moveToNodes = function(startNode, startOffset, + endNode, endOffset, + isReversed) { + this.startNode_ = startNode; + this.startOffset_ = startOffset; + this.endNode_ = endNode; + this.endOffset_ = endOffset; + this.isReversed_ = isReversed; + this.browserRangeWrapper_ = null; +}; + + +/** @override */ +goog.dom.TextRange.prototype.isReversed = function() { + return this.isReversed_; +}; + + +/** @override */ +goog.dom.TextRange.prototype.containsRange = function(otherRange, + opt_allowPartial) { + var otherRangeType = otherRange.getType(); + if (otherRangeType == goog.dom.RangeType.TEXT) { + return this.getBrowserRangeWrapper_().containsRange( + otherRange.getBrowserRangeWrapper_(), opt_allowPartial); + } else if (otherRangeType == goog.dom.RangeType.CONTROL) { + var elements = otherRange.getElements(); + var fn = opt_allowPartial ? goog.array.some : goog.array.every; + return fn(elements, function(el) { + return this.containsNode(el, opt_allowPartial); + }, this); + } + return false; +}; + + +/** + * Tests if the given node is in a document. + * @param {Node} node The node to check. + * @return {boolean} Whether the given node is in the given document. + */ +goog.dom.TextRange.isAttachedNode = function(node) { + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { + var returnValue = false; + /** @preserveTry */ + try { + returnValue = node.parentNode; + } catch (e) { + // IE sometimes throws Invalid Argument errors when a node is detached. + // Note: trying to return a value from the above try block can cause IE + // to crash. It is necessary to use the local returnValue + } + return !!returnValue; + } else { + return goog.dom.contains(node.ownerDocument.body, node); + } +}; + + +/** @override */ +goog.dom.TextRange.prototype.isRangeInDocument = function() { + // Ensure any cached nodes are in the document. IE also allows ranges to + // become detached, so we check if the range is still in the document as + // well for IE. + return (!this.startNode_ || + goog.dom.TextRange.isAttachedNode(this.startNode_)) && + (!this.endNode_ || + goog.dom.TextRange.isAttachedNode(this.endNode_)) && + (!(goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) || + this.getBrowserRangeWrapper_().isRangeInDocument()); +}; + + +/** @override */ +goog.dom.TextRange.prototype.isCollapsed = function() { + return this.getBrowserRangeWrapper_().isCollapsed(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getText = function() { + return this.getBrowserRangeWrapper_().getText(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getHtmlFragment = function() { + // TODO(robbyw): Generalize the code in browserrange so it is static and + // just takes an iterator. This would mean we don't always have to create a + // browser range. + return this.getBrowserRangeWrapper_().getHtmlFragment(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getValidHtml = function() { + return this.getBrowserRangeWrapper_().getValidHtml(); +}; + + +/** @override */ +goog.dom.TextRange.prototype.getPastableHtml = function() { + // TODO(robbyw): Get any attributes the table or tr has. + + var html = this.getValidHtml(); + + if (html.match(/^\s*<td\b/i)) { + // Match html starting with a TD. + html = '<table><tbody><tr>' + html + '</tr></tbody></table>'; + } else if (html.match(/^\s*<tr\b/i)) { + // Match html starting with a TR. + html = '<table><tbody>' + html + '</tbody></table>'; + } else if (html.match(/^\s*<tbody\b/i)) { + // Match html starting with a TBODY. + html = '<table>' + html + '</table>'; + } else if (html.match(/^\s*<li\b/i)) { + // Match html starting with an LI. + var container = this.getContainer(); + var tagType = goog.dom.TagName.UL; + while (container) { + if (container.tagName == goog.dom.TagName.OL) { + tagType = goog.dom.TagName.OL; + break; + } else if (container.tagName == goog.dom.TagName.UL) { + break; + } + container = container.parentNode; + } + html = goog.string.buildString('<', tagType, '>', html, '</', tagType, '>'); + } + + return html; +}; + + +/** + * Returns a TextRangeIterator over the contents of the range. Regardless of + * the direction of the range, the iterator will move in document order. + * @param {boolean=} opt_keys Unused for this iterator. + * @return {!goog.dom.TextRangeIterator} An iterator over tags in the range. + * @override + */ +goog.dom.TextRange.prototype.__iterator__ = function(opt_keys) { + return new goog.dom.TextRangeIterator(this.getStartNode(), + this.getStartOffset(), this.getEndNode(), this.getEndOffset()); +}; + + +// RANGE ACTIONS + + +/** @override */ +goog.dom.TextRange.prototype.select = function() { + this.getBrowserRangeWrapper_().select(this.isReversed_); +}; + + +/** @override */ +goog.dom.TextRange.prototype.removeContents = function() { + this.getBrowserRangeWrapper_().removeContents(); + this.clearCachedValues_(); +}; + + +/** + * Surrounds the text range with the specified element (on Mozilla) or with a + * clone of the specified element (on IE). Returns a reference to the + * surrounding element if the operation was successful; returns null if the + * operation failed. + * @param {Element} element The element with which the selection is to be + * surrounded. + * @return {Element} The surrounding element (same as the argument on Mozilla, + * but not on IE), or null if unsuccessful. + */ +goog.dom.TextRange.prototype.surroundContents = function(element) { + var output = this.getBrowserRangeWrapper_().surroundContents(element); + this.clearCachedValues_(); + return output; +}; + + +/** @override */ +goog.dom.TextRange.prototype.insertNode = function(node, before) { + var output = this.getBrowserRangeWrapper_().insertNode(node, before); + this.clearCachedValues_(); + return output; +}; + + +/** @override */ +goog.dom.TextRange.prototype.surroundWithNodes = function(startNode, endNode) { + this.getBrowserRangeWrapper_().surroundWithNodes(startNode, endNode); + this.clearCachedValues_(); +}; + + +// SAVE/RESTORE + + +/** @override */ +goog.dom.TextRange.prototype.saveUsingDom = function() { + return new goog.dom.DomSavedTextRange_(this); +}; + + +// RANGE MODIFICATION + + +/** @override */ +goog.dom.TextRange.prototype.collapse = function(toAnchor) { + var toStart = this.isReversed() ? !toAnchor : toAnchor; + + if (this.browserRangeWrapper_) { + this.browserRangeWrapper_.collapse(toStart); + } + + if (toStart) { + this.endNode_ = this.startNode_; + this.endOffset_ = this.startOffset_; + } else { + this.startNode_ = this.endNode_; + this.startOffset_ = this.endOffset_; + } + + // Collapsed ranges can't be reversed + this.isReversed_ = false; +}; + + +// SAVED RANGE OBJECTS + + + +/** + * A SavedRange implementation using DOM endpoints. + * @param {goog.dom.AbstractRange} range The range to save. + * @constructor + * @extends {goog.dom.SavedRange} + * @private + */ +goog.dom.DomSavedTextRange_ = function(range) { + goog.dom.DomSavedTextRange_.base(this, 'constructor'); + + /** + * The anchor node. + * @type {Node} + * @private + */ + this.anchorNode_ = range.getAnchorNode(); + + /** + * The anchor node offset. + * @type {number} + * @private + */ + this.anchorOffset_ = range.getAnchorOffset(); + + /** + * The focus node. + * @type {Node} + * @private + */ + this.focusNode_ = range.getFocusNode(); + + /** + * The focus node offset. + * @type {number} + * @private + */ + this.focusOffset_ = range.getFocusOffset(); +}; +goog.inherits(goog.dom.DomSavedTextRange_, goog.dom.SavedRange); + + +/** + * @return {!goog.dom.AbstractRange} The restored range. + * @override + */ +goog.dom.DomSavedTextRange_.prototype.restoreInternal = function() { + return /** @suppress {missingRequire} */ ( + goog.dom.Range.createFromNodes(this.anchorNode_, this.anchorOffset_, + this.focusNode_, this.focusOffset_)); +}; + + +/** @override */ +goog.dom.DomSavedTextRange_.prototype.disposeInternal = function() { + goog.dom.DomSavedTextRange_.superClass_.disposeInternal.call(this); + + this.anchorNode_ = null; + this.focusNode_ = null; +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/textrangeiterator.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/textrangeiterator.js b/externs/GCL/externs/goog/dom/textrangeiterator.js new file mode 100644 index 0000000..efb5221 --- /dev/null +++ b/externs/GCL/externs/goog/dom/textrangeiterator.js @@ -0,0 +1,239 @@ +// Copyright 2007 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 Iterator between two DOM text range positions. + * + * @author [email protected] (Robby Walker) + */ + +goog.provide('goog.dom.TextRangeIterator'); + +goog.require('goog.array'); +goog.require('goog.dom'); +goog.require('goog.dom.NodeType'); +goog.require('goog.dom.RangeIterator'); +goog.require('goog.dom.TagName'); +goog.require('goog.iter.StopIteration'); + + + +/** + * Subclass of goog.dom.TagIterator that iterates over a DOM range. It + * adds functions to determine the portion of each text node that is selected. + * + * @param {Node} startNode The starting node position. + * @param {number} startOffset The offset in to startNode. If startNode is + * an element, indicates an offset in to childNodes. If startNode is a + * text node, indicates an offset in to nodeValue. + * @param {Node} endNode The ending node position. + * @param {number} endOffset The offset in to endNode. If endNode is + * an element, indicates an offset in to childNodes. If endNode is a + * text node, indicates an offset in to nodeValue. + * @param {boolean=} opt_reverse Whether to traverse nodes in reverse. + * @constructor + * @extends {goog.dom.RangeIterator} + * @final + */ +goog.dom.TextRangeIterator = function(startNode, startOffset, endNode, + endOffset, opt_reverse) { + /** + * The first node in the selection. + * @private {Node} + */ + this.startNode_ = null; + + /** + * The last node in the selection. + * @private {Node} + */ + this.endNode_ = null; + + /** + * The offset within the first node in the selection. + * @private {number} + */ + this.startOffset_ = 0; + + /** + * The offset within the last node in the selection. + * @private {number} + */ + this.endOffset_ = 0; + + var goNext; + + if (startNode) { + this.startNode_ = startNode; + this.startOffset_ = startOffset; + this.endNode_ = endNode; + this.endOffset_ = endOffset; + + // Skip to the offset nodes - being careful to special case BRs since these + // have no children but still can appear as the startContainer of a range. + if (startNode.nodeType == goog.dom.NodeType.ELEMENT && + startNode.tagName != goog.dom.TagName.BR) { + var startChildren = startNode.childNodes; + var candidate = startChildren[startOffset]; + if (candidate) { + this.startNode_ = candidate; + this.startOffset_ = 0; + } else { + if (startChildren.length) { + this.startNode_ = + /** @type {Node} */ (goog.array.peek(startChildren)); + } + goNext = true; + } + } + + if (endNode.nodeType == goog.dom.NodeType.ELEMENT) { + this.endNode_ = endNode.childNodes[endOffset]; + if (this.endNode_) { + this.endOffset_ = 0; + } else { + // The offset was past the last element. + this.endNode_ = endNode; + } + } + } + + goog.dom.TextRangeIterator.base( + this, 'constructor', opt_reverse ? this.endNode_ : this.startNode_, + opt_reverse); + + if (goNext) { + try { + this.next(); + } catch (e) { + if (e != goog.iter.StopIteration) { + throw e; + } + } + } +}; +goog.inherits(goog.dom.TextRangeIterator, goog.dom.RangeIterator); + + +/** @override */ +goog.dom.TextRangeIterator.prototype.getStartTextOffset = function() { + // Offsets only apply to text nodes. If our current node is the start node, + // return the saved offset. Otherwise, return 0. + return this.node.nodeType != goog.dom.NodeType.TEXT ? -1 : + this.node == this.startNode_ ? this.startOffset_ : 0; +}; + + +/** @override */ +goog.dom.TextRangeIterator.prototype.getEndTextOffset = function() { + // Offsets only apply to text nodes. If our current node is the end node, + // return the saved offset. Otherwise, return the length of the node. + return this.node.nodeType != goog.dom.NodeType.TEXT ? -1 : + this.node == this.endNode_ ? this.endOffset_ : this.node.nodeValue.length; +}; + + +/** @override */ +goog.dom.TextRangeIterator.prototype.getStartNode = function() { + return this.startNode_; +}; + + +/** + * Change the start node of the iterator. + * @param {Node} node The new start node. + */ +goog.dom.TextRangeIterator.prototype.setStartNode = function(node) { + if (!this.isStarted()) { + this.setPosition(node); + } + + this.startNode_ = node; + this.startOffset_ = 0; +}; + + +/** @override */ +goog.dom.TextRangeIterator.prototype.getEndNode = function() { + return this.endNode_; +}; + + +/** + * Change the end node of the iterator. + * @param {Node} node The new end node. + */ +goog.dom.TextRangeIterator.prototype.setEndNode = function(node) { + this.endNode_ = node; + this.endOffset_ = 0; +}; + + +/** @override */ +goog.dom.TextRangeIterator.prototype.isLast = function() { + return this.isStarted() && this.node == this.endNode_ && + (!this.endOffset_ || !this.isStartTag()); +}; + + +/** + * Move to the next position in the selection. + * Throws {@code goog.iter.StopIteration} when it passes the end of the range. + * @return {Node} The node at the next position. + * @override + */ +goog.dom.TextRangeIterator.prototype.next = function() { + if (this.isLast()) { + throw goog.iter.StopIteration; + } + + // Call the super function. + return goog.dom.TextRangeIterator.superClass_.next.call(this); +}; + + +/** @override */ +goog.dom.TextRangeIterator.prototype.skipTag = function() { + goog.dom.TextRangeIterator.superClass_.skipTag.apply(this); + + // If the node we are skipping contains the end node, we just skipped past + // the end, so we stop the iteration. + if (goog.dom.contains(this.node, this.endNode_)) { + throw goog.iter.StopIteration; + } +}; + + +/** @override */ +goog.dom.TextRangeIterator.prototype.copyFrom = function(other) { + this.startNode_ = other.startNode_; + this.endNode_ = other.endNode_; + this.startOffset_ = other.startOffset_; + this.endOffset_ = other.endOffset_; + this.isReversed_ = other.isReversed_; + + goog.dom.TextRangeIterator.superClass_.copyFrom.call(this, other); +}; + + +/** + * @return {!goog.dom.TextRangeIterator} An identical iterator. + * @override + */ +goog.dom.TextRangeIterator.prototype.clone = function() { + var copy = new goog.dom.TextRangeIterator(this.startNode_, + this.startOffset_, this.endNode_, this.endOffset_, this.isReversed_); + copy.copyFrom(this); + return copy; +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/vendor.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/vendor.js b/externs/GCL/externs/goog/dom/vendor.js new file mode 100644 index 0000000..7c1123e --- /dev/null +++ b/externs/GCL/externs/goog/dom/vendor.js @@ -0,0 +1,96 @@ +// Copyright 2012 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 Vendor prefix getters. + */ + +goog.provide('goog.dom.vendor'); + +goog.require('goog.string'); +goog.require('goog.userAgent'); + + +/** + * Returns the JS vendor prefix used in CSS properties. Different vendors + * use different methods of changing the case of the property names. + * + * @return {?string} The JS vendor prefix or null if there is none. + */ +goog.dom.vendor.getVendorJsPrefix = function() { + if (goog.userAgent.WEBKIT) { + return 'Webkit'; + } else if (goog.userAgent.GECKO) { + return 'Moz'; + } else if (goog.userAgent.IE) { + return 'ms'; + } else if (goog.userAgent.OPERA) { + return 'O'; + } + + return null; +}; + + +/** + * Returns the vendor prefix used in CSS properties. + * + * @return {?string} The vendor prefix or null if there is none. + */ +goog.dom.vendor.getVendorPrefix = function() { + if (goog.userAgent.WEBKIT) { + return '-webkit'; + } else if (goog.userAgent.GECKO) { + return '-moz'; + } else if (goog.userAgent.IE) { + return '-ms'; + } else if (goog.userAgent.OPERA) { + return '-o'; + } + + return null; +}; + + +/** + * @param {string} propertyName A property name. + * @param {!Object=} opt_object If provided, we verify if the property exists in + * the object. + * @return {?string} A vendor prefixed property name, or null if it does not + * exist. + */ +goog.dom.vendor.getPrefixedPropertyName = function(propertyName, opt_object) { + // We first check for a non-prefixed property, if available. + if (opt_object && propertyName in opt_object) { + return propertyName; + } + var prefix = goog.dom.vendor.getVendorJsPrefix(); + if (prefix) { + prefix = prefix.toLowerCase(); + var prefixedPropertyName = prefix + goog.string.toTitleCase(propertyName); + return (!goog.isDef(opt_object) || prefixedPropertyName in opt_object) ? + prefixedPropertyName : null; + } + return null; +}; + + +/** + * @param {string} eventType An event type. + * @return {string} A lower-cased vendor prefixed event type. + */ +goog.dom.vendor.getPrefixedEventType = function(eventType) { + var prefix = goog.dom.vendor.getVendorJsPrefix() || ''; + return (prefix + eventType).toLowerCase(); +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/viewportsizemonitor.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/viewportsizemonitor.js b/externs/GCL/externs/goog/dom/viewportsizemonitor.js new file mode 100644 index 0000000..2f5f30e --- /dev/null +++ b/externs/GCL/externs/goog/dom/viewportsizemonitor.js @@ -0,0 +1,165 @@ +// Copyright 2007 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 Utility class that monitors viewport size changes. + * + * @author [email protected] (Attila Bodis) + * @see ../demos/viewportsizemonitor.html + */ + +goog.provide('goog.dom.ViewportSizeMonitor'); + +goog.require('goog.dom'); +goog.require('goog.events'); +goog.require('goog.events.EventTarget'); +goog.require('goog.events.EventType'); +goog.require('goog.math.Size'); + + + +/** + * This class can be used to monitor changes in the viewport size. Instances + * dispatch a {@link goog.events.EventType.RESIZE} event when the viewport size + * changes. Handlers can call {@link goog.dom.ViewportSizeMonitor#getSize} to + * get the new viewport size. + * + * Use this class if you want to execute resize/reflow logic each time the + * user resizes the browser window. This class is guaranteed to only dispatch + * {@code RESIZE} events when the pixel dimensions of the viewport change. + * (Internet Explorer fires resize events if any element on the page is resized, + * even if the viewport dimensions are unchanged, which can lead to infinite + * resize loops.) + * + * Example usage: + * <pre> + * var vsm = new goog.dom.ViewportSizeMonitor(); + * goog.events.listen(vsm, goog.events.EventType.RESIZE, function(e) { + * alert('Viewport size changed to ' + vsm.getSize()); + * }); + * </pre> + * + * Manually verified on IE6, IE7, FF2, Opera 11, Safari 4 and Chrome. + * + * @param {Window=} opt_window The window to monitor; defaults to the window in + * which this code is executing. + * @constructor + * @extends {goog.events.EventTarget} + */ +goog.dom.ViewportSizeMonitor = function(opt_window) { + goog.dom.ViewportSizeMonitor.base(this, 'constructor'); + + /** + * The window to monitor. Defaults to the window in which the code is running. + * @private {Window} + */ + this.window_ = opt_window || window; + + /** + * Event listener key for window the window resize handler, as returned by + * {@link goog.events.listen}. + * @private {goog.events.Key} + */ + this.listenerKey_ = goog.events.listen(this.window_, + goog.events.EventType.RESIZE, this.handleResize_, false, this); + + /** + * The most recently recorded size of the viewport, in pixels. + * @private {goog.math.Size} + */ + this.size_ = goog.dom.getViewportSize(this.window_); +}; +goog.inherits(goog.dom.ViewportSizeMonitor, goog.events.EventTarget); + + +/** + * Returns a viewport size monitor for the given window. A new one is created + * if it doesn't exist already. This prevents the unnecessary creation of + * multiple spooling monitors for a window. + * @param {Window=} opt_window The window to monitor; defaults to the window in + * which this code is executing. + * @return {!goog.dom.ViewportSizeMonitor} Monitor for the given window. + */ +goog.dom.ViewportSizeMonitor.getInstanceForWindow = function(opt_window) { + var currentWindow = opt_window || window; + var uid = goog.getUid(currentWindow); + + return goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] = + goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] || + new goog.dom.ViewportSizeMonitor(currentWindow); +}; + + +/** + * Removes and disposes a viewport size monitor for the given window if one + * exists. + * @param {Window=} opt_window The window whose monitor should be removed; + * defaults to the window in which this code is executing. + */ +goog.dom.ViewportSizeMonitor.removeInstanceForWindow = function(opt_window) { + var uid = goog.getUid(opt_window || window); + + goog.dispose(goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]); + delete goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]; +}; + + +/** + * Map of window hash code to viewport size monitor for that window, if + * created. + * @type {Object<number,goog.dom.ViewportSizeMonitor>} + * @private + */ +goog.dom.ViewportSizeMonitor.windowInstanceMap_ = {}; + + +/** + * Returns the most recently recorded size of the viewport, in pixels. May + * return null if no window resize event has been handled yet. + * @return {goog.math.Size} The viewport dimensions, in pixels. + */ +goog.dom.ViewportSizeMonitor.prototype.getSize = function() { + // Return a clone instead of the original to preserve encapsulation. + return this.size_ ? this.size_.clone() : null; +}; + + +/** @override */ +goog.dom.ViewportSizeMonitor.prototype.disposeInternal = function() { + goog.dom.ViewportSizeMonitor.superClass_.disposeInternal.call(this); + + if (this.listenerKey_) { + goog.events.unlistenByKey(this.listenerKey_); + this.listenerKey_ = null; + } + + this.window_ = null; + this.size_ = null; +}; + + +/** + * Handles window resize events by measuring the dimensions of the + * viewport and dispatching a {@link goog.events.EventType.RESIZE} event if the + * current dimensions are different from the previous ones. + * @param {goog.events.Event} event The window resize event to handle. + * @private + */ +goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) { + var size = goog.dom.getViewportSize(this.window_); + if (!goog.math.Size.equals(size, this.size_)) { + this.size_ = size; + this.dispatchEvent(goog.events.EventType.RESIZE); + } +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/xml.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/dom/xml.js b/externs/GCL/externs/goog/dom/xml.js new file mode 100644 index 0000000..59f123a --- /dev/null +++ b/externs/GCL/externs/goog/dom/xml.js @@ -0,0 +1,204 @@ +// Copyright 2006 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 + * XML utilities. + * + */ + +goog.provide('goog.dom.xml'); + +goog.require('goog.dom'); +goog.require('goog.dom.NodeType'); + + +/** + * Max XML size for MSXML2. Used to prevent potential DoS attacks. + * @type {number} + */ +goog.dom.xml.MAX_XML_SIZE_KB = 2 * 1024; // In kB + + +/** + * Max XML size for MSXML2. Used to prevent potential DoS attacks. + * @type {number} + */ +goog.dom.xml.MAX_ELEMENT_DEPTH = 256; // Same default as MSXML6. + + +/** + * Creates an XML document appropriate for the current JS runtime + * @param {string=} opt_rootTagName The root tag name. + * @param {string=} opt_namespaceUri Namespace URI of the document element. + * @return {Document} The new document. + */ +goog.dom.xml.createDocument = function(opt_rootTagName, opt_namespaceUri) { + if (opt_namespaceUri && !opt_rootTagName) { + throw Error("Can't create document with namespace and no root tag"); + } + if (document.implementation && document.implementation.createDocument) { + return document.implementation.createDocument(opt_namespaceUri || '', + opt_rootTagName || '', + null); + } else if (typeof ActiveXObject != 'undefined') { + var doc = goog.dom.xml.createMsXmlDocument_(); + if (doc) { + if (opt_rootTagName) { + doc.appendChild(doc.createNode(goog.dom.NodeType.ELEMENT, + opt_rootTagName, + opt_namespaceUri || '')); + } + return doc; + } + } + throw Error('Your browser does not support creating new documents'); +}; + + +/** + * Creates an XML document from a string + * @param {string} xml The text. + * @return {Document} XML document from the text. + */ +goog.dom.xml.loadXml = function(xml) { + if (typeof DOMParser != 'undefined') { + return new DOMParser().parseFromString(xml, 'application/xml'); + } else if (typeof ActiveXObject != 'undefined') { + var doc = goog.dom.xml.createMsXmlDocument_(); + doc.loadXML(xml); + return doc; + } + throw Error('Your browser does not support loading xml documents'); +}; + + +/** + * Serializes an XML document or subtree to string. + * @param {Document|Element} xml The document or the root node of the subtree. + * @return {string} The serialized XML. + */ +goog.dom.xml.serialize = function(xml) { + // Compatible with Firefox, Opera and WebKit. + if (typeof XMLSerializer != 'undefined') { + return new XMLSerializer().serializeToString(xml); + } + // Compatible with Internet Explorer. + var text = xml.xml; + if (text) { + return text; + } + throw Error('Your browser does not support serializing XML documents'); +}; + + +/** + * Selects a single node using an Xpath expression and a root node + * @param {Node} node The root node. + * @param {string} path Xpath selector. + * @return {Node} The selected node, or null if no matching node. + */ +goog.dom.xml.selectSingleNode = function(node, path) { + if (typeof node.selectSingleNode != 'undefined') { + var doc = goog.dom.getOwnerDocument(node); + if (typeof doc.setProperty != 'undefined') { + doc.setProperty('SelectionLanguage', 'XPath'); + } + return node.selectSingleNode(path); + } else if (document.implementation.hasFeature('XPath', '3.0')) { + var doc = goog.dom.getOwnerDocument(node); + var resolver = doc.createNSResolver(doc.documentElement); + var result = doc.evaluate(path, node, resolver, + XPathResult.FIRST_ORDERED_NODE_TYPE, null); + return result.singleNodeValue; + } + return null; +}; + + +/** + * Selects multiple nodes using an Xpath expression and a root node + * @param {Node} node The root node. + * @param {string} path Xpath selector. + * @return {(NodeList|Array<Node>)} The selected nodes, or empty array if no + * matching nodes. + */ +goog.dom.xml.selectNodes = function(node, path) { + if (typeof node.selectNodes != 'undefined') { + var doc = goog.dom.getOwnerDocument(node); + if (typeof doc.setProperty != 'undefined') { + doc.setProperty('SelectionLanguage', 'XPath'); + } + return node.selectNodes(path); + } else if (document.implementation.hasFeature('XPath', '3.0')) { + var doc = goog.dom.getOwnerDocument(node); + var resolver = doc.createNSResolver(doc.documentElement); + var nodes = doc.evaluate(path, node, resolver, + XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + var results = []; + var count = nodes.snapshotLength; + for (var i = 0; i < count; i++) { + results.push(nodes.snapshotItem(i)); + } + return results; + } else { + return []; + } +}; + + +/** + * Sets multiple attributes on an element. Differs from goog.dom.setProperties + * in that it exclusively uses the element's setAttributes method. Use this + * when you need to ensure that the exact property is available as an attribute + * and can be read later by the native getAttribute method. + * @param {!Element} element XML or DOM element to set attributes on. + * @param {!Object<string, string>} attributes Map of property:value pairs. + */ +goog.dom.xml.setAttributes = function(element, attributes) { + for (var key in attributes) { + if (attributes.hasOwnProperty(key)) { + element.setAttribute(key, attributes[key]); + } + } +}; + + +/** + * Creates an instance of the MSXML2.DOMDocument. + * @return {Document} The new document. + * @private + */ +goog.dom.xml.createMsXmlDocument_ = function() { + var doc = new ActiveXObject('MSXML2.DOMDocument'); + if (doc) { + // Prevent potential vulnerabilities exposed by MSXML2, see + // http://b/1707300 and http://wiki/Main/ISETeamXMLAttacks for details. + doc.resolveExternals = false; + doc.validateOnParse = false; + // Add a try catch block because accessing these properties will throw an + // error on unsupported MSXML versions. This affects Windows machines + // running IE6 or IE7 that are on XP SP2 or earlier without MSXML updates. + // See http://msdn.microsoft.com/en-us/library/ms766391(VS.85).aspx for + // specific details on which MSXML versions support these properties. + try { + doc.setProperty('ProhibitDTD', true); + doc.setProperty('MaxXMLSize', goog.dom.xml.MAX_XML_SIZE_KB); + doc.setProperty('MaxElementDepth', goog.dom.xml.MAX_ELEMENT_DEPTH); + } catch (e) { + // No-op. + } + } + return doc; +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/browserfeature2.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/editor/browserfeature2.js b/externs/GCL/externs/goog/editor/browserfeature2.js new file mode 100644 index 0000000..10ac05e --- /dev/null +++ b/externs/GCL/externs/goog/editor/browserfeature2.js @@ -0,0 +1,273 @@ +// Copyright 2005 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 Trogedit constants for browser features and quirks that should + * be used by the rich text editor. + */ + +goog.provide('goog.editor.BrowserFeature'); + +goog.require('goog.editor.defines'); +goog.require('goog.userAgent'); +goog.require('goog.userAgent.product'); +goog.require('goog.userAgent.product.isVersion'); + + +/** + * Maps browser quirks to boolean values, detailing what the current + * browser supports. + * @const + */ +goog.editor.BrowserFeature = { + // Whether this browser uses the IE TextRange object. + HAS_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9), + + // Whether this browser uses the W3C standard Range object. + // Assumes IE higher versions will be compliance with W3C standard. + HAS_W3C_RANGES: goog.userAgent.GECKO || goog.userAgent.WEBKIT || + goog.userAgent.OPERA || + (goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9)), + + // Has the contentEditable attribute, which makes nodes editable. + // + // NOTE(nicksantos): FF3 has contentEditable, but there are 3 major reasons + // why we don't use it: + // 1) In FF3, we listen for key events on the document, and we'd have to + // filter them properly. See TR_Browser.USE_DOCUMENT_FOR_KEY_EVENTS. + // 2) In FF3, we listen for focus/blur events on the document, which + // simply doesn't make sense in contentEditable. focus/blur + // on contentEditable elements still has some quirks, which we're + // talking to Firefox-team about. + // 3) We currently use Mutation events in FF3 to detect changes, + // and these are dispatched on the document only. + // If we ever hope to support FF3/contentEditable, all 3 of these issues + // will need answers. Most just involve refactoring at our end. + HAS_CONTENT_EDITABLE: goog.userAgent.IE || goog.userAgent.WEBKIT || + goog.userAgent.OPERA || + (goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3 && + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9')), + + // Whether to use mutation event types to detect changes + // in the field contents. + USE_MUTATION_EVENTS: goog.userAgent.GECKO, + + // Whether the browser has a functional DOMSubtreeModified event. + // TODO(user): Enable for all FF3 once we're confident this event fires + // reliably. Currently it's only enabled if using contentEditable in FF as + // we have no other choice in that case but to use this event. + HAS_DOM_SUBTREE_MODIFIED_EVENT: goog.userAgent.WEBKIT || + (goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3 && + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9')), + + // Whether nodes can be copied from one document to another + HAS_DOCUMENT_INDEPENDENT_NODES: goog.userAgent.GECKO, + + // Whether the cursor goes before or inside the first block element on + // focus, e.g., <body><p>foo</p></body>. FF will put the cursor before the + // paragraph on focus, which is wrong. + PUTS_CURSOR_BEFORE_FIRST_BLOCK_ELEMENT_ON_FOCUS: goog.userAgent.GECKO, + + // Whether the selection of one frame is cleared when another frame + // is focused. + CLEARS_SELECTION_WHEN_FOCUS_LEAVES: + goog.userAgent.IE || goog.userAgent.WEBKIT || goog.userAgent.OPERA, + + // Whether "unselectable" is supported as an element style. + HAS_UNSELECTABLE_STYLE: goog.userAgent.GECKO || goog.userAgent.WEBKIT, + + // Whether this browser's "FormatBlock" command does not suck. + FORMAT_BLOCK_WORKS_FOR_BLOCKQUOTES: goog.userAgent.GECKO || + goog.userAgent.WEBKIT || goog.userAgent.OPERA, + + // Whether this browser's "FormatBlock" command may create multiple + // blockquotes. + CREATES_MULTIPLE_BLOCKQUOTES: + (goog.userAgent.WEBKIT && + !goog.userAgent.isVersionOrHigher('534.16')) || + goog.userAgent.OPERA, + + // Whether this browser's "FormatBlock" command will wrap blockquotes + // inside of divs, instead of replacing divs with blockquotes. + WRAPS_BLOCKQUOTE_IN_DIVS: goog.userAgent.OPERA, + + // Whether the readystatechange event is more reliable than load. + PREFERS_READY_STATE_CHANGE_EVENT: goog.userAgent.IE, + + // Whether hitting the tab key will fire a keypress event. + // see http://www.quirksmode.org/js/keys.html + TAB_FIRES_KEYPRESS: !goog.userAgent.IE, + + // Has a standards mode quirk where width=100% doesn't do the right thing, + // but width=99% does. + // TODO(user|user): This should be fixable by less hacky means + NEEDS_99_WIDTH_IN_STANDARDS_MODE: goog.userAgent.IE, + + // Whether keyboard events only reliably fire on the document. + // On Gecko without contentEditable, keyboard events only fire reliably on the + // document element. With contentEditable, the field itself is focusable, + // which means that it will fire key events. This does not apply if + // application is using ContentEditableField or otherwise overriding Field + // not to use an iframe. + USE_DOCUMENT_FOR_KEY_EVENTS: goog.userAgent.GECKO && + !goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3, + + // Whether this browser shows non-standard attributes in innerHTML. + SHOWS_CUSTOM_ATTRS_IN_INNER_HTML: goog.userAgent.IE, + + // Whether this browser shrinks empty nodes away to nothing. + // (If so, we need to insert some space characters into nodes that + // shouldn't be collapsed) + COLLAPSES_EMPTY_NODES: + goog.userAgent.GECKO || goog.userAgent.WEBKIT || goog.userAgent.OPERA, + + // Whether we must convert <strong> and <em> tags to <b>, <i>. + CONVERT_TO_B_AND_I_TAGS: goog.userAgent.GECKO || goog.userAgent.OPERA, + + // Whether this browser likes to tab through images in contentEditable mode, + // and we like to disable this feature. + TABS_THROUGH_IMAGES: goog.userAgent.IE, + + // Whether this browser unescapes urls when you extract it from the href tag. + UNESCAPES_URLS_WITHOUT_ASKING: goog.userAgent.IE && + !goog.userAgent.isVersionOrHigher('7.0'), + + // Whether this browser supports execCommand("styleWithCSS") to toggle between + // inserting html tags or inline styling for things like bold, italic, etc. + HAS_STYLE_WITH_CSS: + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.8') || + goog.userAgent.WEBKIT || goog.userAgent.OPERA, + + // Whether clicking on an editable link will take you to that site. + FOLLOWS_EDITABLE_LINKS: goog.userAgent.WEBKIT || + goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9'), + + // Whether this browser has document.activeElement available. + HAS_ACTIVE_ELEMENT: + goog.userAgent.IE || goog.userAgent.OPERA || + goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9'), + + // Whether this browser supports the setCapture method on DOM elements. + HAS_SET_CAPTURE: goog.userAgent.IE, + + // Whether this browser can't set background color when the selection + // is collapsed. + EATS_EMPTY_BACKGROUND_COLOR: goog.userAgent.GECKO || + goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('527'), + + // Whether this browser supports the "focusin" or "DOMFocusIn" event + // consistently. + // NOTE(nicksantos): FF supports DOMFocusIn, but doesn't seem to do so + // consistently. + SUPPORTS_FOCUSIN: goog.userAgent.IE || goog.userAgent.OPERA, + + // Whether clicking on an image will cause the selection to move to the image. + // Note: Gecko moves the selection, but it won't always go to the image. + // For example, if the image is wrapped in a div, and you click on the img, + // anchorNode = focusNode = div, anchorOffset = 0, focusOffset = 1, so this + // is another way of "selecting" the image, but there are too many special + // cases like this so we will do the work manually. + SELECTS_IMAGES_ON_CLICK: goog.userAgent.IE || goog.userAgent.OPERA, + + // Whether this browser moves <style> tags into new <head> elements. + MOVES_STYLE_TO_HEAD: goog.userAgent.WEBKIT, + + // Whether this browser collapses the selection in a contenteditable when the + // mouse is pressed in a non-editable portion of the same frame, even if + // Event.preventDefault is called. This field is deprecated and unused -- only + // old versions of Opera have this bug. + COLLAPSES_SELECTION_ONMOUSEDOWN: false, + + // Whether the user can actually create a selection in this browser with the + // caret in the MIDDLE of the selection by double-clicking. + CARET_INSIDE_SELECTION: goog.userAgent.OPERA, + + // Whether the browser focuses <body contenteditable> automatically when + // the user clicks on <html>. This field is deprecated and unused -- only old + // versions of Opera don't have this behavior. + FOCUSES_EDITABLE_BODY_ON_HTML_CLICK: true, + + // Whether to use keydown for key listening (uses keypress otherwise). Taken + // from goog.events.KeyHandler. + USES_KEYDOWN: goog.userAgent.IE || + goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'), + + // Whether this browser converts spaces to non-breaking spaces when calling + // execCommand's RemoveFormat. + // See: https://bugs.webkit.org/show_bug.cgi?id=14062 + ADDS_NBSPS_IN_REMOVE_FORMAT: + goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('531'), + + // Whether the browser will get stuck inside a link. That is, if your cursor + // is after a link and you type, does your text go inside the link tag. + // Bug: http://bugs.webkit.org/show_bug.cgi?id=17697 + GETS_STUCK_IN_LINKS: + goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('528'), + + // Whether the browser corrupts empty text nodes in Node#normalize, + // removing them from the Document instead of merging them. + NORMALIZE_CORRUPTS_EMPTY_TEXT_NODES: goog.userAgent.GECKO && + goog.userAgent.isVersionOrHigher('1.9') || goog.userAgent.IE || + goog.userAgent.OPERA || + goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('531'), + + // Whether the browser corrupts all text nodes in Node#normalize, + // removing them from the Document instead of merging them. + NORMALIZE_CORRUPTS_ALL_TEXT_NODES: goog.userAgent.IE, + + // Browsers where executing subscript then superscript (or vv) will cause both + // to be applied in a nested fashion instead of the first being overwritten by + // the second. + NESTS_SUBSCRIPT_SUPERSCRIPT: goog.userAgent.IE || goog.userAgent.GECKO || + goog.userAgent.OPERA, + + // Whether this browser can place a cursor in an empty element natively. + CAN_SELECT_EMPTY_ELEMENT: !goog.userAgent.IE && !goog.userAgent.WEBKIT, + + FORGETS_FORMATTING_WHEN_LISTIFYING: goog.userAgent.GECKO || + goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('526'), + + LEAVES_P_WHEN_REMOVING_LISTS: goog.userAgent.IE || goog.userAgent.OPERA, + + CAN_LISTIFY_BR: !goog.userAgent.IE && !goog.userAgent.OPERA, + + // See bug 1286408. When somewhere inside your selection there is an element + // with a style attribute that sets the font size, if you change the font + // size, the browser creates a font tag, but the font size in the style attr + // overrides the font tag. Only webkit removes that font size from the style + // attr. + DOESNT_OVERRIDE_FONT_SIZE_IN_STYLE_ATTR: !goog.userAgent.WEBKIT, + + // Implements this spec about dragging files from the filesystem to the + // browser: http://www.whatwg/org/specs/web-apps/current-work/#dnd + SUPPORTS_HTML5_FILE_DRAGGING: (goog.userAgent.product.CHROME && + goog.userAgent.product.isVersion('4')) || + (goog.userAgent.product.SAFARI && + goog.userAgent.isVersionOrHigher('533')) || + (goog.userAgent.GECKO && + goog.userAgent.isVersionOrHigher('2.0')) || + (goog.userAgent.IE && + goog.userAgent.isVersionOrHigher('10')), + + // Version of Opera that supports the opera-defaultBlock execCommand to change + // the default block inserted when [return] is pressed. Note that this only is + // used if the caret is not already in a block that can be repeated. + // TODO(user): Link to public documentation of this feature if Opera puts + // something up about it. + SUPPORTS_OPERA_DEFAULTBLOCK_COMMAND: + goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('11.10'), + + SUPPORTS_FILE_PASTING: goog.userAgent.product.CHROME && + goog.userAgent.product.isVersion('12') +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/clicktoeditwrapper.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/editor/clicktoeditwrapper.js b/externs/GCL/externs/goog/editor/clicktoeditwrapper.js new file mode 100644 index 0000000..1623f0d --- /dev/null +++ b/externs/GCL/externs/goog/editor/clicktoeditwrapper.js @@ -0,0 +1,423 @@ +// Copyright 2007 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 A wrapper around a goog.editor.Field + * that listens to mouse events on the specified un-editable field, and makes + * the field editable if the user clicks on it. Clients are still responsible + * for determining when to make the field un-editable again. + * + * Clients can still determine when the field has loaded by listening to + * field's load event. + * + * @author [email protected] (Nick Santos) + */ + +goog.provide('goog.editor.ClickToEditWrapper'); + +goog.require('goog.Disposable'); +goog.require('goog.dom'); +goog.require('goog.dom.Range'); +goog.require('goog.dom.TagName'); +goog.require('goog.editor.BrowserFeature'); +goog.require('goog.editor.Command'); +goog.require('goog.editor.Field'); +goog.require('goog.editor.range'); +goog.require('goog.events.BrowserEvent'); +goog.require('goog.events.EventHandler'); +goog.require('goog.events.EventType'); + + + +/** + * Initialize the wrapper, and begin listening to mouse events immediately. + * @param {goog.editor.Field} fieldObj The editable field being wrapped. + * @constructor + * @extends {goog.Disposable} + */ +goog.editor.ClickToEditWrapper = function(fieldObj) { + goog.Disposable.call(this); + + /** + * The field this wrapper interacts with. + * @type {goog.editor.Field} + * @private + */ + this.fieldObj_ = fieldObj; + + /** + * DOM helper for the field's original element. + * @type {goog.dom.DomHelper} + * @private + */ + this.originalDomHelper_ = goog.dom.getDomHelper( + fieldObj.getOriginalElement()); + + /** + * @type {goog.dom.SavedCaretRange} + * @private + */ + this.savedCaretRange_ = null; + + /** + * Event handler for field related events. + * @type {!goog.events.EventHandler<!goog.editor.ClickToEditWrapper>} + * @private + */ + this.fieldEventHandler_ = new goog.events.EventHandler(this); + + /** + * Bound version of the finishMouseUp method. + * @type {Function} + * @private + */ + this.finishMouseUpBound_ = goog.bind(this.finishMouseUp_, this); + + /** + * Event handler for mouse events. + * @type {!goog.events.EventHandler<!goog.editor.ClickToEditWrapper>} + * @private + */ + this.mouseEventHandler_ = new goog.events.EventHandler(this); + + // Start listening to mouse events immediately if necessary. + if (!this.fieldObj_.isLoaded()) { + this.enterDocument(); + } + + this.fieldEventHandler_. + // Whenever the field is made editable, we need to check if there + // are any carets in it, and if so, use them to render the selection. + listen( + this.fieldObj_, goog.editor.Field.EventType.LOAD, + this.renderSelection_). + // Whenever the field is made uneditable, we need to set up + // the click-to-edit listeners. + listen( + this.fieldObj_, goog.editor.Field.EventType.UNLOAD, + this.enterDocument); +}; +goog.inherits(goog.editor.ClickToEditWrapper, goog.Disposable); + + + +/** @return {goog.editor.Field} The field. */ +goog.editor.ClickToEditWrapper.prototype.getFieldObject = function() { + return this.fieldObj_; +}; + + +/** @return {goog.dom.DomHelper} The dom helper of the uneditable element. */ +goog.editor.ClickToEditWrapper.prototype.getOriginalDomHelper = function() { + return this.originalDomHelper_; +}; + + +/** @override */ +goog.editor.ClickToEditWrapper.prototype.disposeInternal = function() { + goog.editor.ClickToEditWrapper.base(this, 'disposeInternal'); + this.exitDocument(); + + if (this.savedCaretRange_) { + this.savedCaretRange_.dispose(); + } + + this.fieldEventHandler_.dispose(); + this.mouseEventHandler_.dispose(); + this.savedCaretRange_ = null; + delete this.fieldEventHandler_; + delete this.mouseEventHandler_; +}; + + +/** + * Initialize listeners when the uneditable field is added to the document. + * Also sets up lorem ipsum text. + */ +goog.editor.ClickToEditWrapper.prototype.enterDocument = function() { + if (this.isInDocument_) { + return; + } + + this.isInDocument_ = true; + + this.mouseEventTriggeredLoad_ = false; + var field = this.fieldObj_.getOriginalElement(); + + // To do artificial selection preservation, we have to listen to mouseup, + // get the current selection, and re-select the same text in the iframe. + // + // NOTE(nicksantos): Artificial selection preservation is needed in all cases + // where we set the field contents by setting innerHTML. There are a few + // rare cases where we don't need it. But these cases are highly + // implementation-specific, and computationally hard to detect (bidi + // and ig modules both set innerHTML), so we just do it in all cases. + this.savedAnchorClicked_ = null; + this.mouseEventHandler_. + listen(field, goog.events.EventType.MOUSEUP, this.handleMouseUp_). + listen(field, goog.events.EventType.CLICK, this.handleClick_); + + // manage lorem ipsum text, if necessary + this.fieldObj_.execCommand(goog.editor.Command.UPDATE_LOREM); +}; + + +/** + * Destroy listeners when the field is removed from the document. + */ +goog.editor.ClickToEditWrapper.prototype.exitDocument = function() { + this.mouseEventHandler_.removeAll(); + this.isInDocument_ = false; +}; + + +/** + * Returns the uneditable field element if the field is not yet editable + * (equivalent to EditableField.getOriginalElement()), and the editable DOM + * element if the field is currently editable (equivalent to + * EditableField.getElement()). + * @return {Element} The element containing the editable field contents. + */ +goog.editor.ClickToEditWrapper.prototype.getElement = function() { + return this.fieldObj_.isLoaded() ? + this.fieldObj_.getElement() : this.fieldObj_.getOriginalElement(); +}; + + +/** + * True if a mouse event should be handled, false if it should be ignored. + * @param {goog.events.BrowserEvent} e The mouse event. + * @return {boolean} Wether or not this mouse event should be handled. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.shouldHandleMouseEvent_ = function(e) { + return e.isButton(goog.events.BrowserEvent.MouseButton.LEFT) && + !(e.shiftKey || e.ctrlKey || e.altKey || e.metaKey); +}; + + +/** + * Handle mouse click events on the field. + * @param {goog.events.BrowserEvent} e The click event. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.handleClick_ = function(e) { + // If the user clicked on a link in an uneditable field, + // we want to cancel the click. + var anchorAncestor = goog.dom.getAncestorByTagNameAndClass( + /** @type {Node} */ (e.target), + goog.dom.TagName.A); + if (anchorAncestor) { + e.preventDefault(); + + if (!goog.editor.BrowserFeature.HAS_ACTIVE_ELEMENT) { + this.savedAnchorClicked_ = anchorAncestor; + } + } +}; + + +/** + * Handle a mouse up event on the field. + * @param {goog.events.BrowserEvent} e The mouseup event. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.handleMouseUp_ = function(e) { + // Only respond to the left mouse button. + if (this.shouldHandleMouseEvent_(e)) { + // We need to get the selection when the user mouses up, but the + // selection doesn't actually change until after the mouseup event has + // propagated. So we need to do this asynchronously. + this.originalDomHelper_.getWindow().setTimeout(this.finishMouseUpBound_, 0); + } +}; + + +/** + * A helper function for handleMouseUp_ -- does the actual work + * when the event is finished propagating. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.finishMouseUp_ = function() { + // Make sure that the field is still not editable. + if (!this.fieldObj_.isLoaded()) { + if (this.savedCaretRange_) { + this.savedCaretRange_.dispose(); + this.savedCaretRange_ = null; + } + + if (!this.fieldObj_.queryCommandValue(goog.editor.Command.USING_LOREM)) { + // We need carets (blank span nodes) to maintain the selection when + // the html is copied into an iframe. However, because our code + // clears the selection to make the behavior consistent, we need to do + // this even when we're not using an iframe. + this.insertCarets_(); + } + + this.ensureFieldEditable_(); + } + + this.exitDocument(); + this.savedAnchorClicked_ = null; +}; + + +/** + * Ensure that the field is editable. If the field is not editable, + * make it so, and record the fact that it was done by a user mouse event. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.ensureFieldEditable_ = function() { + if (!this.fieldObj_.isLoaded()) { + this.mouseEventTriggeredLoad_ = true; + this.makeFieldEditable(this.fieldObj_); + } +}; + + +/** + * Once the field has loaded in an iframe, re-create the selection + * as marked by the carets. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.renderSelection_ = function() { + if (this.savedCaretRange_) { + // Make sure that the restoration document is inside the iframe + // if we're using one. + this.savedCaretRange_.setRestorationDocument( + this.fieldObj_.getEditableDomHelper().getDocument()); + + var startCaret = this.savedCaretRange_.getCaret(true); + var endCaret = this.savedCaretRange_.getCaret(false); + var hasCarets = startCaret && endCaret; + } + + // There are two reasons why we might want to focus the field: + // 1) makeFieldEditable was triggered by the click-to-edit wrapper. + // In this case, the mouse event should have triggered a focus, but + // the editor might have taken the focus away to create lorem ipsum + // text or create an iframe for the field. So we make sure the focus + // is restored. + // 2) somebody placed carets, and we need to select those carets. The field + // needs focus to ensure that the selection appears. + if (this.mouseEventTriggeredLoad_ || hasCarets) { + this.focusOnFieldObj(this.fieldObj_); + } + + if (hasCarets) { + + this.savedCaretRange_.restore(); + this.fieldObj_.dispatchSelectionChangeEvent(); + + // NOTE(nicksantos): Bubbles aren't actually enabled until the end + // if the load sequence, so if the user clicked on a link, the bubble + // will not pop up. + } + + if (this.savedCaretRange_) { + this.savedCaretRange_.dispose(); + this.savedCaretRange_ = null; + } + + this.mouseEventTriggeredLoad_ = false; +}; + + +/** + * Focus on the field object. + * @param {goog.editor.Field} field The field to focus. + * @protected + */ +goog.editor.ClickToEditWrapper.prototype.focusOnFieldObj = function(field) { + field.focusAndPlaceCursorAtStart(); +}; + + +/** + * Make the field object editable. + * @param {goog.editor.Field} field The field to make editable. + * @protected + */ +goog.editor.ClickToEditWrapper.prototype.makeFieldEditable = function(field) { + field.makeEditable(); +}; + + +//================================================================ +// Caret-handling methods + + +/** + * Gets a saved caret range for the given range. + * @param {goog.dom.AbstractRange} range A range wrapper. + * @return {goog.dom.SavedCaretRange} The range, saved with carets, or null + * if the range wrapper was null. + * @private + */ +goog.editor.ClickToEditWrapper.createCaretRange_ = function(range) { + return range && goog.editor.range.saveUsingNormalizedCarets(range); +}; + + +/** + * Inserts the carets, given the current selection. + * + * Note that for all practical purposes, a cursor position is just + * a selection with the start and end at the same point. + * @private + */ +goog.editor.ClickToEditWrapper.prototype.insertCarets_ = function() { + var fieldElement = this.fieldObj_.getOriginalElement(); + + this.savedCaretRange_ = null; + var originalWindow = this.originalDomHelper_.getWindow(); + if (goog.dom.Range.hasSelection(originalWindow)) { + var range = goog.dom.Range.createFromWindow(originalWindow); + range = range && goog.editor.range.narrow(range, fieldElement); + this.savedCaretRange_ = + goog.editor.ClickToEditWrapper.createCaretRange_(range); + } + + if (!this.savedCaretRange_) { + // We couldn't figure out where to put the carets. + // But in FF2/IE6+, this could mean that the user clicked on a + // 'special' node, (e.g., a link or an unselectable item). So the + // selection appears to be null or the full page, even though the user did + // click on something. In IE, we can determine the real selection via + // document.activeElement. In FF, we have to be more hacky. + var specialNodeClicked; + if (goog.editor.BrowserFeature.HAS_ACTIVE_ELEMENT) { + specialNodeClicked = goog.dom.getActiveElement( + this.originalDomHelper_.getDocument()); + } else { + specialNodeClicked = this.savedAnchorClicked_; + } + + var isFieldElement = function(node) { + return node == fieldElement; + }; + if (specialNodeClicked && + goog.dom.getAncestor(specialNodeClicked, isFieldElement, true)) { + // Insert the cursor at the beginning of the active element to be + // consistent with the behavior in FF1.5, where clicking on a + // link makes the current selection equal to the cursor position + // directly before that link. + // + // TODO(nicksantos): Is there a way to more accurately place the cursor? + this.savedCaretRange_ = goog.editor.ClickToEditWrapper.createCaretRange_( + goog.dom.Range.createFromNodes( + specialNodeClicked, 0, specialNodeClicked, 0)); + } + } +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/command.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/editor/command.js b/externs/GCL/externs/goog/editor/command.js new file mode 100644 index 0000000..2996b8c --- /dev/null +++ b/externs/GCL/externs/goog/editor/command.js @@ -0,0 +1,76 @@ +// Copyright 2009 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 Commands that the editor can execute. + * @see ../demos/editor/editor.html + */ +goog.provide('goog.editor.Command'); + + +/** + * Commands that the editor can excute via execCommand or queryCommandValue. + * @enum {string} + */ +goog.editor.Command = { + // Prepend all the strings of built in execCommands with a plus to ensure + // that there's no conflict if a client wants to use the + // browser's execCommand. + UNDO: '+undo', + REDO: '+redo', + LINK: '+link', + FORMAT_BLOCK: '+formatBlock', + INDENT: '+indent', + OUTDENT: '+outdent', + REMOVE_FORMAT: '+removeFormat', + STRIKE_THROUGH: '+strikeThrough', + HORIZONTAL_RULE: '+insertHorizontalRule', + SUBSCRIPT: '+subscript', + SUPERSCRIPT: '+superscript', + UNDERLINE: '+underline', + BOLD: '+bold', + ITALIC: '+italic', + FONT_SIZE: '+fontSize', + FONT_FACE: '+fontName', + FONT_COLOR: '+foreColor', + EMOTICON: '+emoticon', + EQUATION: '+equation', + BACKGROUND_COLOR: '+backColor', + ORDERED_LIST: '+insertOrderedList', + UNORDERED_LIST: '+insertUnorderedList', + TABLE: '+table', + JUSTIFY_CENTER: '+justifyCenter', + JUSTIFY_FULL: '+justifyFull', + JUSTIFY_RIGHT: '+justifyRight', + JUSTIFY_LEFT: '+justifyLeft', + BLOCKQUOTE: '+BLOCKQUOTE', // This is a nodename. Should be all caps. + DIR_LTR: 'ltr', // should be exactly 'ltr' as it becomes dir attribute value + DIR_RTL: 'rtl', // same here + IMAGE: 'image', + EDIT_HTML: 'editHtml', + UPDATE_LINK_BUBBLE: 'updateLinkBubble', + + // queryCommandValue only: returns the default tag name used in the field. + // DIV should be considered the default if no plugin responds. + DEFAULT_TAG: '+defaultTag', + + // TODO(nicksantos): Try to give clients an API so that they don't need + // these execCommands. + CLEAR_LOREM: 'clearlorem', + UPDATE_LOREM: 'updatelorem', + USING_LOREM: 'usinglorem', + + // Modal editor commands (usually dialogs). + MODAL_LINK_EDITOR: 'link' +}; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/contenteditablefield.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/editor/contenteditablefield.js b/externs/GCL/externs/goog/editor/contenteditablefield.js new file mode 100644 index 0000000..a30d245 --- /dev/null +++ b/externs/GCL/externs/goog/editor/contenteditablefield.js @@ -0,0 +1,108 @@ +// Copyright 2012 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 Class to encapsulate an editable field that blends into the + * style of the page and never uses an iframe. The field's height can be + * controlled by CSS styles like min-height, max-height, and overflow. This is + * a goog.editor.Field, but overrides everything iframe related to use + * contentEditable divs. This is essentially a much lighter alternative to + * goog.editor.SeamlessField, but only works in Firefox 3+, and only works + * *well* in Firefox 12+ due to + * https://bugzilla.mozilla.org/show_bug.cgi?id=669026. + * + * @author [email protected] (Garrett Boyer) + * @author [email protected] (Nick Santos) + */ + + +goog.provide('goog.editor.ContentEditableField'); + +goog.require('goog.asserts'); +goog.require('goog.editor.Field'); +goog.require('goog.log'); + + + +/** + * This class encapsulates an editable field that is just a contentEditable + * div. + * + * To see events fired by this object, please see the base class. + * + * @param {string} id An identifer for the field. This is used to find the + * field and the element associated with this field. + * @param {Document=} opt_doc The document that the element with the given + * id can be found in. + * @constructor + * @extends {goog.editor.Field} + */ +goog.editor.ContentEditableField = function(id, opt_doc) { + goog.editor.Field.call(this, id, opt_doc); +}; +goog.inherits(goog.editor.ContentEditableField, goog.editor.Field); + + +/** + * @override + */ +goog.editor.ContentEditableField.prototype.logger = + goog.log.getLogger('goog.editor.ContentEditableField'); + + +/** @override */ +goog.editor.ContentEditableField.prototype.usesIframe = function() { + // Never uses an iframe in any browser. + return false; +}; + + +// Overridden to improve dead code elimination only. +/** @override */ +goog.editor.ContentEditableField.prototype.turnOnDesignModeGecko = + goog.nullFunction; + + +/** @override */ +goog.editor.ContentEditableField.prototype.installStyles = function() { + goog.asserts.assert(!this.cssStyles, 'ContentEditableField does not support' + + ' CSS styles; instead just write plain old CSS on the main page.'); +}; + + +/** @override */ +goog.editor.ContentEditableField.prototype.makeEditableInternal = function( + opt_iframeSrc) { + var field = this.getOriginalElement(); + if (field) { + this.setupFieldObject(field); + // TODO(gboyer): Allow clients/plugins to override with 'plaintext-only' + // for WebKit. + field.contentEditable = true; + + this.injectContents(field.innerHTML, field); + + this.handleFieldLoad(); + } +}; + + +/** + * @override + * + * ContentEditableField does not make any changes to the DOM when it is made + * editable other than setting contentEditable to true. + */ +goog.editor.ContentEditableField.prototype.restoreDom = + goog.nullFunction; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/defines.js ---------------------------------------------------------------------- diff --git a/externs/GCL/externs/goog/editor/defines.js b/externs/GCL/externs/goog/editor/defines.js new file mode 100644 index 0000000..1bf57ba --- /dev/null +++ b/externs/GCL/externs/goog/editor/defines.js @@ -0,0 +1,34 @@ +// 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 Text editor constants for compile time feature selection. + * + */ + +goog.provide('goog.editor.defines'); + + +/** + * @define {boolean} Use contentEditable in FF. + * There are a number of known bugs when the only content in your field is + * inline (e.g. just text, no block elements): + * -indent is a noop and then DOMSubtreeModified events stop firing until + * the structure of the DOM is changed (e.g. make something bold). + * -inserting lists inserts just a NBSP, no list! + * Once those two are fixed, we should have one client guinea pig it and put + * it through a QA run. If we can file the bugs with Mozilla, there's a chance + * they'll fix them for a dot release of Firefox 3. + */ +goog.define('goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3', false);
