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

Side by Side Diff: lib/adblockplus_compat.js

Issue 8483154: Adding ABP core modules to ABP/Opera (Closed)
Patch Set: Created Oct. 9, 2012, 9:51 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
(Empty)
1 /*
2 * This Source Code is subject to the terms of the Mozilla Public License
3 * version 2.0 (the "License"). You can obtain a copy of the License at
4 * http://mozilla.org/MPL/2.0/.
5 */
6
7 // TODO: Parts of this file are identical to ABP/Chrome, these should be split
8 // away into a separate file.
9
10 //
11 // Module framework stuff
12 //
13
14 function require(module)
15 {
16 return require.scopes[module];
17 }
18 require.scopes = {__proto__: null};
19
20 function importAll(module, globalObj)
21 {
22 var exports = require(module);
23 for (var key in exports)
24 globalObj[key] = exports[key];
25 }
26
27 onShutdown = {
28 done: false,
29 add: function() {},
30 remove: function() {}
31 };
32
33 //
34 // XPCOM emulation
35 //
36
37 var Components =
38 {
39 interfaces:
40 {
41 nsIFile: {DIRECTORY_TYPE: 0},
42 nsIFileURL: function() {},
43 nsIHttpChannel: function() {},
44 nsITimer: {TYPE_REPEATING_SLACK: 0},
45 nsIInterfaceRequestor: null,
46 nsIChannelEventSink: null
47 },
48 classes:
49 {
50 "@mozilla.org/timer;1":
51 {
52 createInstance: function()
53 {
54 return new FakeTimer();
55 }
56 },
57 "@mozilla.org/xmlextras/xmlhttprequest;1":
58 {
59 createInstance: function()
60 {
61 return new XMLHttpRequest();
62 }
63 }
64 },
65 results: {},
66 utils: {
67 reportError: function(e)
68 {
69 opera.postError(e + "\n" + (typeof e == "object" ? e.stack : new Error().s tack));
70 }
71 },
72 manager: null,
73 ID: function()
74 {
75 return null;
76 }
77 };
78 const Cc = Components.classes;
79 const Ci = Components.interfaces;
80 const Cr = Components.results;
81 const Cu = Components.utils;
82
83 var XPCOMUtils =
84 {
85 generateQI: function() {}
86 };
87
88 //
89 // Info pseudo-module
90 //
91
92 require.scopes.info =
93 {
94 get addonID()
95 {
96 return widget.id;
97 },
98 addonVersion: "2.0.3", // Hardcoded for now
99 addonRoot: "",
100 get addonName()
101 {
102 return widget.name;
103 },
104 application: "opera"
105 };
106
107 //
108 // IO module: no direct file system access, using FileSystem API
109 //
110
111 require.scopes.io =
112 {
113 IO: {
Felix Dahlke 2012/10/10 12:11:22 Opening brace not on its own line?
Felix Dahlke 2012/10/11 07:54:28 Nevermind.
114 _getFilePath: function(file)
115 {
116 if (file instanceof FakeFile)
117 return file.path;
118 else if ("spec" in file)
119 return file.spec;
120
121 throw new Error("Unexpected file type");
122 },
123
124 lineBreak: "\n",
125
126 resolveFilePath: function(path)
127 {
128 return new FakeFile(path);
129 },
130
131 readFromFile: function(file, decode, listener, callback, timeLineID)
132 {
133 if ("spec" in file && /^defaults\b/.test(file.spec))
Felix Dahlke 2012/10/10 12:11:22 The first check is not necessary, .test(undefined)
Felix Dahlke 2012/10/11 07:54:28 Nevermind.
Wladimir Palant 2012/10/11 09:36:26 Still, I don't feel comfortable running regular ex
134 {
135 // Code attempts to read the default patterns.ini, we don't have that.
136 // Make sure to execute first-run actions instead.
137 callback(null);
138 executeFirstRunActions();
Felix Dahlke 2012/10/11 07:54:28 This function cannot be called from here.
139 return;
140 }
141
142 var path = this._getFilePath(file);
143 if (!(path in window.localStorage))
144 {
145 callback(new Error("File doesn't exist"))
146 return;
147 }
148
149 var lines = window.localStorage[path].split(/[\r\n]+/);
150
151 // Fake asynchronous execution
152 setTimeout(function()
153 {
154 for (var i = 0; i < lines.length; i++)
155 listener.process(lines[i]);
156 listener.process(null);
157 callback(null);
158 }.bind(this), 0);
159 },
160
161 writeToFile: function(file, encode, data, callback, timeLineID)
162 {
163 var path = this._getFilePath(file);
164 window.localStorage[path] = data.join("\n") + "\n";
Felix Dahlke 2012/10/10 12:11:22 Why not use this.lineBreak?
165 window.localStorage[path + "/lastModified"] = Date.now();
166
167 // Fake asynchronous execution
168 setTimeout(callback.bind(null, null), 0);
169 },
170
171 copyFile: function(fromFile, toFile, callback)
172 {
173 // Simply combine read and write operations
174 var data = [];
175 this.readFromFile(fromFile, false, {
Felix Dahlke 2012/10/10 12:11:22 Shouldn't the opening brace be on its own line?
176 process: function(line)
177 {
178 if (line !== null)
179 data.push(line);
180 }
181 }, function(e)
182 {
183 if (e)
184 callback(e);
185 else
186 this.writeToFile(toFile, false, data, callback);
187 }.bind(this));
188 },
189
190 renameFile: function(fromFile, newName, callback)
191 {
192 var path = this._getFilePath(fromFile);
193 if (!(path in window.localStorage))
194 {
195 callback(new Error("File doesn't exist"))
196 return;
197 }
198
199 window.localStorage[newName] = window.localStorage[path];
200 window.localStorage[newName + "/lastModified"] = window.localStorage[path + "/lastModified"] || 0;
Felix Dahlke 2012/10/10 12:11:22 How about a function that sets both localStorage[x
201 delete window.localStorage[path];
202 delete window.localStorage[path + "/lastModified"];
203 callback(null);
204 },
205
206 removeFile: function(file, callback)
207 {
208 var path = this._getFilePath(file);
209 delete window.localStorage[path];
Felix Dahlke 2012/10/10 12:11:22 How about a function to delete both localStorage[x
210 delete window.localStorage[path + "/lastModified"];
211 callback(null);
212 },
213
214 statFile: function(file, callback)
215 {
216 var path = this._getFilePath(file);
217 callback(null, {
218 exists: path in window.localStorage,
219 isDirectory: false,
220 isFile: true,
221 lastModified: parseInt(window.localStorage[path + "/lastModified"], 10) || 0
222 });
223 }
224 }
225 };
226
227 //
228 // Fake nsIFile implementation for our I/O
229 //
230
231 function FakeFile(path)
232 {
233 this.path = path;
234 }
235 FakeFile.prototype =
236 {
237 get leafName()
238 {
239 return this.path;
240 },
241 set leafName(value)
242 {
243 this.path = value;
244 },
245 append: function(path)
246 {
247 this.path += path;
248 },
249 clone: function()
250 {
251 return new FakeFile(this.path);
252 },
253 get parent()
254 {
255 return {create: function() {}};
256 },
257 normalize: function() {}
258 };
259
260 //
261 // Prefs module: the values are hardcoded for now.
262 //
263
264 require.scopes.prefs = {
265 Prefs: {
266 enabled: true,
267 patternsfile: "patterns.ini",
268 patternsbackups: 0,
269 patternsbackupinterval: 24,
270 data_directory: "",
271 savestats: false,
272 privateBrowsing: false,
273 subscriptions_fallbackerrors: 5,
274 subscriptions_fallbackurl: "https://adblockplus.org/getSubscription?version= %VERSION%&url=%SUBSCRIPTION%&downloadURL=%URL%&error=%ERROR%&channelStatus=%CHAN NELSTATUS%&responseStatus=%RESPONSESTATUS%",
275 subscriptions_autoupdate: true,
276 subscriptions_exceptionsurl: "https://easylist-downloads.adblockplus.org/exc eptionrules.txt",
277 documentation_link: "https://adblockplus.org/redirect?link=%LINK%&lang=%LANG %",
278 addListener: function() {}
279 }
280 };
281
282 //
283 // Utils module
284 //
285
286 require.scopes.utils =
287 {
288 Utils: {
289 systemPrincipal: null,
290 getString: function(id)
291 {
292 return id;
293 },
294 runAsync: function(callback, thisPtr)
295 {
296 var params = Array.prototype.slice.call(arguments, 2);
297 window.setTimeout(function()
298 {
299 callback.apply(thisPtr, params);
300 }, 0);
301 },
302 get appLocale()
303 {
304 // Note: navigator.language
305 return window.navigator.browserLanguage;
306 },
307 generateChecksum: function(lines)
308 {
309 // We cannot calculate MD5 checksums yet :-(
310 return null;
311 },
312 makeURI: function(url)
313 {
314 return Services.io.newURI(url);
315 },
316 checkLocalePrefixMatch: function(prefixes)
317 {
318 if (!prefixes)
319 return null;
320
321 var list = prefixes.split(",");
322 for (var i = 0; i < list.length; i++)
323 if (new RegExp("^" + list[i] + "\\b").test(this.appLocale))
324 return list[i];
325
326 return null;
327 }
328 }
329 };
330
331 //
332 // ElemHideHitRegistration dummy implementation
333 //
334
335 require.scopes.elemHideHitRegistration =
336 {
337 AboutHandler: {}
338 };
339
340 //
341 // Services.jsm module emulation
342 //
343
344 var Services =
345 {
346 io: {
347 newURI: function(uri)
348 {
349 if (!uri.length || uri[0] == "~")
350 throw new Error("Invalid URI");
351
352 /^([^:\/]*)/.test(uri);
353 var scheme = RegExp.$1.toLowerCase();
354
355 return {
356 scheme: scheme,
357 spec: uri,
358 QueryInterface: function()
359 {
360 return this;
361 }
362 };
363 },
364 newFileURI: function(file)
365 {
366 var result = this.newURI("file:///" + file.path);
367 result.file = file;
368 return result;
369 }
370 },
371 obs: {
372 addObserver: function() {},
373 removeObserver: function() {}
374 },
375 vc: {
376 compare: function(v1, v2)
377 {
378 function parsePart(s)
379 {
380 if (!s)
381 return parsePart("0");
382
383 var part = {
384 numA: 0,
385 strB: "",
386 numC: 0,
387 extraD: ""
388 };
389
390 if (s === "*")
391 {
392 part.numA = Number.MAX_VALUE;
393 return part;
394 }
395
396 var matches = s.match(/(\d*)(\D*)(\d*)(.*)/);
397 part.numA = parseInt(matches[1], 10) || part.numA;
398 part.strB = matches[2] || part.strB;
399 part.numC = parseInt(matches[3], 10) || part.numC;
400 part.extraD = matches[4] || part.extraD;
401
402 if (part.strB == "+")
403 {
404 part.numA++;
405 part.strB = "pre";
406 }
407
408 return part;
409 }
410
411 function comparePartElement(s1, s2)
412 {
413 if (s1 === "" && s2 !== "")
414 return 1;
415 if (s1 !== "" && s2 === "")
416 return -1;
417 return s1 === s2 ? 0 : (s1 > s2 ? 1 : -1);
418 }
419
420 function compareParts(p1, p2)
421 {
422 var result = 0;
423 var elements = ["numA", "strB", "numC", "extraD"];
424 elements.some(function(element)
425 {
426 result = comparePartElement(p1[element], p2[element]);
427 return result;
428 });
429 return result;
430 }
431
432 var parts1 = v1.split(".");
433 var parts2 = v2.split(".");
434 for (var i = 0; i < Math.max(parts1.length, parts2.length); i++)
435 {
436 var result = compareParts(parsePart(parts1[i]), parsePart(parts2[i]));
437 if (result)
438 return result;
439 }
440 return 0;
441 }
442 }
443 }
444
445 //
446 // FileUtils.jsm module emulation
447 //
448
449 var FileUtils =
450 {
451 PERMS_DIRECTORY: 0
452 };
453
454 function FakeTimer()
455 {
456 }
457 FakeTimer.prototype =
458 {
459 delay: 0,
460 callback: null,
461 initWithCallback: function(callback, delay)
462 {
463 this.callback = callback;
464 this.delay = delay;
465 this.scheduleTimeout();
466 },
467 scheduleTimeout: function()
468 {
469 var me = this;
470 window.setTimeout(function()
471 {
472 try
473 {
474 me.callback();
475 }
476 catch(e)
477 {
478 Cu.reportError(e);
479 }
480 me.scheduleTimeout();
481 }, this.delay);
482 }
483 };
484
485 //
486 // Add a channel property to XMLHttpRequest, Synchronizer needs it
487 //
488
489 XMLHttpRequest.prototype.channel =
490 {
491 status: -1,
492 notificationCallbacks: {},
493 loadFlags: 0,
494 INHIBIT_CACHING: 0,
495 VALIDATE_ALWAYS: 0,
496 QueryInterface: function()
497 {
498 return this;
499 }
500 };
OLDNEW

Powered by Google App Engine
This is Rietveld