forked from vimpr/vimperator-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
appendAnchor.js
115 lines (101 loc) · 3.9 KB
/
appendAnchor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
let PLUGIN_INFO = xml`
<VimperatorPlugin>
<name>appendAnchor</name>
<description>append anchors to texts look like url.</description>
<description lang="ja">リンク中の URL っぽいテキストにアンカーをつける。</description>
<version>0.4.7</version>
<author>SAKAI, Kazuaki</author>
<minVersion>2.0pre</minVersion>
<maxVersion>2.4</maxVersion>
<detail><![CDATA[
== Commands ==
:anc:
Append anchors.
== GlobalVariables ==
g:auto_append_anchor:
Execute ":anc" automatically when Vimperator shows the hints.
g:auto_append_anchor_once:
Just first once.
]]></detail>
<detail lang="ja"><![CDATA[
== Commands ==
:anc:
アンカーを付加する。
== GlobalVariables ==
g:auto_append_anchor:
Vimperator がヒントを表示するときに自動的に ":anc" する。
g:auto_append_anchor_once:
最初の一回だけ。
]]></detail>
</VimperatorPlugin>`;
(function(){
// settings ---
// "ACEILMPRSTXY" is result of below code.
// Array.prototype.uniq = function() this.reduceRight( function (a, b) (a[0] === b || a.unshift(b), a), []);
// [ 'TITLE', 'STYLE', 'SCRIPT', 'TEXTAREA', 'XMP', 'A', ].join('').split('').sort().uniq().join('');
const xpathQueryPlainText = '/descendant::*[not(contains(" TITLE STYLE SCRIPT TEXTAREA XMP A ", concat(" ", translate(local-name(), "aceilmprstxy", "ACEILMPRSTXY"), " ")))]/child::text()';
const regexpLikeURL = new RegExp("(h?ttps?|ftp):/+([a-zA-Z0-9][-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+[-_~*(a-zA-Z0-9;/?@&=+$%#])");
// process global variable
if (stringToBoolean(liberator.globalVariables.auto_append_anchor, false)) {
let originalHintsShow = liberator.modules.hints.show;
let once = stringToBoolean(liberator.globalVariables.auto_append_anchor_once, true);
hints.show = function () {
if (!(once && content.document.anchor_appended)) {
content.document.anchor_appended = true;
liberator.execute('anc');
}
originalHintsShow.apply(this, arguments);
};
}
// register command
liberator.modules.commands.addUserCommand(['anc'], 'append anchors to texts look like url',
function(arg) {
function append() {
let result = 0;
const doc = window.content.document;
const range = doc.createRange();
let nodes = util.evaluateXPath(xpathQueryPlainText);
for (let node in nodes) {
while (node) {
range.selectNode(node)
// search string like URL
let start = range.toString().search(regexpLikeURL);
// go to next node when there is nothing look like URL in current node
if (!(start > -1)) break;
result++;
// build URL
let scheme = RegExp.$1, host = RegExp.$2, lastMatch = RegExp.lastMatch;
if (/^ttps?$/.test(scheme)) scheme = 'h' + scheme;
let href = scheme + '://' + host;
// reset range
range.setStart(node, start);
range.setEnd(node, start + lastMatch.length);
// build anchor element
let anchor = doc.createElement('a');
anchor.setAttribute('href', href);
range.surroundContents(anchor);
// insert
range.insertNode(anchor);
// iterate
node = node.nextSibling.nextSibling.nextSibling;
}
}
range.detach();
return result;
}
for (let i = 0; i < 20 && append(); i++)
;
},
{},
true
);
// stuff function
function stringToBoolean(str, defaultValue) {
if (typeof str === 'number')
str = str.toString();
return !str ? (defaultValue ? true : false)
: str.toLowerCase() === 'false' ? false
: /^\d+$/.test(str) ? (parseInt(str) ? true : false)
: true;
}
})();