-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent_script.js
304 lines (253 loc) · 10.5 KB
/
content_script.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
var last;
/**
* Simple Javascript DOM Selector
* Get full CSS path of any element
*
* Returns a jQuery-style CSS path, with IDs, classes and ':nth-child' pseudo-selectors.
*
* Can either build a full CSS path, from 'html' all the way to ':nth-child()', or a
* more optimised short path, stopping at the first parent with a specific ID,
* eg. "#content .top p" instead of "html body #main #content .top p:nth-child(3)"
*/
function cssPath(el) {
var fullPath = 0, // Set to 1 to build ultra-specific full CSS-path, or 0 for optimised selector
useNthChild = 0, // Set to 1 to use ":nth-child()" pseudo-selectors to match the given element
cssPathStr = '',
testPath = '',
parents = [],
parentSelectors = [],
tagName,
cssId,
cssClass,
tagSelector,
vagueMatch,
nth,
i,
c;
// Go up the list of parent nodes and build unique identifier for each:
while ( el ) {
vagueMatch = 0;
// Get the node's HTML tag name in lowercase:
tagName = el.nodeName.toLowerCase();
// Get node's ID attribute, adding a '#':
cssId = ( el.id ) ? ( '#' + el.id ) : false;
// Get node's CSS classes, replacing spaces with '.':
cssClass = ( el.className ) ? ( '.' + el.className.replace(/\s+/g,".") ) : '';
// Build a unique identifier for this parent node:
if ( cssId ) {
// Matched by ID:
tagSelector = tagName + cssId + cssClass;
} else if ( cssClass ) {
// Matched by class (will be checked for multiples afterwards):
tagSelector = tagName + cssClass;
} else {
// Couldn't match by ID or class, so use ":nth-child()" instead:
vagueMatch = 1;
tagSelector = tagName;
}
// Add this full tag selector to the parentSelectors array:
parentSelectors.unshift( tagSelector )
// If doing short/optimised CSS paths and this element has an ID, stop here:
if ( cssId && !fullPath )
break;
// Go up to the next parent node:
el = el.parentNode !== document ? el.parentNode : false;
} // endwhile
// Build the CSS path string from the parent tag selectors:
for ( i = 0; i < parentSelectors.length; i++ ) {
cssPathStr += ' ' + parentSelectors[i];// + ' ' + cssPathStr;
// If using ":nth-child()" selectors and this selector has no ID / isn't the html or body tag:
if ( useNthChild && !parentSelectors[i].match(/#/) && !parentSelectors[i].match(/^(html|body)$/) ) {
// If there's no CSS class, or if the semi-complete CSS selector path matches multiple elements:
if ( !parentSelectors[i].match(/\./) || $( cssPathStr ).length > 1 ) {
// Count element's previous siblings for ":nth-child" pseudo-selector:
for ( nth = 1, c = el; c.previousElementSibling; c = c.previousElementSibling, nth++ );
// Append ":nth-child()" to CSS path:
cssPathStr += ":nth-child(" + nth + ")";
}
}
}
// Return trimmed full CSS path:
return cssPathStr.replace(/^[ \t]+|[ \t]+$/, '');
}
/**
* MouseOver action for all elements on the page:
*/
function inspectorMouseOver(e) {
// NB: this doesn't work in IE (needs fix):
var element = e.target;
// Set outline:
element.style.outline = '2px solid #f00';
// Set last selected element so it can be 'deselected' on cancel.
last = element;
}
/**
* MouseOut event action for all elements
*/
function inspectorMouseOut(e) {
// Remove outline from element:
e.target.style.outline = '';
}
function getParsedURL(){
var url = window.location.href;
if (url.charAt(url.length - 1) == "/"){
url = url.substring(0, url.length - 1);
}
url = url.substring(0, url.lastIndexOf("/") + 1);
return url;
}
/**
* Click action for hovered element
*/
function inspectorOnClick(e) {
e.preventDefault();
inspectorCancel();
fetch(chrome.extension.getURL("popup.html"))
.then(response => response.text())
.then(data => {
document.body.innerHTML += data;
fetch(chrome.extension.getURL("popup.css"))
.then(response => response.text())
.then(data => {
var styleElement = document.createElement("style");
styleElement.setAttribute("type", "text/css");
styleElement.setAttribute("id", "ww-extractor-style");
styleElement.innerHTML = data;
document.head.appendChild(styleElement);
// set url
var urlInputElement = document.getElementsByClassName("ww-extractor-site-selector-input")[0];
var url = getParsedURL();
urlInputElement.value = url + ".*";
// set css path of selected element
var cssSelectorInputElement = document.getElementsByClassName("ww-extractor-css-selector-input")[0];
cssSelectorInputElement.value = cssPath(e.target);
// set on cancel button click
var cancelButtonElement = document.getElementsByClassName("ww-extractor-cancel-button")[0];
cancelButtonElement.onclick = function(){
var aside = document.getElementById("ww-extractor-aside");
aside.parentNode.removeChild(aside);
var style = document.getElementById("ww-extractor-style");
style.parentNode.removeChild(style);
};
// set on extractor button click
var extractorButtonElement = document.getElementsByClassName("ww-extractor-extract-button")[0];
extractorButtonElement.onclick = function(){
var urlToStore = url;
var cssSelectorToStore = cssSelectorInputElement.value;
chrome.storage.sync.get([urlToStore], function(data){
console.log(data);
if (!(urlToStore in data)){
chrome.storage.sync.set({[urlToStore]: [cssSelectorToStore]}, function() {});
} else {
if (!data[[urlToStore]].includes(cssSelectorToStore)){
data[[urlToStore]].push(cssSelectorToStore);
chrome.storage.sync.set({[urlToStore]: data[[urlToStore]]});
}
}
generate_keywords();
});
var aside = document.getElementById("ww-extractor-aside");
aside.parentNode.removeChild(aside);
var style = document.getElementById("ww-extractor-style");
style.parentNode.removeChild(style);
};
});
});
return false;
}
/**
* Function to cancel inspector:
*/
function inspectorCancel(e) {
document.body.style.cursor = "default";
// Unbind inspector mouse and click events:
if (e === null && event.keyCode === 27) { // IE (won't work yet):
document.detachEvent("mouseover", inspectorMouseOver);
document.detachEvent("mouseout", inspectorMouseOut);
document.detachEvent("click", inspectorOnClick);
document.detachEvent("keydown", inspectorCancel);
last.style.outlineStyle = 'none';
} else if(e == null || e.which === 27) { // Better browsers:
document.removeEventListener("mouseover", inspectorMouseOver, true);
document.removeEventListener("mouseout", inspectorMouseOut, true);
document.removeEventListener("click", inspectorOnClick, true);
document.removeEventListener("keydown", inspectorCancel, true);
// Remove outline on last-selected element:
last.style.outline = 'none';
}
}
/**
* Add event listeners for DOM-inspectorey actions
*/
function runInspector(){
document.body.style.cursor = "crosshair";
if ( document.addEventListener ) {
document.addEventListener("mouseover", inspectorMouseOver, true);
document.addEventListener("mouseout", inspectorMouseOut, true);
document.addEventListener("click", inspectorOnClick, true);
document.addEventListener("keydown", inspectorCancel, true);
} else if ( document.attachEvent ) {
document.attachEvent("mouseover", inspectorMouseOver);
document.attachEvent("mouseout", inspectorMouseOut);
document.attachEvent("click", inspectorOnClick);
document.attachEvent("keydown", inspectorCancel);
}
}
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.runInspector){
module = request.Module;
runInspector();
}
});
function _extractKeywords(element, lines){
chrome.extension.sendMessage({extractKeywords: true, parseLines: lines}, function(response) {
var replaceWithInnerHTML = [];
var keywordLines = response.keywordLines;
for (var j = 0; j < keywordLines.length; j += 1){
var keywordTokens = keywordLines[j];
for (var k = 0; k < keywordTokens.length; k += 1){
var keywordToken = keywordTokens[k];
if (keywordToken.is_keyword){
replaceWithInnerHTML.push("<mark>" + keywordToken.word + "</mark>");
} else {
replaceWithInnerHTML.push(keywordToken.word);
}
if (k + 1 < keywordTokens.length) replaceWithInnerHTML.push(" ");
}
if (j + 1 < lines.length){
replaceWithInnerHTML.push("<br>");
}
}
element.innerHTML = replaceWithInnerHTML.join("");
});
}
function extractKeywords(cssSelectors){
for (var i = 0; i < cssSelectors.length; i += 1){
var cssSelector = cssSelectors[i];
var elements = document.querySelectorAll(cssSelector);
for (var l = 0; l < elements.length; l += 1){
var element = elements[l];
if (element != null){
var lines = element.innerHTML.split("<br>");
_extractKeywords(element, lines);
}
}
}
}
// check to see if we need to extract keywords from this site
function generate_keywords(){
chrome.storage.sync.get(null, function(data){
for (var url in data){
if (data.hasOwnProperty(url)){
try {
var reg = new RegExp(url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ".*");
if (reg.test(window.location.href)){
extractKeywords(data[url]);
}
} catch (e){}
}
}
});
}
//chrome.storage.sync.clear();
generate_keywords();