@@ -29,107 +29,161 @@ import { dom, qs$ } from './dom.js';
29
29
30
30
/******************************************************************************/
31
31
32
-
(async ( ) => {
33
-
const params = new URLSearchParams(document.location.search);
34
-
const url = params.get('url');
35
-
36
-
const a = qs$('.cm-search-widget .sourceURL');
37
-
dom.attr(a, 'href', url);
38
-
dom.attr(a, 'title', url);
32
+
const urlToTextMap = new Map();
33
+
const params = new URLSearchParams(document.location.search);
34
+
let fromURL = '';
35
+
36
+
const cmEditor = new CodeMirror(qs$('#content'), {
37
+
autofocus: true,
38
+
gutters: [ 'CodeMirror-linenumbers' ],
39
+
lineNumbers: true,
40
+
lineWrapping: true,
41
+
matchBrackets: true,
42
+
styleActiveLine: {
43
+
nonEmpty: true,
44
+
},
45
+
});
46
+
47
+
uBlockDashboard.patchCodeMirrorEditor(cmEditor);
48
+
if ( dom.cl.has(dom.html, 'dark') ) {
49
+
dom.cl.add('#content .cm-s-default', 'cm-s-night');
50
+
dom.cl.remove('#content .cm-s-default', 'cm-s-default');
51
+
}
52
+
53
+
// Convert resource URLs into clickable links to code viewer
54
+
cmEditor.addOverlay({
55
+
re: /\b(?:href|src)=["']([^"']+)["']/g,
56
+
match: null,
57
+
token: function(stream) {
58
+
if ( stream.sol() ) {
59
+
this.re.lastIndex = 0;
60
+
this.match = this.re.exec(stream.string);
61
+
}
62
+
if ( this.match === null ) {
63
+
stream.skipToEnd();
64
+
return null;
65
+
}
66
+
const end = this.re.lastIndex - 1;
67
+
const beg = end - this.match[1].length;
68
+
if ( stream.pos < beg ) {
69
+
stream.pos = beg;
70
+
return null;
71
+
}
72
+
if ( stream.pos < end ) {
73
+
stream.pos = end;
74
+
return 'href';
75
+
}
76
+
if ( stream.pos < this.re.lastIndex ) {
77
+
stream.pos = this.re.lastIndex;
78
+
this.match = this.re.exec(stream.string);
79
+
return null;
80
+
}
81
+
stream.skipToEnd();
82
+
return null;
83
+
},
84
+
});
39
85
40
-
const response = await fetch(url);
41
-
const text = await response.text();
86
+
/******************************************************************************/
42
87
88
+
async function fetchResource(url) {
89
+
if ( urlToTextMap.has(url) ) {
90
+
return urlToTextMap.get(url);
91
+
}
92
+
let response, text;
93
+
try {
94
+
response = await fetch(url);
95
+
text = await response.text();
96
+
} catch(reason) {
97
+
return;
98
+
}
43
99
let mime = response.headers.get('Content-Type') || '';
44
100
mime = mime.replace(/\s*;.*$/, '').trim();
45
-
let value = '';
46
101
switch ( mime ) {
47
102
case 'text/css':
48
-
value = beautifier.css(text, { indent_size: 2 });
103
+
text = beautifier.css(text, { indent_size: 2 });
49
104
break;
50
105
case 'text/html':
51
106
case 'application/xhtml+xml':
52
107
case 'application/xml':
53
108
case 'image/svg+xml':
54
-
value = beautifier.html(text, { indent_size: 2 });
109
+
text = beautifier.html(text, { indent_size: 2 });
55
110
break;
56
111
case 'text/javascript':
57
112
case 'application/javascript':
58
113
case 'application/x-javascript':
59
-
value = beautifier.js(text, { indent_size: 4 });
114
+
text = beautifier.js(text, { indent_size: 4 });
60
115
break;
61
116
case 'application/json':
62
-
value = beautifier.js(text, { indent_size: 2 });
117
+
text = beautifier.js(text, { indent_size: 2 });
63
118
break;
64
119
default:
65
-
value = text;
66
120
break;
67
121
}
122
+
urlToTextMap.set(url, { mime, text });
123
+
return { mime, text };
124
+
}
125
+
126
+
/******************************************************************************/
68
127
69
-
const cmEditor = new CodeMirror(qs$('#content'), {
70
-
autofocus: true,
71
-
gutters: [ 'CodeMirror-linenumbers' ],
72
-
lineNumbers: true,
73
-
lineWrapping: true,
74
-
matchBrackets: true,
75
-
mode: mime,
76
-
styleActiveLine: {
77
-
nonEmpty: true,
78
-
},
79
-
value,
80
-
});
81
-
82
-
uBlockDashboard.patchCodeMirrorEditor(cmEditor);
83
-
if ( dom.cl.has(dom.html, 'dark') ) {
84
-
dom.cl.add('#content .cm-s-default', 'cm-s-night');
85
-
dom.cl.remove('#content .cm-s-default', 'cm-s-default');
128
+
function updatePastURLs(url) {
129
+
const list = qs$('#pastURLs');
130
+
let current;
131
+
for ( let i = 0; i < list.children.length; i++ ) {
132
+
const span = list.children[i];
133
+
dom.cl.remove(span, 'selected');
134
+
if ( span.textContent !== url ) { continue; }
135
+
current = span;
86
136
}
137
+
if ( current === undefined ) {
138
+
current = document.createElement('span');
139
+
current.textContent = url;
140
+
list.prepend(current);
141
+
}
142
+
dom.cl.add(current, 'selected');
143
+
}
87
144
88
-
// Convert resource URLs into clickable links to code viewer
89
-
cmEditor.addOverlay({
90
-
re: /\b(?:href|src)=["']([^"']+)["']/g,
91
-
match: null,
92
-
token: function(stream) {
93
-
if ( stream.sol() ) {
94
-
this.re.lastIndex = 0;
95
-
this.match = this.re.exec(stream.string);
96
-
}
97
-
if ( this.match === null ) {
98
-
stream.skipToEnd();
99
-
return null;
100
-
}
101
-
const end = this.re.lastIndex - 1;
102
-
const beg = end - this.match[1].length;
103
-
if ( stream.pos < beg ) {
104
-
stream.pos = beg;
105
-
return null;
106
-
}
107
-
if ( stream.pos < end ) {
108
-
stream.pos = end;
109
-
return 'href';
110
-
}
111
-
if ( stream.pos < this.re.lastIndex ) {
112
-
stream.pos = this.re.lastIndex;
113
-
this.match = this.re.exec(stream.string);
114
-
return null;
115
-
}
116
-
stream.skipToEnd();
117
-
return null;
118
-
},
119
-
});
120
-
121
-
dom.on('#content', 'click', '.cm-href', ev => {
122
-
const href = ev.target.textContent;
123
-
try {
124
-
const toURL = new URL(href, url);
125
-
vAPI.messaging.send('codeViewer', {
126
-
what: 'gotoURL',
127
-
details: {
128
-
url: `code-viewer.html?url=${encodeURIComponent(toURL.href)}`,
129
-
select: true,
130
-
},
131
-
});
132
-
} catch(ex) {
133
-
}
134
-
});
135
-
})();
145
+
/******************************************************************************/
146
+
147
+
async function setURL(resourceURL) {
148
+
const input = qs$('#header input[type="url"]');
149
+
let to;
150
+
try {
151
+
to = new URL(resourceURL, fromURL || undefined);
152
+
} catch(ex) {
153
+
}
154
+
if ( to === undefined ) { return; }
155
+
if ( /^https?:\/\/./.test(to.href) === false ) { return; }
156
+
if ( to.href === fromURL ) { return; }
157
+
let r;
158
+
try {
159
+
r = await fetchResource(to.href);
160
+
} catch(reason) {
161
+
}
162
+
if ( r === undefined ) { return; }
163
+
fromURL = to.href;
164
+
dom.attr(input, 'value', to.href);
165
+
input.value = to;
166
+
const a = qs$('.cm-search-widget .sourceURL');
167
+
dom.attr(a, 'href', to);
168
+
dom.attr(a, 'title', to);
169
+
cmEditor.setOption('mode', r.mime || '');
170
+
cmEditor.setValue(r.text);
171
+
updatePastURLs(to.href);
172
+
cmEditor.focus();
173
+
}
174
+
175
+
/******************************************************************************/
176
+
177
+
setURL(params.get('url'));
178
+
179
+
dom.on('#header input[type="url"]', 'change', ev => {
180
+
setURL(ev.target.value);
181
+
});
182
+
183
+
dom.on('#pastURLs', 'mousedown', 'span', ev => {
184
+
setURL(ev.target.textContent);
185
+
});
186
+
187
+
dom.on('#content', 'click', '.cm-href', ev => {
188
+
setURL(ev.target.textContent);
189
+
});
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4