Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: safari/ext/background.js

Issue 5768064935133184: Issue 2021 - Replaced FileSystem API with chrome.storage.local (Closed)
Left Patch Set: Created Feb. 26, 2015, 12:11 p.m.
Right Patch Set: Rebased Created April 10, 2015, 6:54 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « metadata.safari ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 (function() 18 (function()
19 { 19 {
20 /* Context menus */
21
22 var contextMenuItems = new ext.PageMap();
23
24 var ContextMenus = function(page)
25 {
26 this._page = page;
27 };
28 ContextMenus.prototype = {
29 create: function(item)
30 {
31 var items = contextMenuItems.get(this._page);
32 if (!items)
33 contextMenuItems.set(this._page, items = []);
34
35 items.push(item);
36 },
37 removeAll: function()
38 {
39 contextMenuItems.delete(this._page);
40 }
41 };
42
43 safari.application.addEventListener("contextmenu", function(event)
44 {
45 if (!event.userInfo)
46 return;
47
48 var pageId = event.userInfo.pageId;
49 if (!pageId)
50 return;
51
52 var page = pages[event.userInfo.pageId];
53 var items = contextMenuItems.get(page);
54 if (!items)
55 return;
56
57 var context = event.userInfo.tagName;
58 if (context == "img")
59 context = "image";
60
61 for (var i = 0; i < items.length; i++)
62 {
63 // Supported contexts are: all, audio, image, video
64 var menuItem = items[i];
65 if (menuItem.contexts.indexOf("all") == -1 && menuItem.contexts.indexOf(co ntext) == -1)
66 continue;
67
68 event.contextMenu.appendContextMenuItem(i, menuItem.title);
69 }
70 });
71
72 safari.application.addEventListener("command", function(event)
73 {
74 var page = pages[event.userInfo.pageId];
75 var items = contextMenuItems.get(page);
76
77 items[event.command].onclick(page);
78 });
79
80
81 /* Browser actions */
82
83 var toolbarItemProperties = {};
84
85 var getToolbarItemForWindow = function(win)
86 {
87 for (var i = 0; i < safari.extension.toolbarItems.length; i++)
88 {
89 var toolbarItem = safari.extension.toolbarItems[i];
90
91 if (toolbarItem.browserWindow == win)
92 return toolbarItem;
93 }
94
95 return null;
96 };
97
98 var updateToolbarItemForPage = function(page, win) {
99 var toolbarItem = getToolbarItemForWindow(win);
100 if (!toolbarItem)
101 return;
102
103 for (var name in toolbarItemProperties)
104 {
105 var property = toolbarItemProperties[name];
106
107 if (page && property.pages.has(page))
108 toolbarItem[name] = property.pages.get(page);
109 else
110 toolbarItem[name] = property.global;
111 }
112 };
113
114 var BrowserAction = function(page)
115 {
116 this._page = page;
117 };
118 BrowserAction.prototype = {
119 _set: function(name, value)
120 {
121 var toolbarItem = getToolbarItemForWindow(this._page._tab.browserWindow);
122 if (!toolbarItem)
123 return;
124
125 var property = toolbarItemProperties[name];
126 if (!property)
127 property = toolbarItemProperties[name] = {
128 pages: new ext.PageMap(),
129 global: toolbarItem[name]
130 };
131
132 property.pages.set(this._page, value);
133
134 if (isPageActive(this._page))
135 toolbarItem[name] = value;
136 },
137 setIcon: function(path)
138 {
139 this._set("image", safari.extension.baseURI + path.replace("$size", "16")) ;
140 },
141 setBadge: function(badge)
142 {
143 if (!badge)
144 this._set("badge", 0);
145 else if ("number" in badge)
146 this._set("badge", badge.number);
147 }
148 };
149
150 safari.application.addEventListener("activate", function(event)
151 {
152 // this event is also dispatched on windows that got focused. But we
153 // are only interested in tabs, which became active in their window.
154 if (!(event.target instanceof SafariBrowserTab))
155 return;
156
157 // update the toolbar item for the page visible in the tab that just
158 // became active. If we can't find that page (e.g. when a page was
159 // opened in a new tab, and our content script didn't run yet), the
160 // toolbar item of the window, is reset to its intial configuration.
161 updateToolbarItemForPage(event.target._visiblePage, event.target.browserWind ow);
162 }, true);
163
164
20 /* Pages */ 165 /* Pages */
21 166
22 var pages = Object.create(null); 167 var pages = Object.create(null);
23 var pageCounter = 0; 168 var pageCounter = 0;
24 169
170 var Frame = function(url, parent)
171 {
172 this._urlString = url;
173 this._urlObj = null;
174
175 this.parent = parent;
176 }
177 Frame.prototype = {
178 get url()
179 {
180 // On Safari 6 and before, the URL constuctor doesn't exist.
181 // The "urls" module provides a polifill, but it might not
182 // be loaded yet. So we have to lazily parse URLs.
183 if (!this._urlObj)
184 {
185 this._urlObj = new URL(this._urlString);
186 this._urlString = null;
187 }
188
189 return this._urlObj;
190 }
191 };
192
25 var Page = function(id, tab, url) 193 var Page = function(id, tab, url)
26 { 194 {
27 this._id = id; 195 this._id = id;
28 this._tab = tab; 196 this._tab = tab;
29 this._frames = [{url: new URL(url), parent: null}]; 197 this._frames = [new Frame(url, null)];
30 198
31 if (tab.page) 199 if (tab.page)
32 this._messageProxy = new ext._MessageProxy(tab.page); 200 this._messageProxy = new ext._MessageProxy(tab.page);
33 else 201 else
34 // while the new tab page is shown on Safari 7, the 'page' property 202 // while the new tab page is shown on Safari 7, the 'page' property
35 // of the tab is undefined, and we can't send messages to that page 203 // of the tab is undefined, and we can't send messages to that page
36 this._messageProxy = { 204 this._messageProxy = {
37 handleRequest: function() {}, 205 handleRequest: function() {},
38 handleResponse: function() {}, 206 handleResponse: function() {},
39 sendMessage: function() {} 207 sendMessage: function() {}
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 for (var id in tab._pages) 249 for (var id in tab._pages)
82 { 250 {
83 if (id != page._id) 251 if (id != page._id)
84 forgetPage(id); 252 forgetPage(id);
85 } 253 }
86 254
87 if (isPageActive(page)) 255 if (isPageActive(page))
88 updateToolbarItemForPage(page, tab.browserWindow); 256 updateToolbarItemForPage(page, tab.browserWindow);
89 }; 257 };
90 258
259 var addPage = function(tab, url, prerendered)
260 {
261 var pageId = ++pageCounter;
262
263 if (!('_pages' in tab))
264 tab._pages = Object.create(null);
265
266 var page = new Page(pageId, tab, url);
267 pages[pageId] = tab._pages[pageId] = page;
268
269 // When a new page is shown, forget the previous page associated
270 // with its tab, and reset the toolbar item if necessary.
271 // Note that it wouldn't be sufficient to do that when the old
272 // page is unloading, because Safari dispatches window.onunload
273 // only when reloading the page or following links, but not when
274 // you enter a new URL in the address bar.
275 if (!prerendered)
276 replacePage(page);
277
278 return pageId;
279 };
280
91 ext.pages = { 281 ext.pages = {
92 open: function(url, callback) 282 open: function(url, callback)
93 { 283 {
94 var tab = safari.application.activeBrowserWindow.openTab(); 284 var tab = safari.application.activeBrowserWindow.openTab();
95 tab.url = url; 285 tab.url = url;
96 286
97 if (callback) 287 if (callback)
98 { 288 {
99 var onLoading = function(page) 289 var onLoading = function(page)
100 { 290 {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 return; 328 return;
139 329
140 // when a tab is closed, forget the previous page associated with that 330 // when a tab is closed, forget the previous page associated with that
141 // tab. Note that it wouldn't be sufficient do that when the old page 331 // tab. Note that it wouldn't be sufficient do that when the old page
142 // is unloading, because Safari dispatches window.onunload only when 332 // is unloading, because Safari dispatches window.onunload only when
143 // reloading the page or following links, but not when closing the tab. 333 // reloading the page or following links, but not when closing the tab.
144 for (var id in event.target._pages) 334 for (var id in event.target._pages)
145 forgetPage(id); 335 forgetPage(id);
146 }, true); 336 }, true);
147 337
148 338 // We generally rely on content scripts to report new pages,
149 /* Browser actions */ 339 // since Safari's extension API doesn't consider pre-rendered
150 340 // pages. However, when the extension initializes we have to
151 var toolbarItemProperties = {}; 341 // use Safari's extension API to detect existing tabs.
152 342 safari.application.browserWindows.forEach(function(win)
153 var getToolbarItemForWindow = function(win) 343 {
154 { 344 for (var i = 0; i < win.tabs.length; i++)
155 for (var i = 0; i < safari.extension.toolbarItems.length; i++) 345 {
156 { 346 var tab = win.tabs[i];
157 var toolbarItem = safari.extension.toolbarItems[i]; 347 var url = tab.url;
158 348
159 if (toolbarItem.browserWindow == win) 349 // For the new tab page the url property is undefined.
160 return toolbarItem; 350 if (url)
161 } 351 addPage(tab, url, false);
162 352 }
163 return null;
164 };
165
166 var updateToolbarItemForPage = function(page, win) {
167 var toolbarItem = getToolbarItemForWindow(win);
168 if (!toolbarItem)
169 return;
170
171 for (var name in toolbarItemProperties)
172 {
173 var property = toolbarItemProperties[name];
174
175 if (page && property.pages.has(page))
176 toolbarItem[name] = property.pages.get(page);
177 else
178 toolbarItem[name] = property.global;
179 }
180 };
181
182 var BrowserAction = function(page)
183 {
184 this._page = page;
185 };
186 BrowserAction.prototype = {
187 _set: function(name, value)
188 {
189 var toolbarItem = getToolbarItemForWindow(this._page._tab.browserWindow);
190 if (!toolbarItem)
191 return;
192
193 var property = toolbarItemProperties[name];
194 if (!property)
195 property = toolbarItemProperties[name] = {
196 pages: new ext.PageMap(),
197 global: toolbarItem[name]
198 };
199
200 property.pages.set(this._page, value);
201
202 if (isPageActive(this._page))
203 toolbarItem[name] = value;
204 },
205 setIcon: function(path)
206 {
207 this._set("image", safari.extension.baseURI + path.replace("$size", "16")) ;
208 },
209 setBadge: function(badge)
210 {
211 if (!badge)
212 this._set("badge", 0);
213 else if ("number" in badge)
214 this._set("badge", badge.number);
215 }
216 };
217
218 safari.application.addEventListener("activate", function(event)
219 {
220 // this event is also dispatched on windows that got focused. But we
221 // are only interested in tabs, which became active in their window.
222 if (!(event.target instanceof SafariBrowserTab))
223 return;
224
225 // update the toolbar item for the page visible in the tab that just
226 // became active. If we can't find that page (e.g. when a page was
227 // opened in a new tab, and our content script didn't run yet), the
228 // toolbar item of the window, is reset to its intial configuration.
229 updateToolbarItemForPage(event.target._visiblePage, event.target.browserWind ow);
230 }, true);
231
232
233 /* Context menus */
234
235 var contextMenuItems = new ext.PageMap();
236
237 var ContextMenus = function(page)
238 {
239 this._page = page;
240 };
241 ContextMenus.prototype = {
242 create: function(item)
243 {
244 var items = contextMenuItems.get(this._page);
245 if (!items)
246 contextMenuItems.set(this._page, items = []);
247
248 items.push(item);
249 },
250 removeAll: function()
251 {
252 contextMenuItems.delete(this._page);
253 }
254 };
255
256 safari.application.addEventListener("contextmenu", function(event)
257 {
258 if (!event.userInfo)
259 return;
260
261 var pageId = event.userInfo.pageId;
262 if (!pageId)
263 return;
264
265 var page = pages[event.userInfo.pageId];
266 var items = contextMenuItems.get(page);
267 if (!items)
268 return;
269
270 var context = event.userInfo.tagName;
271 if (context == "img")
272 context = "image";
273
274 for (var i = 0; i < items.length; i++)
275 {
276 // Supported contexts are: all, audio, image, video
277 var menuItem = items[i];
278 if (menuItem.contexts.indexOf("all") == -1 && menuItem.contexts.indexOf(co ntext) == -1)
279 continue;
280
281 event.contextMenu.appendContextMenuItem(i, menuItem.title);
282 }
283 });
284
285 safari.application.addEventListener("command", function(event)
286 {
287 var page = pages[event.userInfo.pageId];
288 var items = contextMenuItems.get(page);
289
290 items[event.command].onclick(page);
291 }); 353 });
292 354
293 355
294 /* Web requests */ 356 /* Web requests */
295 357
296 ext.webRequest = { 358 ext.webRequest = {
297 onBeforeRequest: new ext._EventTarget(), 359 onBeforeRequest: new ext._EventTarget(),
298 handlerBehaviorChanged: function() {} 360 handlerBehaviorChanged: function() {},
299 }; 361 indistinguishableTypes: [["OTHER", "FONT"]]
300
301
302 /* Background page */
303
304 ext.backgroundPage = {
305 getWindow: function()
306 {
307 return window;
308 }
309 }; 362 };
310 363
311 364
312 /* Background page proxy (for access from content scripts) */ 365 /* Background page proxy (for access from content scripts) */
313 366
314 var backgroundPageProxy = { 367 var backgroundPageProxy = {
315 cache: new ext.PageMap(), 368 cache: new ext.PageMap(),
316 369
317 registerObject: function(obj, objects) 370 registerObject: function(obj, objects)
318 { 371 {
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 { 580 {
528 case "loading": 581 case "loading":
529 var tab = event.target; 582 var tab = event.target;
530 var message = event.message; 583 var message = event.message;
531 584
532 var pageId; 585 var pageId;
533 var frameId; 586 var frameId;
534 587
535 if (message.isTopLevel) 588 if (message.isTopLevel)
536 { 589 {
537 pageId = ++pageCounter; 590 pageId = addPage(tab, message.url, message.isPrerendered);
538 frameId = 0; 591 frameId = 0;
539 592
540 if (!('_pages' in tab)) 593 ext.pages.onLoading._dispatch(pages[pageId]);
541 tab._pages = Object.create(null);
542
543 var page = new Page(pageId, tab, message.url);
544 pages[pageId] = tab._pages[pageId] = page;
545
546 // when a new page is shown, forget the previous page associated
547 // with its tab, and reset the toolbar item if necessary.
548 // Note that it wouldn't be sufficient to do that when the old
549 // page is unloading, because Safari dispatches window.onunload
550 // only when reloading the page or following links, but not when
551 // you enter a new URL in the address bar.
552 if (!message.isPrerendered)
553 replacePage(page);
554
555 ext.pages.onLoading._dispatch(page);
556 } 594 }
557 else 595 else
558 { 596 {
559 var page; 597 var page;
560 var parentFrame; 598 var parentFrame;
561 599
562 var lastPageId; 600 var lastPageId;
563 var lastPage; 601 var lastPage;
564 var lastPageTopLevelFrame; 602 var lastPageTopLevelFrame;
565 603
(...skipping 28 matching lines...) Expand all
594 // if we can't find the parent frame and its page, fall back to 632 // if we can't find the parent frame and its page, fall back to
595 // the page most recently loaded in the tab and its top level fram e 633 // the page most recently loaded in the tab and its top level fram e
596 if (!page) 634 if (!page)
597 { 635 {
598 pageId = lastPageId; 636 pageId = lastPageId;
599 page = lastPage; 637 page = lastPage;
600 parentFrame = lastPageTopLevelFrame; 638 parentFrame = lastPageTopLevelFrame;
601 } 639 }
602 640
603 frameId = page._frames.length; 641 frameId = page._frames.length;
604 page._frames.push({url: new URL(message.url), parent: parentFrame} ); 642 page._frames.push(new Frame(message.url, parentFrame));
605 } 643 }
606
607 event.message = {pageId: pageId, frameId: frameId}; 644 event.message = {pageId: pageId, frameId: frameId};
608 break; 645 break;
609 case "webRequest": 646 case "webRequest":
610 var page = pages[event.message.pageId]; 647 var page = pages[event.message.pageId];
611 var frame = page._frames[event.message.frameId]; 648 var frame = page._frames[event.message.frameId];
612 649
613 var results = ext.webRequest.onBeforeRequest._dispatch( 650 var results = ext.webRequest.onBeforeRequest._dispatch(
614 new URL(event.message.url, frame.url), 651 new URL(event.message.url, frame.url),
615 event.message.type, page, frame 652 event.message.type, page, frame
616 ); 653 );
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
682 { 719 {
683 delete safari.extension.settings[key]; 720 delete safari.extension.settings[key];
684 721
685 if (callback) 722 if (callback)
686 setTimeout(callback, 0); 723 setTimeout(callback, 0);
687 }, 724 },
688 onChanged: new ext._EventTarget(), 725 onChanged: new ext._EventTarget(),
689 726
690 // Preferences were previously encoded as JSON for compatibility 727 // Preferences were previously encoded as JSON for compatibility
691 // with localStorage, which has been used on Chrome. 728 // with localStorage, which has been used on Chrome.
692 migratePrefs: function(prefs) 729 migratePrefs: function(hooks)
693 { 730 {
694 var settings = safari.extension.settings; 731 var settings = safari.extension.settings;
695 732
696 for (var key in settings) 733 for (var key in settings)
697 { 734 {
698 if (key in prefs) 735 var item = hooks.map(key, settings[key]);
736
737 if (item)
699 { 738 {
700 try
701 {
702 settings["pref:" + key] = JSON.parse(settings[key]);
703 }
704 catch (e)
705 {
706 }
707
708 delete settings[key]; 739 delete settings[key];
740 settings[item.key] = item.value;
709 } 741 }
710 } 742 }
743
744 hooks.done();
711 }, 745 },
712 746
713 // While moving away from the FileSystem API on Chrome the data structure 747 // While moving away from the FileSystem API on Chrome the data structure
714 // for files on Safari changed as well, in order to keep thing consistent. 748 // for files on Safari changed as well, in order to keep thing consistent.
715 migrateFiles: function(callback) 749 migrateFiles: function(callback)
716 { 750 {
717 var settings = safari.extension.settings; 751 var settings = safari.extension.settings;
718 752
719 for (var key in settings) 753 for (var key in settings)
720 { 754 {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
772 tab.activate(); 806 tab.activate();
773 if (callback) 807 if (callback)
774 callback(page); 808 callback(page);
775 return; 809 return;
776 } 810 }
777 } 811 }
778 812
779 ext.pages.open(optionsUrl, callback); 813 ext.pages.open(optionsUrl, callback);
780 }; 814 };
781 })(); 815 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld