зеркало из https://github.com/mozilla/gecko-dev.git
Bug 566225 - Add framework to linkify phone numbers in pages, preffed off. r=wesj
This commit is contained in:
Родитель
6661e60ca5
Коммит
770cd6e9c0
|
@ -777,3 +777,6 @@ pref("gfx.canvas.azure.backends", "skia");
|
|||
pref("gfx.canvas.azure.accelerated", true);
|
||||
|
||||
pref("general.useragent.override.youtube.com", "Android; Tablet;#Android; Mobile;");
|
||||
|
||||
// When true, phone number linkification is enabled.
|
||||
pref("browser.ui.linkify.phone", false);
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/* 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/. */
|
||||
|
||||
const LINKIFY_TIMEOUT = 0;
|
||||
|
||||
function Linkifier() {
|
||||
this._linkifyTimer = null;
|
||||
this._phoneRegex = /(?:\s|^)[\+]?(\(?\d{1,8}\)?)?([- ]+\(?\d{1,8}\)?)+( ?(x|ext) ?\d{1,3})?(?:\s|$)/g;
|
||||
}
|
||||
|
||||
Linkifier.prototype = {
|
||||
_buildAnchor : function(aDoc, aNumberText) {
|
||||
let anchorNode = aDoc.createElement("a");
|
||||
let cleanedText = "";
|
||||
for (let i = 0; i < aNumberText.length; i++) {
|
||||
let c = aNumberText.charAt(i);
|
||||
if ((c >= '0' && c <= '9') || c == '+') //assuming there is only the leading '+'.
|
||||
cleanedText += c;
|
||||
}
|
||||
anchorNode.setAttribute("href", "tel:" + cleanedText);
|
||||
let nodeText = aDoc.createTextNode(aNumberText);
|
||||
anchorNode.appendChild(nodeText);
|
||||
return anchorNode;
|
||||
},
|
||||
|
||||
_linkifyNodeNumbers : function(aNodeToProcess, aDoc) {
|
||||
let parent = aNodeToProcess.parentNode;
|
||||
let nodeText = aNodeToProcess.nodeValue;
|
||||
|
||||
// Replacing the original text node with a sequence of
|
||||
// |text before number|anchor with number|text after number nodes.
|
||||
// Each step a couple of (optional) text node and anchor node are appended.
|
||||
let anchorNode = null;
|
||||
let m = null;
|
||||
let startIndex = 0;
|
||||
let prevNode = null;
|
||||
while (m = this._phoneRegex.exec(nodeText)) {
|
||||
anchorNode = this._buildAnchor(aDoc, nodeText.substr(m.index, m[0].length));
|
||||
|
||||
let textExistsBeforeNumber = (m.index > startIndex);
|
||||
let nodeToAdd = null;
|
||||
if (textExistsBeforeNumber)
|
||||
nodeToAdd = aDoc.createTextNode(nodeText.substr(startIndex, m.index - startIndex));
|
||||
else
|
||||
nodeToAdd = anchorNode;
|
||||
|
||||
if (!prevNode) // first time, need to replace the whole node with the first new one.
|
||||
parent.replaceChild(nodeToAdd, aNodeToProcess);
|
||||
else
|
||||
parent.insertBefore(nodeToAdd, prevNode.nextSibling); //inserts after.
|
||||
|
||||
if (textExistsBeforeNumber) // if we added the text node before the anchor, we still need to add the anchor node.
|
||||
parent.insertBefore(anchorNode, nodeToAdd.nextSibling);
|
||||
|
||||
// next nodes need to be appended to this node.
|
||||
prevNode = anchorNode;
|
||||
startIndex = m.index + m[0].length;
|
||||
}
|
||||
|
||||
// if some text is remaining after the last anchor.
|
||||
if (startIndex > 0 && startIndex < nodeText.length) {
|
||||
let lastNode = aDoc.createTextNode(nodeText.substr(startIndex));
|
||||
parent.insertBefore(lastNode, prevNode.nextSibling);
|
||||
return lastNode;
|
||||
}
|
||||
return anchorNode;
|
||||
},
|
||||
|
||||
linkifyNumbers: function(aDoc) {
|
||||
// Removing any installed timer in case the page has changed and a previous timer is still running.
|
||||
if (this._linkifyTimer) {
|
||||
clearTimeout(this._linkifyTimer);
|
||||
this._linkifyTimer = null;
|
||||
}
|
||||
|
||||
let filterNode = function (node) {
|
||||
if (node.parentNode.tagName != 'A' &&
|
||||
node.parentNode.tagName != 'SCRIPT' &&
|
||||
node.parentNode.tagName != 'NOSCRIPT' &&
|
||||
node.parentNode.tagName != 'STYLE' &&
|
||||
node.parentNode.tagName != 'APPLET' &&
|
||||
node.parentNode.tagName != 'TEXTAREA')
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
else
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
|
||||
let nodeWalker = aDoc.createTreeWalker(aDoc.body, NodeFilter.SHOW_TEXT, filterNode, false);
|
||||
let parseNode = function() {
|
||||
let node = nodeWalker.nextNode();
|
||||
if (!node) {
|
||||
this._linkifyTimer = null;
|
||||
return;
|
||||
}
|
||||
let lastAddedNode = this._linkifyNodeNumbers(node, aDoc);
|
||||
// we assign a different timeout whether the node was processed or not.
|
||||
if (lastAddedNode) {
|
||||
nodeWalker.currentNode = lastAddedNode;
|
||||
this._linkifyTimer = setTimeout(parseNode, LINKIFY_TIMEOUT);
|
||||
} else {
|
||||
this._linkifyTimer = setTimeout(parseNode, LINKIFY_TIMEOUT);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this._linkifyTimer = setTimeout(parseNode, LINKIFY_TIMEOUT);
|
||||
}
|
||||
};
|
|
@ -69,6 +69,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
|||
["MasterPassword", "chrome://browser/content/MasterPassword.js"],
|
||||
["PluginHelper", "chrome://browser/content/PluginHelper.js"],
|
||||
["OfflineApps", "chrome://browser/content/OfflineApps.js"],
|
||||
["Linkifier", "chrome://browser/content/Linkify.js"],
|
||||
].forEach(function (aScript) {
|
||||
let [name, script] = aScript;
|
||||
XPCOMUtils.defineLazyGetter(window, name, function() {
|
||||
|
@ -3540,6 +3541,12 @@ Tab.prototype = {
|
|||
tabID: this.id
|
||||
});
|
||||
|
||||
if (!aEvent.persisted && Services.prefs.getBoolPref("browser.ui.linkify.phone")) {
|
||||
if (!this._linkifier)
|
||||
this._linkifier = new Linkifier();
|
||||
this._linkifier.linkifyNumbers(this.browser.contentWindow.document);
|
||||
}
|
||||
|
||||
if (!Reader.isEnabledForParseOnLoad)
|
||||
return;
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ chrome.jar:
|
|||
content/PermissionsHelper.js (content/PermissionsHelper.js)
|
||||
content/FeedHandler.js (content/FeedHandler.js)
|
||||
content/Feedback.js (content/Feedback.js)
|
||||
content/Linkify.js (content/Linkify.js)
|
||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||
content/aboutHealthReport.xhtml (content/aboutHealthReport.xhtml)
|
||||
* content/aboutHealthReport.js (content/aboutHealthReport.js)
|
||||
|
|
Загрузка…
Ссылка в новой задаче