diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/editor/plugins/linkbubble.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/editor/plugins/linkbubble.js | 556 |
1 files changed, 0 insertions, 556 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/editor/plugins/linkbubble.js b/contexts/data/lib/closure-library/closure/goog/editor/plugins/linkbubble.js deleted file mode 100644 index 0707357..0000000 --- a/contexts/data/lib/closure-library/closure/goog/editor/plugins/linkbubble.js +++ /dev/null @@ -1,556 +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 Base class for bubble plugins. - * - */ - -goog.provide('goog.editor.plugins.LinkBubble'); -goog.provide('goog.editor.plugins.LinkBubble.Action'); - -goog.require('goog.array'); -goog.require('goog.dom'); -goog.require('goog.editor.BrowserFeature'); -goog.require('goog.editor.Command'); -goog.require('goog.editor.Link'); -goog.require('goog.editor.plugins.AbstractBubblePlugin'); -goog.require('goog.editor.range'); -goog.require('goog.string'); -goog.require('goog.style'); -goog.require('goog.ui.editor.messages'); -goog.require('goog.uri.utils'); -goog.require('goog.window'); - - - -/** - * Property bubble plugin for links. - * @param {...!goog.editor.plugins.LinkBubble.Action} var_args List of - * extra actions supported by the bubble. - * @constructor - * @extends {goog.editor.plugins.AbstractBubblePlugin} - */ -goog.editor.plugins.LinkBubble = function(var_args) { - goog.base(this); - - /** - * List of extra actions supported by the bubble. - * @type {Array.<!goog.editor.plugins.LinkBubble.Action>} - * @private - */ - this.extraActions_ = goog.array.toArray(arguments); - - /** - * List of spans corresponding to the extra actions. - * @type {Array.<!Element>} - * @private - */ - this.actionSpans_ = []; - - /** - * A list of whitelisted URL schemes which are safe to open. - * @type {Array.<string>} - * @private - */ - this.safeToOpenSchemes_ = ['http', 'https', 'ftp']; -}; -goog.inherits(goog.editor.plugins.LinkBubble, - goog.editor.plugins.AbstractBubblePlugin); - - -/** - * Element id for the link text. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.LINK_TEXT_ID_ = 'tr_link-text'; - - -/** - * Element id for the test link span. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.TEST_LINK_SPAN_ID_ = 'tr_test-link-span'; - - -/** - * Element id for the test link. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.TEST_LINK_ID_ = 'tr_test-link'; - - -/** - * Element id for the change link span. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.CHANGE_LINK_SPAN_ID_ = 'tr_change-link-span'; - - -/** - * Element id for the link. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.CHANGE_LINK_ID_ = 'tr_change-link'; - - -/** - * Element id for the delete link span. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.DELETE_LINK_SPAN_ID_ = 'tr_delete-link-span'; - - -/** - * Element id for the delete link. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.DELETE_LINK_ID_ = 'tr_delete-link'; - - -/** - * Element id for the link bubble wrapper div. - * type {string} - * @private - */ -goog.editor.plugins.LinkBubble.LINK_DIV_ID_ = 'tr_link-div'; - - -/** - * @desc Text label for link that lets the user click it to see where the link - * this bubble is for point to. - */ -var MSG_LINK_BUBBLE_TEST_LINK = goog.getMsg('Go to link: '); - - -/** - * @desc Label that pops up a dialog to change the link. - */ -var MSG_LINK_BUBBLE_CHANGE = goog.getMsg('Change'); - - -/** - * @desc Label that allow the user to remove this link. - */ -var MSG_LINK_BUBBLE_REMOVE = goog.getMsg('Remove'); - - -/** - * Whether to stop leaking the page's url via the referrer header when the - * link text link is clicked. - * @type {boolean} - * @private - */ -goog.editor.plugins.LinkBubble.prototype.stopReferrerLeaks_ = false; - - -/** - * Whether to block opening links with a non-whitelisted URL scheme. - * @type {boolean} - * @private - */ -goog.editor.plugins.LinkBubble.prototype.blockOpeningUnsafeSchemes_ = - true; - - -/** - * Tells the plugin to stop leaking the page's url via the referrer header when - * the link text link is clicked. When the user clicks on a link, the - * browser makes a request for the link url, passing the url of the current page - * in the request headers. If the user wants the current url to be kept secret - * (e.g. an unpublished document), the owner of the url that was clicked will - * see the secret url in the request headers, and it will no longer be a secret. - * Calling this method will not send a referrer header in the request, just as - * if the user had opened a blank window and typed the url in themselves. - */ -goog.editor.plugins.LinkBubble.prototype.stopReferrerLeaks = function() { - // TODO(user): Right now only 2 plugins have this API to stop - // referrer leaks. If more plugins need to do this, come up with a way to - // enable the functionality in all plugins at once. Same thing for - // setBlockOpeningUnsafeSchemes and associated functionality. - this.stopReferrerLeaks_ = true; -}; - - -/** - * Tells the plugin whether to block URLs with schemes not in the whitelist. - * If blocking is enabled, this plugin will not linkify the link in the bubble - * popup. - * @param {boolean} blockOpeningUnsafeSchemes Whether to block non-whitelisted - * schemes. - */ -goog.editor.plugins.LinkBubble.prototype.setBlockOpeningUnsafeSchemes = - function(blockOpeningUnsafeSchemes) { - this.blockOpeningUnsafeSchemes_ = blockOpeningUnsafeSchemes; -}; - - -/** - * Sets a whitelist of allowed URL schemes that are safe to open. - * Schemes should all be in lowercase. If the plugin is set to block opening - * unsafe schemes, user-entered URLs will be converted to lowercase and checked - * against this list. The whitelist has no effect if blocking is not enabled. - * @param {Array.<String>} schemes String array of URL schemes to allow (http, - * https, etc.). - */ -goog.editor.plugins.LinkBubble.prototype.setSafeToOpenSchemes = - function(schemes) { - this.safeToOpenSchemes_ = schemes; -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.getTrogClassId = function() { - return 'LinkBubble'; -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.isSupportedCommand = - function(command) { - return command == goog.editor.Command.UPDATE_LINK_BUBBLE; -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.execCommandInternal = - function(command, var_args) { - if (command == goog.editor.Command.UPDATE_LINK_BUBBLE) { - this.updateLink_(); - } -}; - - -/** - * Updates the href in the link bubble with a new link. - * @private - */ -goog.editor.plugins.LinkBubble.prototype.updateLink_ = function() { - var targetEl = this.getTargetElement(); - this.closeBubble(); - this.createBubble(targetEl); -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.getBubbleTargetFromSelection = - function(selectedElement) { - var bubbleTarget = goog.dom.getAncestorByTagNameAndClass(selectedElement, - goog.dom.TagName.A); - - if (!bubbleTarget) { - // See if the selection is touching the right side of a link, and if so, - // show a bubble for that link. The check for "touching" is very brittle, - // and currently only guarantees that it will pop up a bubble at the - // position the cursor is placed at after the link dialog is closed. - // NOTE(robbyw): This assumes this method is always called with - // selected element = range.getContainerElement(). Right now this is true, - // but attempts to re-use this method for other purposes could cause issues. - // TODO(robbyw): Refactor this method to also take a range, and use that. - var range = this.getFieldObject().getRange(); - if (range && range.isCollapsed() && range.getStartOffset() == 0) { - var startNode = range.getStartNode(); - var previous = startNode.previousSibling; - if (previous && previous.tagName == goog.dom.TagName.A) { - bubbleTarget = previous; - } - } - } - - return /** @type {Element} */ (bubbleTarget); -}; - - -/** - * Set the optional function for getting the "test" link of a url. - * @param {function(string) : string} func The function to use. - */ -goog.editor.plugins.LinkBubble.prototype.setTestLinkUrlFn = function(func) { - this.testLinkUrlFn_ = func; -}; - - -/** - * Returns the target element url for the bubble. - * @return {string} The url href. - * @protected - */ -goog.editor.plugins.LinkBubble.prototype.getTargetUrl = function() { - // Get the href-attribute through getAttribute() rather than the href property - // because Google-Toolbar on Firefox with "Send with Gmail" turned on - // modifies the href-property of 'mailto:' links but leaves the attribute - // untouched. - return this.getTargetElement().getAttribute('href') || ''; -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.getBubbleType = function() { - return goog.dom.TagName.A; -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.getBubbleTitle = function() { - return goog.ui.editor.messages.MSG_LINK_CAPTION; -}; - - -/** @override */ -goog.editor.plugins.LinkBubble.prototype.createBubbleContents = function( - bubbleContainer) { - var linkObj = this.getLinkToTextObj_(); - - // Create linkTextSpan, show plain text for e-mail address or truncate the - // text to <= 48 characters so that property bubbles don't grow too wide and - // create a link if URL. Only linkify valid links. - // TODO(robbyw): Repalce this color with a CSS class. - var color = linkObj.valid ? 'black' : 'red'; - var shouldOpenUrl = this.shouldOpenUrl(linkObj.linkText); - var linkTextSpan; - if (goog.editor.Link.isLikelyEmailAddress(linkObj.linkText) || - !linkObj.valid || !shouldOpenUrl) { - linkTextSpan = this.dom_.createDom(goog.dom.TagName.SPAN, - { - id: goog.editor.plugins.LinkBubble.LINK_TEXT_ID_, - style: 'color:' + color - }, this.dom_.createTextNode(linkObj.linkText)); - } else { - var testMsgSpan = this.dom_.createDom(goog.dom.TagName.SPAN, - {id: goog.editor.plugins.LinkBubble.TEST_LINK_SPAN_ID_}, - MSG_LINK_BUBBLE_TEST_LINK); - linkTextSpan = this.dom_.createDom(goog.dom.TagName.SPAN, - { - id: goog.editor.plugins.LinkBubble.LINK_TEXT_ID_, - style: 'color:' + color - }, ''); - var linkText = goog.string.truncateMiddle(linkObj.linkText, 48); - // Actually creates a pseudo-link that can't be right-clicked to open in a - // new tab, because that would avoid the logic to stop referrer leaks. - this.createLink(goog.editor.plugins.LinkBubble.TEST_LINK_ID_, - this.dom_.createTextNode(linkText).data, - this.testLink, - linkTextSpan); - } - - var changeLinkSpan = this.createLinkOption( - goog.editor.plugins.LinkBubble.CHANGE_LINK_SPAN_ID_); - this.createLink(goog.editor.plugins.LinkBubble.CHANGE_LINK_ID_, - MSG_LINK_BUBBLE_CHANGE, this.showLinkDialog_, changeLinkSpan); - - // This function is called multiple times - we have to reset the array. - this.actionSpans_ = []; - for (var i = 0; i < this.extraActions_.length; i++) { - var action = this.extraActions_[i]; - var actionSpan = this.createLinkOption(action.spanId_); - this.actionSpans_.push(actionSpan); - this.createLink(action.linkId_, action.message_, - function() { - action.actionFn_(this.getTargetUrl()); - }, - actionSpan); - } - - var removeLinkSpan = this.createLinkOption( - goog.editor.plugins.LinkBubble.DELETE_LINK_SPAN_ID_); - this.createLink(goog.editor.plugins.LinkBubble.DELETE_LINK_ID_, - MSG_LINK_BUBBLE_REMOVE, this.deleteLink_, removeLinkSpan); - - this.onShow(); - - var bubbleContents = this.dom_.createDom(goog.dom.TagName.DIV, - {id: goog.editor.plugins.LinkBubble.LINK_DIV_ID_}, - testMsgSpan || '', linkTextSpan, changeLinkSpan); - - for (i = 0; i < this.actionSpans_.length; i++) { - bubbleContents.appendChild(this.actionSpans_[i]); - } - bubbleContents.appendChild(removeLinkSpan); - - goog.dom.appendChild(bubbleContainer, bubbleContents); -}; - - -/** - * Tests the link by opening it in a new tab/window. Should be used as the - * click event handler for the test pseudo-link. - * @protected - */ -goog.editor.plugins.LinkBubble.prototype.testLink = function() { - goog.window.open(this.getTestLinkAction_(), - { - 'target': '_blank', - 'noreferrer': this.stopReferrerLeaks_ - }, this.getFieldObject().getAppWindow()); -}; - - -/** - * Returns whether the URL should be considered invalid. This always returns - * false in the base class, and should be overridden by subclasses that wish - * to impose validity rules on URLs. - * @param {string} url The url to check. - * @return {boolean} Whether the URL should be considered invalid. - */ -goog.editor.plugins.LinkBubble.prototype.isInvalidUrl = goog.functions.FALSE; - - -/** - * Gets the text to display for a link, based on the type of link - * @return {Object} Returns an object of the form: - * {linkText: displayTextForLinkTarget, valid: ifTheLinkIsValid}. - * @private - */ -goog.editor.plugins.LinkBubble.prototype.getLinkToTextObj_ = function() { - var isError; - var targetUrl = this.getTargetUrl(); - - if (this.isInvalidUrl(targetUrl)) { - /** - * @desc Message shown in a link bubble when the link is not a valid url. - */ - var MSG_INVALID_URL_LINK_BUBBLE = goog.getMsg('invalid url'); - targetUrl = MSG_INVALID_URL_LINK_BUBBLE; - isError = true; - } else if (goog.editor.Link.isMailto(targetUrl)) { - targetUrl = targetUrl.substring(7); // 7 == "mailto:".length - } - - return {linkText: targetUrl, valid: !isError}; -}; - - -/** - * Shows the link dialog - * @private - */ -goog.editor.plugins.LinkBubble.prototype.showLinkDialog_ = function() { - this.getFieldObject().execCommand(goog.editor.Command.MODAL_LINK_EDITOR, - new goog.editor.Link( - /** @type {HTMLAnchorElement} */ (this.getTargetElement()), - false)); - this.closeBubble(); -}; - - -/** - * Deletes the link associated with the bubble - * @private - */ -goog.editor.plugins.LinkBubble.prototype.deleteLink_ = function() { - this.getFieldObject().dispatchBeforeChange(); - - var link = this.getTargetElement(); - var child = link.lastChild; - goog.dom.flattenElement(link); - goog.editor.range.placeCursorNextTo(child, false); - - this.closeBubble(); - - this.getFieldObject().dispatchChange(); -}; - - -/** - * Sets the proper state for the action links. - * @protected - * @override - */ -goog.editor.plugins.LinkBubble.prototype.onShow = function() { - var linkDiv = this.dom_.getElement( - goog.editor.plugins.LinkBubble.LINK_DIV_ID_); - if (linkDiv) { - var testLinkSpan = this.dom_.getElement( - goog.editor.plugins.LinkBubble.TEST_LINK_SPAN_ID_); - if (testLinkSpan) { - var url = this.getTargetUrl(); - goog.style.showElement(testLinkSpan, !goog.editor.Link.isMailto(url)); - } - - for (var i = 0; i < this.extraActions_.length; i++) { - var action = this.extraActions_[i]; - var actionSpan = this.dom_.getElement(action.spanId_); - if (actionSpan) { - goog.style.showElement(actionSpan, action.toShowFn_( - this.getTargetUrl())); - } - } - } -}; - - -/** - * Gets the url for the bubble test link. The test link is the link in the - * bubble the user can click on to make sure the link they entered is correct. - * @return {string} The url for the bubble link href. - * @private - */ -goog.editor.plugins.LinkBubble.prototype.getTestLinkAction_ = function() { - var targetUrl = this.getTargetUrl(); - return this.testLinkUrlFn_ ? this.testLinkUrlFn_(targetUrl) : targetUrl; -}; - - -/** - * Checks whether the plugin should open the given url in a new window. - * @param {string} url The url to check. - * @return {boolean} If the plugin should open the given url in a new window. - * @protected - */ -goog.editor.plugins.LinkBubble.prototype.shouldOpenUrl = function(url) { - return !this.blockOpeningUnsafeSchemes_ || this.isSafeSchemeToOpen_(url); -}; - - -/** - * Determines whether or not a url has a scheme which is safe to open. - * Schemes like javascript are unsafe due to the possibility of XSS. - * @param {string} url A url. - * @return {boolean} Whether the url has a safe scheme. - * @private - */ -goog.editor.plugins.LinkBubble.prototype.isSafeSchemeToOpen_ = - function(url) { - var scheme = goog.uri.utils.getScheme(url) || 'http'; - return goog.array.contains(this.safeToOpenSchemes_, scheme.toLowerCase()); -}; - - - -/** - * Constructor for extra actions that can be added to the link bubble. - * @param {string} spanId The ID for the span showing the action. - * @param {string} linkId The ID for the link showing the action. - * @param {string} message The text for the link showing the action. - * @param {function(string):boolean} toShowFn Test function to determine whether - * to show the action for the given URL. - * @param {function(string):void} actionFn Action function to run when the - * action is clicked. Takes the current target URL as a parameter. - * @constructor - */ -goog.editor.plugins.LinkBubble.Action = function(spanId, linkId, message, - toShowFn, actionFn) { - this.spanId_ = spanId; - this.linkId_ = linkId; - this.message_ = message; - this.toShowFn_ = toShowFn; - this.actionFn_ = actionFn; -}; |