| // 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 A dialog for editing/creating a link. |
| * |
| * @author robbyw@google.com (Robby Walker) |
| */ |
| |
| goog.provide('goog.ui.editor.LinkDialog'); |
| goog.provide('goog.ui.editor.LinkDialog.BeforeTestLinkEvent'); |
| goog.provide('goog.ui.editor.LinkDialog.EventType'); |
| goog.provide('goog.ui.editor.LinkDialog.OkEvent'); |
| |
| goog.require('goog.a11y.aria'); |
| goog.require('goog.a11y.aria.State'); |
| goog.require('goog.dom'); |
| goog.require('goog.dom.TagName'); |
| goog.require('goog.dom.safe'); |
| goog.require('goog.editor.BrowserFeature'); |
| goog.require('goog.editor.Link'); |
| goog.require('goog.editor.focus'); |
| goog.require('goog.editor.node'); |
| goog.require('goog.events.Event'); |
| goog.require('goog.events.EventHandler'); |
| goog.require('goog.events.InputHandler'); |
| goog.require('goog.html.SafeHtml'); |
| goog.require('goog.string'); |
| goog.require('goog.string.Unicode'); |
| goog.require('goog.style'); |
| goog.require('goog.ui.Button'); |
| goog.require('goog.ui.Component'); |
| goog.require('goog.ui.LinkButtonRenderer'); |
| goog.require('goog.ui.editor.AbstractDialog'); |
| goog.require('goog.ui.editor.TabPane'); |
| goog.require('goog.ui.editor.messages'); |
| goog.require('goog.userAgent'); |
| goog.require('goog.window'); |
| |
| |
| |
| /** |
| * A type of goog.ui.editor.AbstractDialog for editing/creating a link. |
| * @param {goog.dom.DomHelper} domHelper DomHelper to be used to create the |
| * dialog's dom structure. |
| * @param {goog.editor.Link} link The target link. |
| * @constructor |
| * @extends {goog.ui.editor.AbstractDialog} |
| * @final |
| */ |
| goog.ui.editor.LinkDialog = function(domHelper, link) { |
| goog.ui.editor.LinkDialog.base(this, 'constructor', domHelper); |
| |
| /** |
| * The link being modified by this dialog. |
| * @type {goog.editor.Link} |
| * @private |
| */ |
| this.targetLink_ = link; |
| |
| /** |
| * The event handler for this dialog. |
| * @type {goog.events.EventHandler<!goog.ui.editor.LinkDialog>} |
| * @private |
| */ |
| this.eventHandler_ = new goog.events.EventHandler(this); |
| this.registerDisposable(this.eventHandler_); |
| |
| /** |
| * Optional warning to show about email addresses. |
| * @type {goog.html.SafeHtml} |
| * @private |
| */ |
| this.emailWarning_ = null; |
| |
| /** |
| * Whether to show a checkbox where the user can choose to have the link open |
| * in a new window. |
| * @type {boolean} |
| * @private |
| */ |
| this.showOpenLinkInNewWindow_ = false; |
| |
| /** |
| * Whether the "open link in new window" checkbox should be checked when the |
| * dialog is shown, and also whether it was checked last time the dialog was |
| * closed. |
| * @type {boolean} |
| * @private |
| */ |
| this.isOpenLinkInNewWindowChecked_ = false; |
| |
| /** |
| * Whether to show a checkbox where the user can choose to have 'rel=nofollow' |
| * attribute added to the link. |
| * @type {boolean} |
| * @private |
| */ |
| this.showRelNoFollow_ = false; |
| |
| /** |
| * InputHandler object to listen for changes in the url input field. |
| * @type {goog.events.InputHandler} |
| * @private |
| */ |
| this.urlInputHandler_ = null; |
| |
| /** |
| * InputHandler object to listen for changes in the email input field. |
| * @type {goog.events.InputHandler} |
| * @private |
| */ |
| this.emailInputHandler_ = null; |
| |
| /** |
| * InputHandler object to listen for changes in the text to display input |
| * field. |
| * @type {goog.events.InputHandler} |
| * @private |
| */ |
| this.textInputHandler_ = null; |
| |
| /** |
| * The tab bar where the url and email tabs are. |
| * @type {goog.ui.editor.TabPane} |
| * @private |
| */ |
| this.tabPane_ = null; |
| |
| /** |
| * The div element holding the link's display text input. |
| * @type {HTMLDivElement} |
| * @private |
| */ |
| this.textToDisplayDiv_ = null; |
| |
| /** |
| * The input element holding the link's display text. |
| * @type {HTMLInputElement} |
| * @private |
| */ |
| this.textToDisplayInput_ = null; |
| |
| /** |
| * Whether or not the feature of automatically generating the display text is |
| * enabled. |
| * @type {boolean} |
| * @private |
| */ |
| this.autogenFeatureEnabled_ = true; |
| |
| /** |
| * Whether or not we should automatically generate the display text. |
| * @type {boolean} |
| * @private |
| */ |
| this.autogenerateTextToDisplay_ = false; |
| |
| /** |
| * Whether or not automatic generation of the display text is disabled. |
| * @type {boolean} |
| * @private |
| */ |
| this.disableAutogen_ = false; |
| |
| /** |
| * The input element (checkbox) to indicate that the link should open in a new |
| * window. |
| * @type {HTMLInputElement} |
| * @private |
| */ |
| this.openInNewWindowCheckbox_ = null; |
| |
| /** |
| * The input element (checkbox) to indicate that the link should have |
| * 'rel=nofollow' attribute. |
| * @type {HTMLInputElement} |
| * @private |
| */ |
| this.relNoFollowCheckbox_ = null; |
| |
| /** |
| * Whether to stop leaking the page's url via the referrer header when the |
| * "test this link" link is clicked. |
| * @type {boolean} |
| * @private |
| */ |
| this.stopReferrerLeaks_ = false; |
| }; |
| goog.inherits(goog.ui.editor.LinkDialog, goog.ui.editor.AbstractDialog); |
| |
| |
| /** |
| * Events specific to the link dialog. |
| * @enum {string} |
| */ |
| goog.ui.editor.LinkDialog.EventType = { |
| BEFORE_TEST_LINK: 'beforetestlink' |
| }; |
| |
| |
| |
| /** |
| * OK event object for the link dialog. |
| * @param {string} linkText Text the user chose to display for the link. |
| * @param {string} linkUrl Url the user chose for the link to point to. |
| * @param {boolean} openInNewWindow Whether the link should open in a new window |
| * when clicked. |
| * @param {boolean} noFollow Whether the link should have 'rel=nofollow' |
| * attribute. |
| * @constructor |
| * @extends {goog.events.Event} |
| * @final |
| */ |
| goog.ui.editor.LinkDialog.OkEvent = function( |
| linkText, linkUrl, openInNewWindow, noFollow) { |
| goog.ui.editor.LinkDialog.OkEvent.base(this, 'constructor', |
| goog.ui.editor.AbstractDialog.EventType.OK); |
| |
| /** |
| * The text of the link edited in the dialog. |
| * @type {string} |
| */ |
| this.linkText = linkText; |
| |
| /** |
| * The url of the link edited in the dialog. |
| * @type {string} |
| */ |
| this.linkUrl = linkUrl; |
| |
| /** |
| * Whether the link should open in a new window when clicked. |
| * @type {boolean} |
| */ |
| this.openInNewWindow = openInNewWindow; |
| |
| /** |
| * Whether the link should have 'rel=nofollow' attribute. |
| * @type {boolean} |
| */ |
| this.noFollow = noFollow; |
| }; |
| goog.inherits(goog.ui.editor.LinkDialog.OkEvent, goog.events.Event); |
| |
| |
| |
| /** |
| * Event fired before testing a link by opening it in another window. |
| * Calling preventDefault will stop the link from being opened. |
| * @param {string} url Url of the link being tested. |
| * @constructor |
| * @extends {goog.events.Event} |
| * @final |
| */ |
| goog.ui.editor.LinkDialog.BeforeTestLinkEvent = function(url) { |
| goog.ui.editor.LinkDialog.BeforeTestLinkEvent.base(this, 'constructor', |
| goog.ui.editor.LinkDialog.EventType.BEFORE_TEST_LINK); |
| |
| /** |
| * The url of the link being tested. |
| * @type {string} |
| */ |
| this.url = url; |
| }; |
| goog.inherits(goog.ui.editor.LinkDialog.BeforeTestLinkEvent, goog.events.Event); |
| |
| |
| /** |
| * Sets the warning message to show to users about including email addresses on |
| * public web pages. |
| * @param {!goog.html.SafeHtml} emailWarning Warning message to show users about |
| * including email addresses on the web. |
| */ |
| goog.ui.editor.LinkDialog.prototype.setEmailWarning = function( |
| emailWarning) { |
| this.emailWarning_ = emailWarning; |
| }; |
| |
| |
| /** |
| * Tells the dialog to show a checkbox where the user can choose to have the |
| * link open in a new window. |
| * @param {boolean} startChecked Whether to check the checkbox the first |
| * time the dialog is shown. Subesquent times the checkbox will remember its |
| * previous state. |
| */ |
| goog.ui.editor.LinkDialog.prototype.showOpenLinkInNewWindow = function( |
| startChecked) { |
| this.showOpenLinkInNewWindow_ = true; |
| this.isOpenLinkInNewWindowChecked_ = startChecked; |
| }; |
| |
| |
| /** |
| * Tells the dialog to show a checkbox where the user can choose to add |
| * 'rel=nofollow' attribute to the link. |
| */ |
| goog.ui.editor.LinkDialog.prototype.showRelNoFollow = function() { |
| this.showRelNoFollow_ = true; |
| }; |
| |
| |
| /** @override */ |
| goog.ui.editor.LinkDialog.prototype.show = function() { |
| goog.ui.editor.LinkDialog.base(this, 'show'); |
| |
| |
| this.selectAppropriateTab_(this.textToDisplayInput_.value, |
| this.getTargetUrl_()); |
| this.syncOkButton_(); |
| |
| if (this.showOpenLinkInNewWindow_) { |
| if (!this.targetLink_.isNew()) { |
| // If link is not new, checkbox should reflect current target. |
| this.isOpenLinkInNewWindowChecked_ = |
| this.targetLink_.getAnchor().target == '_blank'; |
| } |
| this.openInNewWindowCheckbox_.checked = this.isOpenLinkInNewWindowChecked_; |
| } |
| |
| if (this.showRelNoFollow_) { |
| this.relNoFollowCheckbox_.checked = |
| goog.ui.editor.LinkDialog.hasNoFollow(this.targetLink_.getAnchor().rel); |
| } |
| }; |
| |
| |
| /** @override */ |
| goog.ui.editor.LinkDialog.prototype.hide = function() { |
| this.disableAutogenFlag_(false); |
| goog.ui.editor.LinkDialog.base(this, 'hide'); |
| }; |
| |
| |
| /** |
| * Tells the dialog whether to show the 'text to display' div. |
| * When the target element of the dialog is an image, there is no link text |
| * to modify. This function can be used for this kind of situations. |
| * @param {boolean} visible Whether to make 'text to display' div visible. |
| */ |
| goog.ui.editor.LinkDialog.prototype.setTextToDisplayVisible = function( |
| visible) { |
| if (this.textToDisplayDiv_) { |
| goog.style.setStyle(this.textToDisplayDiv_, 'display', |
| visible ? 'block' : 'none'); |
| } |
| }; |
| |
| |
| /** |
| * Tells the plugin whether to stop leaking the page's url via the referrer |
| * header when the "test this link" link is clicked. |
| * @param {boolean} stop Whether to stop leaking the referrer. |
| */ |
| goog.ui.editor.LinkDialog.prototype.setStopReferrerLeaks = function(stop) { |
| this.stopReferrerLeaks_ = stop; |
| }; |
| |
| |
| /** |
| * Tells the dialog whether the autogeneration of text to display is to be |
| * enabled. |
| * @param {boolean} enable Whether to enable the feature. |
| */ |
| goog.ui.editor.LinkDialog.prototype.setAutogenFeatureEnabled = function( |
| enable) { |
| this.autogenFeatureEnabled_ = enable; |
| }; |
| |
| |
| /** |
| * Checks if {@code str} contains {@code "nofollow"} as a separate word. |
| * @param {string} str String to be tested. This is usually {@code rel} |
| * attribute of an {@code HTMLAnchorElement} object. |
| * @return {boolean} {@code true} if {@code str} contains {@code nofollow}. |
| */ |
| goog.ui.editor.LinkDialog.hasNoFollow = function(str) { |
| return goog.ui.editor.LinkDialog.NO_FOLLOW_REGEX_.test(str); |
| }; |
| |
| |
| /** |
| * Removes {@code "nofollow"} from {@code rel} if it's present as a separate |
| * word. |
| * @param {string} rel Input string. This is usually {@code rel} attribute of |
| * an {@code HTMLAnchorElement} object. |
| * @return {string} {@code rel} with any {@code "nofollow"} removed. |
| */ |
| goog.ui.editor.LinkDialog.removeNoFollow = function(rel) { |
| return rel.replace(goog.ui.editor.LinkDialog.NO_FOLLOW_REGEX_, ''); |
| }; |
| |
| |
| // *** Protected interface ************************************************** // |
| |
| |
| /** @override */ |
| goog.ui.editor.LinkDialog.prototype.createDialogControl = function() { |
| var builder = new goog.ui.editor.AbstractDialog.Builder(this); |
| builder.setTitle(goog.ui.editor.messages.MSG_EDIT_LINK) |
| .setContent(this.createDialogContent_()); |
| return builder.build(); |
| }; |
| |
| |
| /** |
| * Creates and returns the event object to be used when dispatching the OK |
| * event to listeners based on which tab is currently selected and the contents |
| * of the input fields of that tab. |
| * @return {!goog.ui.editor.LinkDialog.OkEvent} The event object to be used when |
| * dispatching the OK event to listeners. |
| * @protected |
| * @override |
| */ |
| goog.ui.editor.LinkDialog.prototype.createOkEvent = function() { |
| if (this.tabPane_.getCurrentTabId() == |
| goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB) { |
| return this.createOkEventFromEmailTab_(); |
| } else { |
| return this.createOkEventFromWebTab_(); |
| } |
| }; |
| |
| |
| // *** Private implementation *********************************************** // |
| |
| |
| /** |
| * Regular expression that matches {@code nofollow} value in an |
| * {@code * HTMLAnchorElement}'s {@code rel} element. |
| * @type {RegExp} |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.NO_FOLLOW_REGEX_ = /\bnofollow\b/i; |
| |
| |
| /** |
| * Creates contents of this dialog. |
| * @return {!Element} Contents of the dialog as a DOM element. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.createDialogContent_ = function() { |
| this.textToDisplayDiv_ = /** @type {!HTMLDivElement} */( |
| this.buildTextToDisplayDiv_()); |
| var content = this.dom.createDom(goog.dom.TagName.DIV, null, |
| this.textToDisplayDiv_); |
| |
| this.tabPane_ = new goog.ui.editor.TabPane(this.dom, |
| goog.ui.editor.messages.MSG_LINK_TO); |
| this.registerDisposable(this.tabPane_); |
| this.tabPane_.addTab(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB, |
| goog.ui.editor.messages.MSG_ON_THE_WEB, |
| goog.ui.editor.messages.MSG_ON_THE_WEB_TIP, |
| goog.ui.editor.LinkDialog.BUTTON_GROUP_, |
| this.buildTabOnTheWeb_()); |
| this.tabPane_.addTab(goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB, |
| goog.ui.editor.messages.MSG_EMAIL_ADDRESS, |
| goog.ui.editor.messages.MSG_EMAIL_ADDRESS_TIP, |
| goog.ui.editor.LinkDialog.BUTTON_GROUP_, |
| this.buildTabEmailAddress_()); |
| this.tabPane_.render(content); |
| |
| this.eventHandler_.listen(this.tabPane_, goog.ui.Component.EventType.SELECT, |
| this.onChangeTab_); |
| |
| if (this.showOpenLinkInNewWindow_) { |
| content.appendChild(this.buildOpenInNewWindowDiv_()); |
| } |
| if (this.showRelNoFollow_) { |
| content.appendChild(this.buildRelNoFollowDiv_()); |
| } |
| |
| return content; |
| }; |
| |
| |
| /** |
| * Builds and returns the text to display section of the edit link dialog. |
| * @return {!Element} A div element to be appended into the dialog div. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.buildTextToDisplayDiv_ = function() { |
| var table = this.dom.createTable(1, 2); |
| table.cellSpacing = '0'; |
| table.cellPadding = '0'; |
| table.style.fontSize = '10pt'; |
| // Build the text to display input. |
| var textToDisplayDiv = this.dom.createDom(goog.dom.TagName.DIV); |
| var html = goog.html.SafeHtml.create('span', { |
| 'style': { |
| 'position': 'relative', |
| 'bottom': '2px', |
| 'padding-right': '1px', |
| 'white-space': 'nowrap' |
| }, |
| id: goog.ui.editor.LinkDialog.Id_.TEXT_TO_DISPLAY_LABEL |
| }, [goog.ui.editor.messages.MSG_TEXT_TO_DISPLAY, goog.string.Unicode.NBSP]); |
| goog.dom.safe.setInnerHtml(table.rows[0].cells[0], html); |
| this.textToDisplayInput_ = /** @type {!HTMLInputElement} */( |
| this.dom.createDom(goog.dom.TagName.INPUT, |
| {id: goog.ui.editor.LinkDialog.Id_.TEXT_TO_DISPLAY})); |
| var textInput = this.textToDisplayInput_; |
| // 98% prevents scroll bars in standards mode. |
| // TODO(robbyw): Is this necessary for quirks mode? |
| goog.style.setStyle(textInput, 'width', '98%'); |
| goog.style.setStyle(table.rows[0].cells[1], 'width', '100%'); |
| goog.dom.appendChild(table.rows[0].cells[1], textInput); |
| |
| goog.a11y.aria.setState(/** @type {!Element} */ (textInput), |
| goog.a11y.aria.State.LABELLEDBY, |
| goog.ui.editor.LinkDialog.Id_.TEXT_TO_DISPLAY_LABEL); |
| textInput.value = this.targetLink_.getCurrentText(); |
| |
| this.textInputHandler_ = new goog.events.InputHandler(textInput); |
| this.registerDisposable(this.textInputHandler_); |
| this.eventHandler_.listen(this.textInputHandler_, |
| goog.events.InputHandler.EventType.INPUT, this.onTextToDisplayEdit_); |
| |
| goog.dom.appendChild(textToDisplayDiv, table); |
| return textToDisplayDiv; |
| }; |
| |
| |
| /** |
| * Builds and returns the "checkbox to open the link in a new window" section of |
| * the edit link dialog. |
| * @return {!Element} A div element to be appended into the dialog div. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.buildOpenInNewWindowDiv_ = function() { |
| this.openInNewWindowCheckbox_ = /** @type {!HTMLInputElement} */( |
| this.dom.createDom(goog.dom.TagName.INPUT, {'type': 'checkbox'})); |
| return this.dom.createDom(goog.dom.TagName.DIV, null, |
| this.dom.createDom(goog.dom.TagName.LABEL, null, |
| this.openInNewWindowCheckbox_, |
| goog.ui.editor.messages.MSG_OPEN_IN_NEW_WINDOW)); |
| }; |
| |
| |
| /** |
| * Creates a DIV with a checkbox for {@code rel=nofollow} option. |
| * @return {!Element} Newly created DIV element. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.buildRelNoFollowDiv_ = function() { |
| /** @desc Checkbox text for adding 'rel=nofollow' attribute to a link. */ |
| var MSG_ADD_REL_NOFOLLOW_ATTR = goog.getMsg( |
| "Add '{$relNoFollow}' attribute ({$linkStart}Learn more{$linkEnd})", { |
| 'relNoFollow': 'rel=nofollow', |
| 'linkStart': '<a href="http://support.google.com/webmasters/bin/' + |
| 'answer.py?hl=en&answer=96569" target="_blank">', |
| 'linkEnd': '</a>' |
| }); |
| |
| this.relNoFollowCheckbox_ = /** @type {!HTMLInputElement} */( |
| this.dom.createDom(goog.dom.TagName.INPUT, {'type': 'checkbox'})); |
| return this.dom.createDom(goog.dom.TagName.DIV, null, |
| this.dom.createDom(goog.dom.TagName.LABEL, null, |
| this.relNoFollowCheckbox_, |
| goog.dom.htmlToDocumentFragment(MSG_ADD_REL_NOFOLLOW_ATTR))); |
| }; |
| |
| |
| /** |
| * Builds and returns the div containing the tab "On the web". |
| * @return {!Element} The div element containing the tab. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.buildTabOnTheWeb_ = function() { |
| var onTheWebDiv = this.dom.createElement(goog.dom.TagName.DIV); |
| |
| var headingDiv = this.dom.createDom(goog.dom.TagName.DIV, {}, |
| this.dom.createDom(goog.dom.TagName.B, {}, |
| goog.ui.editor.messages.MSG_WHAT_URL)); |
| var urlInput = this.dom.createDom(goog.dom.TagName.INPUT, |
| { |
| id: goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT, |
| className: goog.ui.editor.LinkDialog.TARGET_INPUT_CLASSNAME_ |
| }); |
| goog.a11y.aria.setState(urlInput, |
| goog.a11y.aria.State.LABELLEDBY, |
| goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB); |
| // IE throws on unknown values for type. |
| if (!goog.userAgent.IE) { |
| // On browsers that support Web Forms 2.0, allow autocompletion of URLs. |
| // (As of now, this is only supported by Opera 9) |
| urlInput.type = 'url'; |
| } |
| |
| if (goog.editor.BrowserFeature.NEEDS_99_WIDTH_IN_STANDARDS_MODE && |
| goog.editor.node.isStandardsMode(urlInput)) { |
| urlInput.style.width = '99%'; |
| } |
| |
| var inputDiv = this.dom.createDom(goog.dom.TagName.DIV, null, urlInput); |
| |
| this.urlInputHandler_ = new goog.events.InputHandler(urlInput); |
| this.registerDisposable(this.urlInputHandler_); |
| this.eventHandler_.listen(this.urlInputHandler_, |
| goog.events.InputHandler.EventType.INPUT, |
| this.onUrlOrEmailInputChange_); |
| |
| var testLink = new goog.ui.Button(goog.ui.editor.messages.MSG_TEST_THIS_LINK, |
| goog.ui.LinkButtonRenderer.getInstance(), |
| this.dom); |
| testLink.render(inputDiv); |
| testLink.getElement().style.marginTop = '1em'; |
| this.eventHandler_.listen(testLink, |
| goog.ui.Component.EventType.ACTION, |
| this.onWebTestLink_); |
| |
| // Build the "On the web" explanation text div. |
| var explanationDiv = this.dom.createDom(goog.dom.TagName.DIV, |
| goog.ui.editor.LinkDialog.EXPLANATION_TEXT_CLASSNAME_); |
| goog.dom.safe.setInnerHtml(explanationDiv, |
| goog.ui.editor.messages.getTrLinkExplanationSafeHtml()); |
| onTheWebDiv.appendChild(headingDiv); |
| onTheWebDiv.appendChild(inputDiv); |
| onTheWebDiv.appendChild(explanationDiv); |
| |
| return onTheWebDiv; |
| }; |
| |
| |
| /** |
| * Builds and returns the div containing the tab "Email address". |
| * @return {!Element} the div element containing the tab. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.buildTabEmailAddress_ = function() { |
| var emailTab = this.dom.createDom(goog.dom.TagName.DIV); |
| |
| var headingDiv = this.dom.createDom(goog.dom.TagName.DIV, {}, |
| this.dom.createDom(goog.dom.TagName.B, {}, |
| goog.ui.editor.messages.MSG_WHAT_EMAIL)); |
| goog.dom.appendChild(emailTab, headingDiv); |
| var emailInput = this.dom.createDom(goog.dom.TagName.INPUT, |
| { |
| id: goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_INPUT, |
| className: goog.ui.editor.LinkDialog.TARGET_INPUT_CLASSNAME_ |
| }); |
| goog.a11y.aria.setState(emailInput, |
| goog.a11y.aria.State.LABELLEDBY, |
| goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB); |
| |
| if (goog.editor.BrowserFeature.NEEDS_99_WIDTH_IN_STANDARDS_MODE && |
| goog.editor.node.isStandardsMode(emailInput)) { |
| // Standards mode sizes this too large. |
| emailInput.style.width = '99%'; |
| } |
| |
| goog.dom.appendChild(emailTab, emailInput); |
| |
| this.emailInputHandler_ = new goog.events.InputHandler(emailInput); |
| this.registerDisposable(this.emailInputHandler_); |
| this.eventHandler_.listen(this.emailInputHandler_, |
| goog.events.InputHandler.EventType.INPUT, |
| this.onUrlOrEmailInputChange_); |
| |
| goog.dom.appendChild(emailTab, |
| this.dom.createDom(goog.dom.TagName.DIV, |
| { |
| id: goog.ui.editor.LinkDialog.Id_.EMAIL_WARNING, |
| className: goog.ui.editor.LinkDialog.EMAIL_WARNING_CLASSNAME_, |
| style: 'visibility:hidden' |
| }, goog.ui.editor.messages.MSG_INVALID_EMAIL)); |
| |
| if (this.emailWarning_) { |
| var explanationDiv = this.dom.createDom(goog.dom.TagName.DIV, |
| goog.ui.editor.LinkDialog.EXPLANATION_TEXT_CLASSNAME_); |
| goog.dom.safe.setInnerHtml(explanationDiv, this.emailWarning_); |
| goog.dom.appendChild(emailTab, explanationDiv); |
| } |
| return emailTab; |
| }; |
| |
| |
| /** |
| * Returns the url that the target points to. |
| * @return {string} The url that the target points to. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.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.targetLink_.getAnchor().getAttribute('href') || ''; |
| }; |
| |
| |
| /** |
| * Selects the correct tab based on the URL, and fills in its inputs. |
| * For new links, it suggests a url based on the link text. |
| * @param {string} text The inner text of the link. |
| * @param {string} url The href for the link. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.selectAppropriateTab_ = function( |
| text, url) { |
| if (this.isNewLink_()) { |
| // Newly created non-empty link: try to infer URL from the link text. |
| this.guessUrlAndSelectTab_(text); |
| } else if (goog.editor.Link.isMailto(url)) { |
| // The link is for an email. |
| this.tabPane_.setSelectedTabId( |
| goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB); |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_INPUT) |
| .value = url.substring(url.indexOf(':') + 1); |
| this.setAutogenFlagFromCurInput_(); |
| } else { |
| // No specific tab was appropriate, default to on the web tab. |
| this.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB); |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT) |
| .value = this.isNewLink_() ? 'http://' : url; |
| this.setAutogenFlagFromCurInput_(); |
| } |
| }; |
| |
| |
| /** |
| * Select a url/tab based on the link's text. This function is simply |
| * the isNewLink_() == true case of selectAppropriateTab_(). |
| * @param {string} text The inner text of the link. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.guessUrlAndSelectTab_ = function(text) { |
| if (goog.editor.Link.isLikelyEmailAddress(text)) { |
| // The text is for an email address. |
| this.tabPane_.setSelectedTabId( |
| goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB); |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_INPUT) |
| .value = text; |
| this.setAutogenFlag_(true); |
| // TODO(user): Why disable right after enabling? What bug are we |
| // working around? |
| this.disableAutogenFlag_(true); |
| } else if (goog.editor.Link.isLikelyUrl(text)) { |
| // The text is for a web URL. |
| this.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB); |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT) |
| .value = text; |
| this.setAutogenFlag_(true); |
| this.disableAutogenFlag_(true); |
| } else { |
| // No meaning could be deduced from text, choose a default tab. |
| if (!this.targetLink_.getCurrentText()) { |
| this.setAutogenFlag_(true); |
| } |
| this.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB); |
| } |
| }; |
| |
| |
| /** |
| * Called on a change to the url or email input. If either one of those tabs |
| * is active, sets the OK button to enabled/disabled accordingly. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.syncOkButton_ = function() { |
| var inputValue; |
| if (this.tabPane_.getCurrentTabId() == |
| goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB) { |
| inputValue = this.dom.getElement( |
| goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_INPUT).value; |
| this.toggleInvalidEmailWarning_(inputValue != '' && |
| !goog.editor.Link.isLikelyEmailAddress(inputValue)); |
| } else if (this.tabPane_.getCurrentTabId() == |
| goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB) { |
| inputValue = this.dom.getElement( |
| goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT).value; |
| } else { |
| return; |
| } |
| this.getOkButtonElement().disabled = |
| goog.string.isEmptyOrWhitespace(inputValue); |
| }; |
| |
| |
| /** |
| * Show/hide the Invalid Email Address warning. |
| * @param {boolean} on Whether to show the warning. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.toggleInvalidEmailWarning_ = function(on) { |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.EMAIL_WARNING) |
| .style.visibility = (on ? 'visible' : 'hidden'); |
| }; |
| |
| |
| /** |
| * Changes the autogenerateTextToDisplay flag so that text to |
| * display stops autogenerating. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.onTextToDisplayEdit_ = function() { |
| var inputEmpty = this.textToDisplayInput_.value == ''; |
| if (inputEmpty) { |
| this.setAutogenFlag_(true); |
| } else { |
| this.setAutogenFlagFromCurInput_(); |
| } |
| }; |
| |
| |
| /** |
| * The function called when hitting OK with the "On the web" tab current. |
| * @return {!goog.ui.editor.LinkDialog.OkEvent} The event object to be used when |
| * dispatching the OK event to listeners. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.createOkEventFromWebTab_ = function() { |
| var input = /** @type {HTMLInputElement} */( |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT)); |
| var linkURL = input.value; |
| if (goog.editor.Link.isLikelyEmailAddress(linkURL)) { |
| // Make sure that if user types in an e-mail address, it becomes "mailto:". |
| return this.createOkEventFromEmailTab_( |
| goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT); |
| } else { |
| if (linkURL.search(/:/) < 0) { |
| linkURL = 'http://' + goog.string.trimLeft(linkURL); |
| } |
| return this.createOkEventFromUrl_(linkURL); |
| } |
| }; |
| |
| |
| /** |
| * The function called when hitting OK with the "email address" tab current. |
| * @param {string=} opt_inputId Id of an alternate input to check. |
| * @return {!goog.ui.editor.LinkDialog.OkEvent} The event object to be used when |
| * dispatching the OK event to listeners. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.createOkEventFromEmailTab_ = function( |
| opt_inputId) { |
| var linkURL = this.dom.getElement( |
| opt_inputId || goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_INPUT).value; |
| linkURL = 'mailto:' + linkURL; |
| return this.createOkEventFromUrl_(linkURL); |
| }; |
| |
| |
| /** |
| * Function to test a link from the on the web tab. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.onWebTestLink_ = function() { |
| var input = /** @type {HTMLInputElement} */( |
| this.dom.getElement(goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT)); |
| var url = input.value; |
| if (url.search(/:/) < 0) { |
| url = 'http://' + goog.string.trimLeft(url); |
| } |
| if (this.dispatchEvent( |
| new goog.ui.editor.LinkDialog.BeforeTestLinkEvent(url))) { |
| var win = this.dom.getWindow(); |
| var size = goog.dom.getViewportSize(win); |
| var openOptions = { |
| target: '_blank', |
| width: Math.max(size.width - 50, 50), |
| height: Math.max(size.height - 50, 50), |
| toolbar: true, |
| scrollbars: true, |
| location: true, |
| statusbar: false, |
| menubar: true, |
| 'resizable': true, |
| 'noreferrer': this.stopReferrerLeaks_ |
| }; |
| goog.window.open(url, openOptions, win); |
| } |
| }; |
| |
| |
| /** |
| * Called whenever the url or email input is edited. If the text to display |
| * matches the text to display, turn on auto. Otherwise if auto is on, update |
| * the text to display based on the url. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.onUrlOrEmailInputChange_ = function() { |
| if (this.autogenerateTextToDisplay_) { |
| this.setTextToDisplayFromAuto_(); |
| } else if (this.textToDisplayInput_.value == '') { |
| this.setAutogenFlagFromCurInput_(); |
| } |
| this.syncOkButton_(); |
| }; |
| |
| |
| /** |
| * Called when the currently selected tab changes. |
| * @param {goog.events.Event} e The tab change event. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.onChangeTab_ = function(e) { |
| var tab = /** @type {goog.ui.Tab} */ (e.target); |
| |
| // Focus on the input field in the selected tab. |
| var input = this.dom.getElement(tab.getId() + |
| goog.ui.editor.LinkDialog.Id_.TAB_INPUT_SUFFIX); |
| goog.editor.focus.focusInputField(input); |
| |
| // For some reason, IE does not fire onpropertychange events when the width |
| // is specified as a percentage, which breaks the InputHandlers. |
| input.style.width = ''; |
| input.style.width = input.offsetWidth + 'px'; |
| |
| this.syncOkButton_(); |
| this.setTextToDisplayFromAuto_(); |
| }; |
| |
| |
| /** |
| * If autogen is turned on, set the value of text to display based on the |
| * current selection or url. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.setTextToDisplayFromAuto_ = function() { |
| if (this.autogenFeatureEnabled_ && this.autogenerateTextToDisplay_) { |
| var inputId = this.tabPane_.getCurrentTabId() + |
| goog.ui.editor.LinkDialog.Id_.TAB_INPUT_SUFFIX; |
| this.textToDisplayInput_.value = |
| /** @type {HTMLInputElement} */(this.dom.getElement(inputId)).value; |
| } |
| }; |
| |
| |
| /** |
| * Turn on the autogenerate text to display flag, and set some sort of indicator |
| * that autogen is on. |
| * @param {boolean} val Boolean value to set autogenerate to. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.setAutogenFlag_ = function(val) { |
| // TODO(user): This whole autogen thing is very confusing. It needs |
| // to be refactored and/or explained. |
| this.autogenerateTextToDisplay_ = val; |
| }; |
| |
| |
| /** |
| * Disables autogen so that onUrlOrEmailInputChange_ doesn't act in cases |
| * that are undesirable. |
| * @param {boolean} autogen Boolean value to set disableAutogen to. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.disableAutogenFlag_ = function(autogen) { |
| this.setAutogenFlag_(!autogen); |
| this.disableAutogen_ = autogen; |
| }; |
| |
| |
| /** |
| * Creates an OK event from the text to display input and the specified link. |
| * If text to display input is empty, then generate the auto value for it. |
| * @return {!goog.ui.editor.LinkDialog.OkEvent} The event object to be used when |
| * dispatching the OK event to listeners. |
| * @param {string} url Url the target element should point to. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.createOkEventFromUrl_ = function(url) { |
| // Fill in the text to display input in case it is empty. |
| this.setTextToDisplayFromAuto_(); |
| if (this.showOpenLinkInNewWindow_) { |
| // Save checkbox state for next time. |
| this.isOpenLinkInNewWindowChecked_ = this.openInNewWindowCheckbox_.checked; |
| } |
| return new goog.ui.editor.LinkDialog.OkEvent(this.textToDisplayInput_.value, |
| url, this.showOpenLinkInNewWindow_ && this.isOpenLinkInNewWindowChecked_, |
| this.showRelNoFollow_ && this.relNoFollowCheckbox_.checked); |
| }; |
| |
| |
| /** |
| * If an email or url is being edited, set autogenerate to on if the text to |
| * display matches the url. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.setAutogenFlagFromCurInput_ = function() { |
| var autogen = false; |
| if (!this.disableAutogen_) { |
| var tabInput = this.dom.getElement(this.tabPane_.getCurrentTabId() + |
| goog.ui.editor.LinkDialog.Id_.TAB_INPUT_SUFFIX); |
| autogen = (tabInput.value == this.textToDisplayInput_.value); |
| } |
| this.setAutogenFlag_(autogen); |
| }; |
| |
| |
| /** |
| * @return {boolean} Whether the link is new. |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.prototype.isNewLink_ = function() { |
| return this.targetLink_.isNew(); |
| }; |
| |
| |
| /** |
| * IDs for relevant DOM elements. |
| * @enum {string} |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.Id_ = { |
| TEXT_TO_DISPLAY: 'linkdialog-text', |
| TEXT_TO_DISPLAY_LABEL: 'linkdialog-text-label', |
| ON_WEB_TAB: 'linkdialog-onweb', |
| ON_WEB_INPUT: 'linkdialog-onweb-tab-input', |
| EMAIL_ADDRESS_TAB: 'linkdialog-email', |
| EMAIL_ADDRESS_INPUT: 'linkdialog-email-tab-input', |
| EMAIL_WARNING: 'linkdialog-email-warning', |
| TAB_INPUT_SUFFIX: '-tab-input' |
| }; |
| |
| |
| /** |
| * Base name for the radio buttons group. |
| * @type {string} |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.BUTTON_GROUP_ = 'linkdialog-buttons'; |
| |
| |
| /** |
| * Class name for the url and email input elements. |
| * @type {string} |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.TARGET_INPUT_CLASSNAME_ = |
| goog.getCssName('tr-link-dialog-target-input'); |
| |
| |
| /** |
| * Class name for the email address warning element. |
| * @type {string} |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.EMAIL_WARNING_CLASSNAME_ = |
| goog.getCssName('tr-link-dialog-email-warning'); |
| |
| |
| /** |
| * Class name for the explanation text elements. |
| * @type {string} |
| * @private |
| */ |
| goog.ui.editor.LinkDialog.EXPLANATION_TEXT_CLASSNAME_ = |
| goog.getCssName('tr-link-dialog-explanation-text'); |