-
Notifications
You must be signed in to change notification settings - Fork 8
/
options.js
241 lines (239 loc) · 7.85 KB
/
options.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
/*global chrome, FileReader, window, document, console*/
var DEFAULT_ICON = "images/default-64.png",
FILE_TYPES = ["image/jpeg", "image/png", "image/x-icon"],
FILE_SIZE_LIMIT = 102400,
ITEM_BYTES_LIMIT = chrome.storage.sync.QUOTA_BYTES_PER_ITEM,
ICON_MAX_KEYS = chrome.storage.sync.QUOTA_BYTES / ITEM_BYTES_LIMIT - 3;
/**
* Displays error on file field
* @param {string} errorString
*/
function setFileError(errorString) {
// Update status to let user know options were saved.
var status = document.getElementById('statusIcon');
status.textContent = errorString;
window.setTimeout(function() {
status.textContent = '';
}, 5000);
}
/**
* Read icon file and convert to base64.
* Limits: 100KB and/or 128x128px
* @param {Object} evt Event containing the file
*/
function handleFileSelect(evt) {
'use strict';
var files = evt.target.files,
file = files[0];
if (files && file) {
var preview = document.getElementById('iconImage');
preview.setAttribute('src', DEFAULT_ICON);
if (file.size > FILE_SIZE_LIMIT) {
setFileError('File size limit exceeded (max 100KB)');
evt.srcElement.value = '';
return;
} else if (FILE_TYPES.indexOf(file.type) === -1) {
setFileError('Invalid file type (JPEG or PNG)');
evt.srcElement.value = '';
return;
}
var reader = new FileReader();
reader.onload = function(readerEvt) {
var binaryString = readerEvt.target.result;
var base64String = 'data:image/png;base64,' + window.btoa(binaryString);
preview.setAttribute('src', base64String);
};
reader.readAsBinaryString(file);
}
}
/**
* Validate options
* @return {boolean} Returns true if success, false if fails
*/
function validateOptions() {
var customUrl = document.getElementById('customUrl').value,
domainRegex = document.getElementById('domain').value,
notificationValue = document.getElementById('notification').checked,
notificationTitle = document.getElementById('notificationTitle').value,
notificationText = document.getElementById('notificationText').value,
passedValidation = true;
//More than enough
if (customUrl.length > 1024) {
passedValidation = false;
}
if (domainRegex.length > 1024) {
passedValidation = false;
}
if (notificationValue === true && (notificationText.length > 256 || notificationTitle.length > 256)) {
passedValidation = false;
}
return passedValidation;
}
// Saves options to chrome.storage.sync
/**
* Saves options to chrome.storage.sync
*/
function saveOptions() {
'use strict';
var i = 0;
// Get values from inputs
var customUrl = document.getElementById('customUrl').value,
mode = -1,
domainRegex = document.getElementById('domain').value,
onlyHostname = document.getElementById('onlyHostname').checked,
iconSource = document.getElementById('iconImage').src,
notificationValue = document.getElementById('notification').checked,
notificationTitle = document.getElementById('notificationTitle').value,
notificationText = document.getElementById('notificationText').value,
modes = document.getElementsByName('mode');
//window mode
for (i = 0; i < modes.length; i++) {
if (modes[i].checked) {
mode = i;
break;
}
}
// Validate new data
if (validateOptions() !== true) {
return;
}
// Set the options object
var options = {};
//Generate the keys for the icon
options.customUrl = customUrl;
options.mode = mode;
options.domain = domainRegex;
options.onlyHostname = onlyHostname;
options.notification = {
'show': notificationValue,
'title': notificationTitle,
'text': notificationText
};
//Icon keys cleanup
for (i = 0; i < ICON_MAX_KEYS; i++) {
options['icon' + i] = '';
}
//Split icon base64 string, maximum QUOTA_BYTES_PER_ITEM = 4096 bytes
//maxLength = QUOTA_BYTES_PER_ITEM - 4 (key 'icon') - 4 quotes (on key and value)
var maxLength = ITEM_BYTES_LIMIT - 'iconxx'.length - 4,
//g = global match: finds all matches rather than stopping on the first one
regex = new RegExp('.{1,' + maxLength + '}', 'g'),
splitted = iconSource.match(regex),
iconKeys = [];
for (i = 0; i < ICON_MAX_KEYS && i < splitted.length; i++) {
if (splitted[i] !== undefined) {
options['icon' + i] = splitted[i];
}
}
chrome.storage.sync.set(options, function() {
// Update status to let user know options were saved.
var status = document.getElementById('status');
status.textContent = 'Options saved';
// Check for error
if (chrome.runtime.lastError !== undefined) {
console.error("An error ocurred saving options: " + chrome.runtime.lastError.string);
console.error(chrome.runtime.lastError);
status.textContent = 'An error ocurred saving options';
}
window.setTimeout(function() {
status.textContent = '';
}, 1800);
});
}
/**
* Restore user options on page load
*/
function restoreOptions() {
'use strict';
// Set defaults for localStorage get error
var options = {};
//Generate the keys for the icon
options.customUrl = 'https://duckduckgo.com/';
options.mode = 0;
options.domain = ".*";
options.onlyHostname = false;
options.notification = {
'show': false,
'title': 'Curtom Button',
'text': 'URL doesn\'t match'
};
// Icon cleanup
for (var i = 0; i < ICON_MAX_KEYS; i++) {
options['icon' + i] = '';
}
options.icon0 = DEFAULT_ICON;
// Get the items from localStorage
chrome.storage.sync.get(options, function(items) {
// Check for error
if (chrome.runtime.lastError !== undefined) {
console.error("An error ocurred restoring options: " + chrome.runtime.lastError);
return;
}
document.getElementById('customUrl').value = items.customUrl;
document.getElementById('domain').value = items.domain;
document.getElementById('onlyHostname').checked = items.onlyHostname;
document.getElementsByName('mode')[items.mode].checked = true;
var iconString = '';
//Get icon parts and join them
for (var i = 0; i < ICON_MAX_KEYS; i++) {
iconString += items['icon' + i];
}
document.getElementById('iconImage').src = iconString;
document.getElementById('notification').checked = items.notification.show;
document.getElementById('notificationTitle').value = items.notification.title;
document.getElementById('notificationText').value = items.notification.text;
if (items.notification.show === true) {
document.getElementById('notificationOptions').style.display = 'block';
}
});
}
/**
* Reset to default domain, match anything
*/
function resetDomain() {
'use strict';
document.getElementById('domain').value = ".*";
}
/**
* Reset to default icon
*/
function resetIcon() {
'use strict';
document.getElementById('iconImage').src = DEFAULT_ICON;
}
/**
* Reset notification options values
*/
function resetNotification() {
'use strict';
document.getElementById('notificationTitle').value = 'Custom Button';
document.getElementById('notificationText').value = 'URL doesn\'t match';
}
/**
* Show/hide notification options
*/
function toggleNotificationOptions() {
'use strict';
var options = document.getElementById('notificationOptions');
// First time we get display is empty
if (options.style.display === '' || options.style.display === 'none') {
options.style.display = 'block';
} else {
options.style.display = 'none';
}
}
/**
* Listeners
*/
document.addEventListener('DOMContentLoaded', restoreOptions);
document.getElementById('save').addEventListener('click', saveOptions);
document.getElementById('iconFilePicker').addEventListener('change', handleFileSelect, false);
document.getElementById('notification').addEventListener('change', toggleNotificationOptions);
document.getElementById('domainRestore').addEventListener('click', resetDomain);
document.getElementById('notificationRestore').addEventListener('click', resetNotification);
document.getElementById('iconRestore').addEventListener('click', resetIcon);
if (window.File && window.FileReader && window.FileList && window.Blob) {
document.getElementById('iconFilePicker').addEventListener('change', handleFileSelect, false);
} else {
console.log('The File APIs are not fully supported in this browser.');
}