/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ export var SelectionUtils = { /** * Trim the selection text to a reasonable size and sanitize it to make it * safe for search query input. * * @param aSelection * The selection text to trim. * @param aMaxLen * The maximum string length, defaults to a reasonable size if undefined. * @return The trimmed selection text. */ trimSelection(aSelection, aMaxLen) { // Selections of more than 150 characters aren't useful. const maxLen = Math.min(aMaxLen || 150, aSelection.length); if (aSelection.length > maxLen) { // only use the first maxLen important chars. see bug 221361 let pattern = new RegExp("^(?:\\s*.){0," + maxLen + "}"); pattern.test(aSelection); aSelection = RegExp.lastMatch; } aSelection = aSelection.trim().replace(/\s+/g, " "); if (aSelection.length > maxLen) { aSelection = aSelection.substr(0, maxLen); } return aSelection; }, /** * Retrieve the text selection details for the given window. * * @param aTopWindow * The top window of the element containing the selection. * @param aCharLen * The maximum string length for the selection text. * @return The selection details containing the full and trimmed selection text * and link details for link selections. */ getSelectionDetails(aTopWindow, aCharLen) { let focusedWindow = {}; let focusedElement = Services.focus.getFocusedElementForWindow( aTopWindow, true, focusedWindow ); focusedWindow = focusedWindow.value; let selection = focusedWindow.getSelection(); let selectionStr = selection.toString(); let fullText; let url; let linkText; let isDocumentLevelSelection = true; // try getting a selected text in text input. if (!selectionStr && focusedElement) { // Don't get the selection for password fields. See bug 565717. if ( ChromeUtils.getClassName(focusedElement) === "HTMLTextAreaElement" || (ChromeUtils.getClassName(focusedElement) === "HTMLInputElement" && focusedElement.mozIsTextField(true)) ) { selection = focusedElement.editor.selection; selectionStr = selection.toString(); isDocumentLevelSelection = false; } } let collapsed = selection.isCollapsed; if (selectionStr) { // Have some text, let's figure out if it looks like a URL that isn't // actually a link. linkText = selectionStr.trim(); if (/^(?:https?|ftp):/i.test(linkText)) { try { url = Services.io.newURI(linkText); } catch (ex) {} } else if (/^(?:[a-z\d-]+\.)+[a-z]+$/i.test(linkText)) { // Check if this could be a valid url, just missing the protocol. // Now let's see if this is an intentional link selection. Our guess is // based on whether the selection begins/ends with whitespace or is // preceded/followed by a non-word character. // selection.toString() trims trailing whitespace, so we look for // that explicitly in the first and last ranges. let beginRange = selection.getRangeAt(0); let delimitedAtStart = /^\s/.test(beginRange); if (!delimitedAtStart) { let container = beginRange.startContainer; let offset = beginRange.startOffset; if (container.nodeType == container.TEXT_NODE && offset > 0) { delimitedAtStart = /\W/.test(container.textContent[offset - 1]); } else { delimitedAtStart = true; } } let delimitedAtEnd = false; if (delimitedAtStart) { let endRange = selection.getRangeAt(selection.rangeCount - 1); delimitedAtEnd = /\s$/.test(endRange); if (!delimitedAtEnd) { let container = endRange.endContainer; let offset = endRange.endOffset; if ( container.nodeType == container.TEXT_NODE && offset < container.textContent.length ) { delimitedAtEnd = /\W/.test(container.textContent[offset]); } else { delimitedAtEnd = true; } } } if (delimitedAtStart && delimitedAtEnd) { try { url = Services.uriFixup.getFixupURIInfo(linkText).preferredURI; } catch (ex) {} } } } if (selectionStr) { // Pass up to 16K through unmolested. If an add-on needs more, they will // have to use a content script. fullText = selectionStr.substr(0, 16384); selectionStr = this.trimSelection(selectionStr, aCharLen); } if (url && !url.host) { url = null; } return { text: selectionStr, docSelectionIsCollapsed: collapsed, isDocumentLevelSelection, fullText, linkURL: url ? url.spec : null, linkText: url ? linkText : "", }; }, };