| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | |
| 3 * Copyright (C) 2006-2016 Eyeo GmbH | |
| 4 * | |
| 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 | |
| 7 * published by the Free Software Foundation. | |
| 8 * | |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 * GNU General Public License for more details. | |
| 13 * | |
| 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/>. | |
| 16 */ | |
| 17 | |
| 18 (function() | |
| 19 { | |
| 20 /* Message passing */ | |
| 21 | |
| 22 var MessageProxy = ext._MessageProxy = function(messageDispatcher) | |
| 23 { | |
| 24 this._messageDispatcher = messageDispatcher; | |
| 25 this._responseCallbacks = Object.create(null); | |
| 26 this._responseCallbackCounter = 0; | |
| 27 }; | |
| 28 MessageProxy.prototype = { | |
| 29 _sendResponse: function(request, message) | |
| 30 { | |
| 31 var response = {}; | |
| 32 | |
| 33 if ("documentId" in request) | |
| 34 response["targetDocuments"] = [request["documentId"]]; | |
| 35 | |
| 36 for (var prop in request) | |
| 37 response[prop] = request[prop]; | |
| 38 response.payload = message; | |
| 39 | |
| 40 this._messageDispatcher.dispatchMessage("response", response); | |
| 41 }, | |
| 42 handleRequest: function(request, sender) | |
| 43 { | |
| 44 if ("callbackId" in request) | |
| 45 { | |
| 46 var sent = false; | |
| 47 var sendResponse = function(message) | |
| 48 { | |
| 49 this._sendResponse(request, message); | |
| 50 sent = true; | |
| 51 }.bind(this); | |
| 52 | |
| 53 var results = ext.onMessage._dispatch(request.payload, sender, sendRespo
nse); | |
| 54 | |
| 55 // The onMessage listener has to return true to indicate that a response | |
| 56 // is sent later asynchronously. Otherwise if no response was sent yet, | |
| 57 // we sent a response indicating that there is no response, that | |
| 58 // the other end can remove the callback and doesn't leak memory. | |
| 59 if (!sent && results.indexOf(true) == -1) | |
| 60 this._sendResponse(request, undefined); | |
| 61 } | |
| 62 else | |
| 63 { | |
| 64 ext.onMessage._dispatch(request.payload, sender, function() {}); | |
| 65 } | |
| 66 }, | |
| 67 handleResponse: function(response) | |
| 68 { | |
| 69 var callbackId = response.callbackId; | |
| 70 var callback = this._responseCallbacks[callbackId]; | |
| 71 if (callback) | |
| 72 { | |
| 73 delete this._responseCallbacks[callbackId]; | |
| 74 | |
| 75 if (typeof response.payload != "undefined") | |
| 76 callback(response.payload); | |
| 77 } | |
| 78 }, | |
| 79 sendMessage: function(message, responseCallback, extra) | |
| 80 { | |
| 81 var request = {payload: message}; | |
| 82 | |
| 83 if (responseCallback) | |
| 84 { | |
| 85 request.callbackId = ++this._responseCallbackCounter; | |
| 86 this._responseCallbacks[request.callbackId] = responseCallback; | |
| 87 } | |
| 88 | |
| 89 for (var prop in extra) | |
| 90 request[prop] = extra[prop]; | |
| 91 | |
| 92 this._messageDispatcher.dispatchMessage("request", request); | |
| 93 } | |
| 94 }; | |
| 95 | |
| 96 ext.onMessage = new ext._EventTarget(); | |
| 97 | |
| 98 | |
| 99 /* I18n */ | |
| 100 | |
| 101 var getLocaleCandidates = function() | |
| 102 { | |
| 103 var candidates = []; | |
| 104 var defaultLocale = "en_US"; | |
| 105 | |
| 106 // e.g. "ja-jp-mac" -> "ja_JP", note that the part after the second | |
| 107 // dash is dropped, since we only support language and region | |
| 108 var [language, region] = navigator.language.split("-"); | |
| 109 | |
| 110 if (region) | |
| 111 { | |
| 112 region = region.toUpperCase(); | |
| 113 | |
| 114 // e.g. "es-AR" -> "es_419", note that we combine all dialects of | |
| 115 // Spanish outside of Spain, the same way Google Chrome does, | |
| 116 // since we use the same translations as for the Chrome extension | |
| 117 if (language == "es" && region != "ES") | |
| 118 region = "419"; | |
| 119 | |
| 120 candidates.push(language + "_" + region); | |
| 121 } | |
| 122 | |
| 123 candidates.push(language); | |
| 124 | |
| 125 if (candidates.indexOf(defaultLocale) == -1) | |
| 126 candidates.push(defaultLocale); | |
| 127 | |
| 128 return candidates; | |
| 129 }; | |
| 130 | |
| 131 var initCatalog = function(uiLocale) | |
| 132 { | |
| 133 var bidiDir = /^(ar|fa|he|ug|ur)(_|$)/.test(uiLocale) ? "rtl" : "ltr"; | |
| 134 var catalog = Object.create(null); | |
| 135 | |
| 136 catalog["@@ui_locale"] = [uiLocale, []]; | |
| 137 catalog["@@bidi_dir" ] = [bidiDir, []]; | |
| 138 | |
| 139 return catalog; | |
| 140 }; | |
| 141 | |
| 142 var locales = getLocaleCandidates(); | |
| 143 var catalog = initCatalog(locales[0]); | |
| 144 | |
| 145 var replacePlaceholder = function(text, placeholder, content) | |
| 146 { | |
| 147 return text.split("$" + placeholder + "$").join(content || ""); | |
| 148 }; | |
| 149 | |
| 150 var parseMessage = function(rawMessage) | |
| 151 { | |
| 152 var text = rawMessage.message; | |
| 153 var placeholders = []; | |
| 154 | |
| 155 for (var placeholder in rawMessage.placeholders) | |
| 156 { | |
| 157 var content = rawMessage.placeholders[placeholder].content; | |
| 158 | |
| 159 if (/^\$\d+$/.test(content)) | |
| 160 placeholders[parseInt(content.substr(1), 10) - 1] = placeholder; | |
| 161 else | |
| 162 text = replacePlaceholder(text, placeholder, content); | |
| 163 } | |
| 164 | |
| 165 return [text, placeholders]; | |
| 166 }; | |
| 167 | |
| 168 var readCatalog = function(locale) | |
| 169 { | |
| 170 var xhr = new XMLHttpRequest(); | |
| 171 xhr.open("GET", safari.extension.baseURI + "_locales/" + locale + "/messages
.json", false); | |
| 172 | |
| 173 try | |
| 174 { | |
| 175 xhr.send(); | |
| 176 } | |
| 177 catch (e) | |
| 178 { | |
| 179 return; | |
| 180 } | |
| 181 | |
| 182 if (xhr.status != 200 && xhr.status != 0) | |
| 183 return; | |
| 184 | |
| 185 var rawCatalog = JSON.parse(xhr.responseText); | |
| 186 for (var msgId in rawCatalog) | |
| 187 { | |
| 188 if (!(msgId in catalog)) | |
| 189 catalog[msgId] = parseMessage(rawCatalog[msgId]); | |
| 190 } | |
| 191 }; | |
| 192 | |
| 193 ext.i18n = { | |
| 194 getMessage: function(msgId, substitutions) | |
| 195 { | |
| 196 while (true) | |
| 197 { | |
| 198 var message = catalog[msgId]; | |
| 199 if (message) | |
| 200 { | |
| 201 var [text, placeholders] = message; | |
| 202 | |
| 203 if (!(substitutions instanceof Array)) | |
| 204 substitutions = [substitutions]; | |
| 205 | |
| 206 for (var i = 0; i < placeholders.length; i++) | |
| 207 text = replacePlaceholder(text, placeholders[i], substitutions[i]); | |
| 208 | |
| 209 return text; | |
| 210 } | |
| 211 | |
| 212 if (locales.length == 0) | |
| 213 return ""; | |
| 214 | |
| 215 readCatalog(locales.shift()); | |
| 216 } | |
| 217 } | |
| 218 }; | |
| 219 | |
| 220 | |
| 221 /* Utils */ | |
| 222 | |
| 223 ext.getURL = function(path) | |
| 224 { | |
| 225 return safari.extension.baseURI + path; | |
| 226 }; | |
| 227 })(); | |
| OLD | NEW |