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

Side by Side Diff: safari/ext/common.js

Issue 5464830253203456: Refactored the abstraction layer to address prerendered pages on Safari caused by leaky abstraction (Closed)
Patch Set: Created Feb. 22, 2014, 10:45 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2013 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 /* Events */ 19 {
20 /* Message passing */
20 21
21 WrappedEventTarget = function(target, eventName, capture) 22 var MessageProxy = ext._MessageProxy = function(messageDispatcher)
22 { 23 {
23 this._listeners = []; 24 this._messageDispatcher = messageDispatcher;
24 this._wrappedListeners = []; 25 this._responseCallbacks = {__proto__: null};
26 this._responseCallbackCounter = 0;
27 };
28 MessageProxy.prototype = {
29 _sendResponse: function(request, message)
30 {
31 var response = {};
32 for (var prop in request)
33 response[prop] = request[prop];
34 response.payload = message;
25 35
26 this._target = target; 36 this._messageDispatcher.dispatchMessage("response", response);
27 this._eventName = eventName; 37 },
28 this._capture = capture; 38 handleRequest: function(request, sender)
29 };
30 WrappedEventTarget.prototype = {
31 addListener: function(listener)
32 { 39 {
33 var wrappedListener = this._wrapListener(listener); 40 var sendResponse;
41 if ("callbackId" in request)
42 sendResponse = this._sendResponse.bind(this, request);
43 else
44 sendResponse = function() {};
34 45
35 this._listeners.push(listener); 46 ext.onMessage._dispatch(request.payload, sender, sendResponse);
36 this._wrappedListeners.push(wrappedListener); 47 },
48 handleResponse: function(response)
49 {
50 var callbackId = response.callbackId;
51 var callback = this._responseCallbacks[callbackId];
52 if (callback)
53 {
54 delete this._responseCallbacks[callbackId];
55 callback(response.payload);
56 }
57 },
58 sendMessage: function(message, responseCallback, extra)
59 {
60 var request = {payload: message};
37 61
38 this._target.addEventListener( 62 if (responseCallback)
39 this._eventName, 63 {
40 wrappedListener, 64 request.callbackId = ++this._responseCallbackCounter;
41 this._capture 65 this._responseCallbacks[request.callbackId] = responseCallback;
42 ); 66 }
43 },
44 removeListener: function(listener)
45 {
46 var idx = this._listeners.indexOf(listener);
47 67
48 if (idx != -1) 68 for (var prop in extra)
49 { 69 request[prop] = extra[prop];
50 this._target.removeEventListener(
51 this._eventName,
52 this._wrappedListeners[idx],
53 this._capture
54 );
55 70
56 this._listeners.splice(idx, 1); 71 this._messageDispatcher.dispatchMessage("request", request);
57 this._wrappedListeners.splice(idx, 1);
58 }
59 } 72 }
60 }; 73 };
61 74
62 MessageEventTarget = function(target) 75 ext.onMessage = new ext._EventTarget();
63 {
64 WrappedEventTarget.call(this, target, "message", false);
65 };
66 MessageEventTarget.prototype = {
67 __proto__: WrappedEventTarget.prototype,
68 _wrapListener: function(listener)
69 {
70 return function(event)
71 {
72 if (event.name == "request")
73 listener(event.message.payload, this._getSenderDetails(event), functio n(message)
74 {
75 this._getResponseDispatcher(event).dispatchMessage("response",
76 {
77 requestId: event.message.requestId,
78 payload: message
79 });
80 }.bind(this));
81 }.bind(this);
82 }
83 };
84
85
86 /* Message passing */
87
88 var requestCounter = 0;
89
90 _sendMessage = function(message, responseCallback, messageDispatcher, response EventTarget, extra)
91 {
92 var requestId = ++requestCounter;
93
94 if (responseCallback)
95 {
96 var responseListener = function(event)
97 {
98 if (event.name == "response" && event.message.requestId == requestId)
99 {
100 responseEventTarget.removeEventListener("message", responseListener, f alse);
101 responseCallback(event.message.payload);
102 }
103 };
104 responseEventTarget.addEventListener("message", responseListener, false);
105 }
106
107 var rawMessage = {requestId: requestId, payload: message};
108 for (var k in extra)
109 rawMessage[k] = extra[k];
110 messageDispatcher.dispatchMessage("request", rawMessage);
111 };
112 76
113 77
114 /* I18n */ 78 /* I18n */
115 79
116 var I18n = function() 80 var localeCandidates = null;
81 var uiLocale;
82
83 var getLocaleCandidates = function()
117 { 84 {
118 this._localeCandidates = this._getLocaleCandidates(); 85 var candidates = [];
119 this._uiLocale = this._localeCandidates[0]; 86 var defaultLocale = "en_US";
87
88 var bits, i;
89 for (i = (bits = navigator.language.split("-")).length; i > 0; i--)
90 {
91 var locale = bits.slice(0, i).join("_");
92 candidates.push(locale);
93
94 if (locale == defaultLocale)
95 return candidates;
96 }
97
98 candidates.push(defaultLocale);
99 return candidates;
120 }; 100 };
121 I18n.prototype = { 101
122 _getLocaleCandidates: function() 102 var getCatalog = function(locale)
103 {
104 var xhr = new XMLHttpRequest();
105
106 xhr.open("GET", safari.extension.baseURI + "_locales/" + locale + "/messages .json", false);
107
108 try {
109 xhr.send();
110 }
111 catch (e)
123 { 112 {
124 var candidates = []; 113 return null;
125 var defaultLocale = "en_US"; 114 }
126 115
127 var bits, i; 116 if (xhr.status != 200 && xhr.status != 0)
128 for (i = (bits = navigator.language.split("-")).length; i > 0; i--) 117 return null;
118
119 return JSON.parse(xhr.responseText);
120 };
121
122 ext.i18n = {
123 getMessage: function(msgId, substitutions)
124 {
125 if (!localeCandidates)
129 { 126 {
130 var locale = bits.slice(0, i).join("_"); 127 localeCandidates = getLocaleCandidates();
131 candidates.push(locale); 128 uiLocale = localeCandidates[0];
132
133 if (locale == defaultLocale)
134 return candidates;
135 } 129 }
136 130
137 candidates.push(defaultLocale); 131 if (msgId == "@@ui_locale")
138 return candidates; 132 return uiLocale;
139 },
140 _getCatalog: function(locale)
141 {
142 var xhr = new XMLHttpRequest();
143
144 xhr.open("GET", safari.extension.baseURI + "_locales/" + locale + "/messag es.json", false);
145 133
146 try { 134 for (var i = 0; i < localeCandidates.length; i++)
147 xhr.send();
148 }
149 catch (e)
150 { 135 {
151 return null; 136 var catalog = getCatalog(localeCandidates[i]);
152 }
153
154 if (xhr.status != 200 && xhr.status != 0)
155 return null;
156
157 return JSON.parse(xhr.responseText);
158 },
159 getMessage: function(msgId, substitutions)
160 {
161 if (msgId == "@@ui_locale")
162 return this._uiLocale;
163
164 for (var i = 0; i < this._localeCandidates.length; i++)
165 {
166 var catalog = this._getCatalog(this._localeCandidates[i]);
167 if (!catalog) 137 if (!catalog)
168 { 138 {
169 // if there is no catalog for this locale 139 // if there is no catalog for this locale
170 // candidate, don't try to load it again 140 // candidate, don't try to load it again
171 this._localeCandidates.splice(i--, 1); 141 localeCandidates.splice(i--, 1);
172 continue; 142 continue;
173 } 143 }
174 144
175 var msg = catalog[msgId]; 145 var msg = catalog[msgId];
176 if (!msg) 146 if (!msg)
177 continue; 147 continue;
178 148
179 var msgstr = msg.message; 149 var msgstr = msg.message;
180 if (!msgstr) 150 if (!msgstr)
181 continue; 151 continue;
182 152
183 for (var placeholder in msg.placeholders) 153 for (var placeholder in msg.placeholders)
184 { 154 {
185 var placeholderDetails = msg.placeholders[placeholder]; 155 var placeholderDetails = msg.placeholders[placeholder];
186 if (!placeholderDetails || !placeholderDetails.content) 156 if (!placeholderDetails || !placeholderDetails.content)
187 continue; 157 continue;
188 if (placeholderDetails.content.indexOf("$") != 0) 158 if (placeholderDetails.content.indexOf("$") != 0)
189 continue; 159 continue;
190 160
191 var placeholderIdx = parseInt(placeholderDetails.content.substr(1)); 161 var placeholderIdx = parseInt(placeholderDetails.content.substr(1));
192 if (isNaN(placeholderIdx) || placeholderIdx < 1) 162 if (isNaN(placeholderIdx) || placeholderIdx < 1)
193 continue; 163 continue;
194 164
195 var placeholderValue; 165 var placeholderValue;
196 if (Object.prototype.toString.call(substitutions) == "[object Array]") 166 if (substitutions && substitutions.constructor == Array)
197 placeholderValue = substitutions[placeholderIdx - 1]; 167 placeholderValue = substitutions[placeholderIdx - 1];
198 else if (placeholderIdx == 1) 168 else if (placeholderIdx == 1)
199 placeholderValue = substitutions; 169 placeholderValue = substitutions;
200 170
201 msgstr = msgstr.replace("$" + placeholder + "$", placeholderValue || " "); 171 msgstr = msgstr.replace("$" + placeholder + "$", placeholderValue || " ");
202 } 172 }
203 173
204 return msgstr; 174 return msgstr;
205 } 175 }
206 176
207 return ""; 177 return "";
208 } 178 }
209 }; 179 };
210 180
211 181
212 /* API */ 182 /* Utils */
213 183
214 ext = { 184 ext.getURL = function(path)
215 getURL: function(path) 185 {
216 { 186 return safari.extension.baseURI + path;
217 return safari.extension.baseURI + path;
218 },
219 i18n: new I18n()
220 }; 187 };
221 })(); 188 })();
OLDNEW
« notification.js ('K') | « safari/ext/background.js ('k') | safari/ext/content.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld