diff --git a/extensions/chromium/preferences_schema.json b/extensions/chromium/preferences_schema.json index 85cd24d2a..921ef28df 100644 --- a/extensions/chromium/preferences_schema.json +++ b/extensions/chromium/preferences_schema.json @@ -75,6 +75,19 @@ "useOnlyCssZoom": { "type": "boolean", "default": false + }, + "externalLinkTarget": { + "title": "External links target window", + "description": "Controls how external links will be opened.\n 0 = default.\n 1 = replaces current window.\n 2 = new window/tab.\n 3 = parent.\n 4 = in top window.", + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3, + 4 + ], + "default": 0 } } } diff --git a/extensions/firefox/bootstrap.js b/extensions/firefox/bootstrap.js index 2fb8cac09..0ff82985f 100644 --- a/extensions/firefox/bootstrap.js +++ b/extensions/firefox/bootstrap.js @@ -14,8 +14,7 @@ */ /* jshint esnext:true */ /* globals Components, Services, dump, XPCOMUtils, PdfStreamConverter, - APP_SHUTDOWN, PdfjsChromeUtils, PdfjsContentUtils, - DEFAULT_PREFERENCES */ + APP_SHUTDOWN, PdfjsChromeUtils, PdfjsContentUtils */ 'use strict'; @@ -47,7 +46,11 @@ function log(str) { } function initializeDefaultPreferences() { -//#include ../../web/default_preferences.js + var DEFAULT_PREFERENCES = +//#include ../../web/default_preferences.json +//#if false + 'end of DEFAULT_PREFERENCES'; +//#endif var defaultBranch = Services.prefs.getDefaultBranch(EXT_PREFIX + '.'); var defaultValue; diff --git a/extensions/firefox/content/PdfJs.jsm b/extensions/firefox/content/PdfJs.jsm index a1433d29b..09d4e34ef 100644 --- a/extensions/firefox/content/PdfJs.jsm +++ b/extensions/firefox/content/PdfJs.jsm @@ -14,7 +14,7 @@ */ /* jshint esnext:true */ /* globals Components, Services, XPCOMUtils, PdfjsChromeUtils, - PdfjsContentUtils, DEFAULT_PREFERENCES, PdfStreamConverter */ + PdfjsContentUtils, PdfStreamConverter */ 'use strict'; @@ -77,7 +77,11 @@ function isDefaultHandler() { } function initializeDefaultPreferences() { -//#include ../../../web/default_preferences.js + var DEFAULT_PREFERENCES = +//#include ../../../web/default_preferences.json +//#if false + 'end of DEFAULT_PREFERENCES'; +//#endif var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + '.'); var defaultValue; diff --git a/extensions/firefox/content/PdfjsChromeUtils.jsm b/extensions/firefox/content/PdfjsChromeUtils.jsm index a5f48327d..5b3e28d3a 100644 --- a/extensions/firefox/content/PdfjsChromeUtils.jsm +++ b/extensions/firefox/content/PdfjsChromeUtils.jsm @@ -13,7 +13,7 @@ * limitations under the License. */ /* jshint esnext:true */ -/* globals Components, Services, XPCOMUtils, DEFAULT_PREFERENCES */ +/* globals Components, Services, XPCOMUtils */ 'use strict'; @@ -35,7 +35,11 @@ XPCOMUtils.defineLazyServiceGetter(Svc, 'mime', '@mozilla.org/mime;1', 'nsIMIMEService'); -//#include ../../../web/default_preferences.js +var DEFAULT_PREFERENCES = +//#include ../../../web/default_preferences.json +//#if false + 'end of DEFAULT_PREFERENCES'; +//#endif var PdfjsChromeUtils = { // For security purposes when running remote, we restrict preferences diff --git a/gulpfile.js b/gulpfile.js index 6796065ac..0ac9dc1dc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -72,6 +72,22 @@ function stripUMDHeaders(content) { return content.replace(reg, ''); } +function checkChromePreferencesFile(chromePrefsPath, webPrefsPath) { + var chromePrefs = JSON.parse(fs.readFileSync(chromePrefsPath).toString()); + var chromePrefsKeys = Object.keys(chromePrefs.properties); + chromePrefsKeys.sort(); + var webPrefs = JSON.parse(fs.readFileSync(webPrefsPath).toString()); + var webPrefsKeys = Object.keys(webPrefs); + webPrefsKeys.sort(); + if (webPrefsKeys.length !== chromePrefsKeys.length) { + return false; + } + return webPrefsKeys.every(function (value, index) { + return chromePrefsKeys[index] === value && + chromePrefs.properties[value].default === webPrefs[value]; + }); +} + function bundle(filename, outfilename, pathPrefix, initFiles, amdName, defines, isMainFile, versionInfo) { // Reading UMD headers and building loading orders of modules. The @@ -489,6 +505,16 @@ gulp.task('lint', function (done) { return; } + console.log(); + console.log('### Checking supplemental files'); + + if (!checkChromePreferencesFile( + 'extensions/chromium/preferences_schema.json', + 'web/default_preferences.json')) { + done(new Error('chromium/preferences_schema is not in sync.')); + return; + } + console.log('files checked, no errors found'); done(); }); diff --git a/web/chromecom.js b/web/chromecom.js index 5f4eaf6a6..46ae1b3cc 100644 --- a/web/chromecom.js +++ b/web/chromecom.js @@ -13,7 +13,7 @@ * limitations under the License. */ -/* globals chrome, DEFAULT_PREFERENCES, DEFAULT_URL */ +/* globals chrome, DEFAULT_URL */ 'use strict'; (function (root, factory) { @@ -299,8 +299,8 @@ Preferences._writeToStorage = function (prefObj) { return new Promise(function (resolve) { - if (prefObj === DEFAULT_PREFERENCES) { - var keysToRemove = Object.keys(DEFAULT_PREFERENCES); + if (prefObj === Preferences.defaults) { + var keysToRemove = Object.keys(Preferences.defaults); // If the storage is reset, remove the keys so that the values from // managed storage are applied again. chrome.storage.local.remove(keysToRemove, function() { @@ -320,16 +320,16 @@ // Get preferences as set by the system administrator. // See extensions/chromium/preferences_schema.json for more information. // These preferences can be overridden by the user. - chrome.storage.managed.get(DEFAULT_PREFERENCES, getPreferences); + chrome.storage.managed.get(Preferences.defaults, getPreferences); } else { // Managed storage not supported, e.g. in old Chromium versions. - getPreferences(DEFAULT_PREFERENCES); + getPreferences(Preferences.defaults); } function getPreferences(defaultPrefs) { if (chrome.runtime.lastError) { // Managed storage not supported, e.g. in Opera. - defaultPrefs = DEFAULT_PREFERENCES; + defaultPrefs = Preferences.defaults; } chrome.storage.local.get(defaultPrefs, function(readPrefs) { resolve(readPrefs); diff --git a/web/default_preferences.js b/web/default_preferences.js index 510c50d73..b8fed8c18 100644 --- a/web/default_preferences.js +++ b/web/default_preferences.js @@ -15,21 +15,22 @@ 'use strict'; -//#if CHROME -////Note: Keep in sync with extensions/chromium/preferences_schema.json ! -//#endif -var DEFAULT_PREFERENCES = { - showPreviousViewOnLoad: true, - defaultZoomValue: '', - sidebarViewOnLoad: 0, - enableHandToolOnLoad: false, - enableWebGL: false, - pdfBugEnabled: false, - disableRange: false, - disableStream: false, - disableAutoFetch: false, - disableFontFace: false, - disableTextLayer: false, - useOnlyCssZoom: false, - externalLinkTarget: 0, -}; +var DEFAULT_PREFERENCES; + +(function defaultPreferencesLoaderWrapper() { + function loaded() { + try { + DEFAULT_PREFERENCES = JSON.parse(xhr.responseText); + } catch (e) { + console.error('Unable to load DEFAULT_PREFERENCES: ' + e); + DEFAULT_PREFERENCES = {}; + } + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('defaultpreferencesloaded', true, true, null); + document.dispatchEvent(event); + } + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'default_preferences.json'); + xhr.onload = xhr.onerror = loaded; + xhr.send(); +})(); diff --git a/web/default_preferences.json b/web/default_preferences.json new file mode 100644 index 000000000..af97bffd1 --- /dev/null +++ b/web/default_preferences.json @@ -0,0 +1,15 @@ +{ + "showPreviousViewOnLoad": true, + "defaultZoomValue": "", + "sidebarViewOnLoad": 0, + "enableHandToolOnLoad": false, + "enableWebGL": false, + "pdfBugEnabled": false, + "disableRange": false, + "disableStream": false, + "disableAutoFetch": false, + "disableFontFace": false, + "disableTextLayer": false, + "useOnlyCssZoom": false, + "externalLinkTarget": 0 +} \ No newline at end of file diff --git a/web/preferences.js b/web/preferences.js index ec43653f3..b5fad7518 100644 --- a/web/preferences.js +++ b/web/preferences.js @@ -26,7 +26,32 @@ } }(this, function (exports) { -//#include $ROOT/web/default_preferences.js +//#if PRODUCTION +//var defaultPreferences = Promise.resolve( +//#include $ROOT/web/default_preferences.json +//); +//#else + var defaultPreferences = new Promise(function (resolve) { + if (DEFAULT_PREFERENCES) { + resolve(DEFAULT_PREFERENCES); + return; + } + document.addEventListener('defaultpreferencesloaded', function loaded() { + resolve(DEFAULT_PREFERENCES); + document.removeEventListener('defaultpreferencesloaded', loaded); + }); + }); +//#endif + +function cloneObj(obj) { + var result = {}; + for (var i in obj) { + if (Object.prototype.hasOwnProperty.call(obj, i)) { + result[i] = obj[i]; + } + } + return result; +} /** * Preferences - Utility for storing persistent settings. @@ -34,7 +59,7 @@ * or every time the viewer is loaded. */ var Preferences = { - prefs: Object.create(DEFAULT_PREFERENCES), + prefs: null, isInitializedPromiseResolved: false, initializedPromise: null, @@ -44,8 +69,19 @@ var Preferences = { * have been initialized. */ initialize: function preferencesInitialize() { - return this.initializedPromise = - this._readFromStorage(DEFAULT_PREFERENCES).then(function(prefObj) { + return this.initializedPromise = defaultPreferences.then( + function (defaults) { + + Object.defineProperty(this, 'defaults', { + value: Object.freeze(defaults), + writable: false, + enumerable: true, + configurable: false + }); + + this.prefs = cloneObj(defaults); + return this._readFromStorage(defaults); + }.bind(this)).then(function(prefObj) { this.isInitializedPromiseResolved = true; if (prefObj) { this.prefs = prefObj; @@ -82,8 +118,8 @@ var Preferences = { */ reset: function preferencesReset() { return this.initializedPromise.then(function() { - this.prefs = Object.create(DEFAULT_PREFERENCES); - return this._writeToStorage(DEFAULT_PREFERENCES); + this.prefs = cloneObj(this.defaults); + return this._writeToStorage(this.defaults); }.bind(this)); }, @@ -94,7 +130,7 @@ var Preferences = { */ reload: function preferencesReload() { return this.initializedPromise.then(function () { - this._readFromStorage(DEFAULT_PREFERENCES).then(function(prefObj) { + this._readFromStorage(this.defaults).then(function(prefObj) { if (prefObj) { this.prefs = prefObj; } @@ -111,13 +147,13 @@ var Preferences = { */ set: function preferencesSet(name, value) { return this.initializedPromise.then(function () { - if (DEFAULT_PREFERENCES[name] === undefined) { + if (this.defaults[name] === undefined) { throw new Error('preferencesSet: \'' + name + '\' is undefined.'); } else if (value === undefined) { throw new Error('preferencesSet: no value is specified.'); } var valueType = typeof value; - var defaultType = typeof DEFAULT_PREFERENCES[name]; + var defaultType = typeof this.defaults[name]; if (valueType !== defaultType) { if (valueType === 'number' && defaultType === 'string') { @@ -145,7 +181,7 @@ var Preferences = { */ get: function preferencesGet(name) { return this.initializedPromise.then(function () { - var defaultValue = DEFAULT_PREFERENCES[name]; + var defaultValue = this.defaults[name]; if (defaultValue === undefined) { throw new Error('preferencesGet: \'' + name + '\' is undefined.');