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
|
var REDIRECTS = []; // The global redirects list...
var options = {
isSyncEnabled : false
};
var template;
function normalize(r) {
return new Redirect(r).toObject(); //Cleans out any extra props, and adds default values for missing ones.
}
// Saves the entire list of redirects to storage.
function saveChanges() {
// Clean them up so angular $$hash things and stuff don't get serialized.
let arr = REDIRECTS.map(normalize);
chrome.runtime.sendMessage({type:"save-redirects", redirects:arr}, function(response) {
console.log(response.message);
if(response.message.indexOf("Redirects failed to save") > -1){
showMessage(response.message, false);
} else{
console.log('Saved ' + arr.length + ' redirects at ' + new Date() + '. Message from background page:' + response.message);
}
});
}
function toggleSyncSetting() {
chrome.runtime.sendMessage({type:"toggle-sync", isSyncEnabled: !options.isSyncEnabled}, function(response) {
if(response.message === "sync-enabled"){
options.isSyncEnabled = true;
showMessage('Sync is enabled!',true);
} else if(response.message === "sync-disabled"){
options.isSyncEnabled = false;
showMessage('Sync is disabled - local storage will be used!',true);
} else if(response.message.indexOf("Sync Not Possible")>-1){
options.isSyncEnabled = false;
chrome.storage.local.set({isSyncEnabled: $s.isSyncEnabled}, function(){
// console.log("set back to false");
});
showMessage(response.message, false);
}
else {
alert(response.message)
showMessage('Error occured when trying to change Sync settings. Look at the logs and raise an issue',false);
}
el('#storage-sync-option').checked = options.isSyncEnabled;
});
}
function renderRedirects() {
el('.redirect-rows').textContent = '';
for (let i=0; i < REDIRECTS.length; i++) {
let r = REDIRECTS[i];
let node = template.cloneNode(true);
node.removeAttribute('id');
renderSingleRedirect(node, r, i);
el('.redirect-rows').appendChild(node);
}
}
function renderSingleRedirect(node, redirect, index) {
//Add extra props to help with rendering...
if (index === 0) {
redirect.$first = true;
}
if (index === REDIRECTS.length - 1) {
redirect.$last = true;
}
redirect.$index = index;
dataBind(node, redirect);
node.setAttribute('data-index', index);
for (let btn of node.querySelectorAll('.btn')) {
btn.setAttribute('data-index', index);
}
//Remove extra props...
delete redirect.$first;
delete redirect.$last;
delete redirect.$index;
}
function updateBindings() {
let nodes = document.querySelectorAll('.redirect-row');
if (nodes.length !== REDIRECTS.length) {
throw new Error('Mismatch in lengths, Redirects are ' + REDIRECTS.length + ', nodes are ' + nodes.length)
}
for (let i=0; i < nodes.length; i++) {
let node = nodes[i];
let redirect = REDIRECTS[i];
renderSingleRedirect(node, redirect, i);
}
}
function duplicateRedirect(index) {
let redirect = new Redirect(REDIRECTS[index]);
REDIRECTS.splice(index, 0, redirect);
let newNode = template.cloneNode(true);
newNode.removeAttribute('id');
el('.redirect-rows').appendChild(newNode);
updateBindings();
saveChanges();
}
function toggleDisabled(index) {
let redirect = REDIRECTS[index];
redirect.disabled = !redirect.disabled
updateBindings();
saveChanges();
}
function moveUp(index) {
let prev = REDIRECTS[index-1];
REDIRECTS[index-1] = REDIRECTS[index];
REDIRECTS[index] = prev;
updateBindings();
saveChanges();
}
function moveDown(index) {
let next = REDIRECTS[index+1];
REDIRECTS[index+1] = REDIRECTS[index];
REDIRECTS[index] = next;
updateBindings();
saveChanges();
}
function moveUpTop(index) {
let top = REDIRECTS[0];
move(REDIRECTS, index, top);
updateBindings();
saveChanges();
}
function moveDownBottom(index) {
let bottom = REDIRECTS.length - 1;
move(REDIRECTS, index, bottom);
updateBindings();
saveChanges();
}
//All the setup stuff for the page
function pageLoad() {
template = el('#redirect-row-template');
template.parentNode.removeChild(template);
//Need to proxy this through the background page, because Firefox gives us dead objects
//nonsense when accessing chrome.storage directly.
chrome.runtime.sendMessage({type: "get-redirects"}, function(response) {
console.log('Received redirects message, count=' + response.redirects.length);
for (var i=0; i < response.redirects.length; i++) {
REDIRECTS.push(new Redirect(response.redirects[i]));
}
if (response.redirects.length === 0) {
//Add example redirect for first time users...
REDIRECTS.push(new Redirect(
{
"description": "Example redirect, try going to http://example.com/anywordhere",
"exampleUrl": "http://example.com/some-word-that-matches-wildcard",
"exampleResult": "https://google.com/search?q=some-word-that-matches-wildcard",
"error": null,
"includePattern": "http://example.com/*",
"excludePattern": "",
"patternDesc": "Any word after example.com leads to google search for that word.",
"redirectUrl": "https://google.com/search?q=$1",
"patternType": "W",
"processMatches": "noProcessing",
"disabled": false,
"appliesTo": [
"main_frame"
]
}
));
}
renderRedirects();
});
chrome.storage.local.get({isSyncEnabled:false}, function(obj){
options.isSyncEnabled = obj.isSyncEnabled;
el('#storage-sync-option').checked = options.isSyncEnabled;
});
if(navigator.userAgent.toLowerCase().indexOf("chrome") > -1){
show('#storage-sync-option');
}
//Setup event listeners
el('#hide-message').addEventListener('click', hideMessage);
el('#storage-sync-option input').addEventListener('click', toggleSyncSetting);
el('.redirect-rows').addEventListener('click', function(ev) {
let action = ev.target.getAttribute('data-action');
//We clone and re-use nodes all the time, so instead of attaching and removing event handlers endlessly we just put
//a data-action attribute on them with the name of the function that should be called...
if (!action) {
return;
}
let handler = window[action];
let index = parseInt(ev.target.getAttribute('data-index'));
handler(index);
});
}
function updateFavicon(e) {
let type = e.matches ? 'dark' : 'light'
el('link[rel="shortcut icon"]').href = `images/icon-${type}-theme-32.png`;
chrome.runtime.sendMessage({type: "update-icon"}); //Only works if this page is open, but still, better than nothing...
}
let mql = window.matchMedia('(prefers-color-scheme:dark)');
mql.onchange = updateFavicon;
updateFavicon(mql);
pageLoad();
|