diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index db84e8254..38d9af92b 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -16,7 +16,7 @@ */ /* jshint esnext:true */ /* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils, - dump, NetworkManager, PdfJsTelemetry */ + dump, NetworkManager, PdfJsTelemetry, DEFAULT_PREFERENCES */ 'use strict'; @@ -33,12 +33,16 @@ const PDF_CONTENT_TYPE = 'application/pdf'; const PREF_PREFIX = 'PDFJSSCRIPT_PREF_PREFIX'; const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html'; const MAX_DATABASE_LENGTH = 4096; +const MAX_STRING_PREF_LENGTH = 4096; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/NetUtil.jsm'); Cu.import('resource://pdf.js/network.js'); +// Load the default preferences. +Cu.import('resource://pdf.js/default_preferences.js'); + XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils', 'resource://gre/modules/PrivateBrowsingUtils.jsm'); @@ -58,6 +62,10 @@ function getChromeWindow(domWindow) { return containingBrowser.ownerDocument.defaultView; } +function setBoolPref(pref, value) { + Services.prefs.setBoolPref(pref, value); +} + function getBoolPref(pref, def) { try { return Services.prefs.getBoolPref(pref); @@ -66,6 +74,10 @@ function getBoolPref(pref, def) { } } +function setIntPref(pref, value) { + Services.prefs.setIntPref(pref, value); +} + function getIntPref(pref, def) { try { return Services.prefs.getIntPref(pref); @@ -431,6 +443,62 @@ ChromeActions.prototype = { } getChromeWindow(this.domWindow).gFindBar .updateControlState(result, findPrevious); + }, + setPreferences: function(prefs) { + var prefValue, defaultValue, prefName, prefType, defaultType; + + for (var key in DEFAULT_PREFERENCES) { + prefValue = prefs[key]; + defaultValue = DEFAULT_PREFERENCES[key]; + prefName = (PREF_PREFIX + '.' + key); + + if (!prefValue || prefValue === defaultValue) { + Services.prefs.clearUserPref(prefName); + } else { + prefType = typeof prefValue; + defaultType = typeof defaultValue; + + if (prefType !== defaultType) { + continue; + } + switch (defaultType) { + case 'boolean': + setBoolPref(prefName, prefValue); + break; + case 'number': + setIntPref(prefName, prefValue); + break; + case 'string': + // Protect against adding arbitrarily long strings in about:config. + if (prefValue.length <= MAX_STRING_PREF_LENGTH) { + setStringPref(prefName, prefValue); + } + break; + } + } + } + }, + getPreferences: function() { + var currentPrefs = {}; + var defaultValue, prefName; + + for (var key in DEFAULT_PREFERENCES) { + defaultValue = DEFAULT_PREFERENCES[key]; + prefName = (PREF_PREFIX + '.' + key); + + switch (typeof defaultValue) { + case 'boolean': + currentPrefs[key] = getBoolPref(prefName, defaultValue); + break; + case 'number': + currentPrefs[key] = getIntPref(prefName, defaultValue); + break; + case 'string': + currentPrefs[key] = getStringPref(prefName, defaultValue); + break; + } + } + return JSON.stringify(currentPrefs); } }; diff --git a/make.js b/make.js index ca6c77181..6b5b84985 100644 --- a/make.js +++ b/make.js @@ -436,7 +436,8 @@ target.firefox = function() { copy: [ [COMMON_WEB_FILES, FIREFOX_BUILD_CONTENT_DIR + '/web'], [FIREFOX_EXTENSION_DIR + 'tools/l10n.js', - FIREFOX_BUILD_CONTENT_DIR + '/web'] + FIREFOX_BUILD_CONTENT_DIR + '/web'], + ['web/default_preferences.js', FIREFOX_BUILD_CONTENT_DIR] ], preprocess: [ [COMMON_WEB_FILES_PREPROCESS, FIREFOX_BUILD_CONTENT_DIR + '/web'], @@ -551,7 +552,8 @@ target.mozcentral = function() { defines: defines, copy: [ [COMMON_WEB_FILES, MOZCENTRAL_CONTENT_DIR + '/web'], - ['extensions/firefox/tools/l10n.js', MOZCENTRAL_CONTENT_DIR + '/web'] + ['extensions/firefox/tools/l10n.js', MOZCENTRAL_CONTENT_DIR + '/web'], + ['web/default_preferences.js', MOZCENTRAL_CONTENT_DIR] ], preprocess: [ [COMMON_WEB_FILES_PREPROCESS, MOZCENTRAL_CONTENT_DIR + '/web'], diff --git a/web/default_preferences.js b/web/default_preferences.js new file mode 100644 index 000000000..498907751 --- /dev/null +++ b/web/default_preferences.js @@ -0,0 +1,27 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2013 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* globals */ + +'use strict'; + +var EXPORTED_SYMBOLS = ['DEFAULT_PREFERENCES']; + +var DEFAULT_PREFERENCES = { + showPreviousViewOnLoad: true, + defaultZoomValue: '', + ifAvailableShowOutlineOnLoad: false +}; diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 488fcd4dd..6826097f2 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* globals Preferences, PDFJS */ 'use strict'; @@ -102,3 +103,14 @@ var DownloadManager = (function DownloadManagerClosure() { return DownloadManager; })(); + +Preferences.prototype.writeToStorage = function(prefObj) { + FirefoxCom.requestSync('setPreferences', prefObj); +}; + +Preferences.prototype.readFromStorage = function() { + var readFromStoragePromise = new PDFJS.Promise(); + var readPrefs = JSON.parse(FirefoxCom.requestSync('getPreferences')); + readFromStoragePromise.resolve(readPrefs); + return readFromStoragePromise; +}; diff --git a/web/preferences.js b/web/preferences.js new file mode 100644 index 000000000..2e3625e5e --- /dev/null +++ b/web/preferences.js @@ -0,0 +1,126 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2013 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* globals DEFAULT_PREFERENCES, PDFJS, isLocalStorageEnabled */ + +'use strict'; + +//#include default_preferences.js + +var Preferences = (function PreferencesClosure() { + function Preferences() { + this.prefs = {}; + this.initializedPromise = this.readFromStorage().then(function(prefObj) { + if (prefObj) { + this.prefs = prefObj; + } + }.bind(this)); + } + + Preferences.prototype = { + writeToStorage: function Preferences_writeToStorage(prefObj) { + return; + }, + + readFromStorage: function Preferences_readFromStorage() { + var readFromStoragePromise = new PDFJS.Promise(); + return readFromStoragePromise; + }, + + reset: function Preferences_reset() { + if (this.initializedPromise.isResolved) { + this.prefs = {}; + this.writeToStorage(this.prefs); + } + }, + + set: function Preferences_set(name, value) { + if (!this.initializedPromise.isResolved) { + return; + } else if (DEFAULT_PREFERENCES[name] === undefined) { + console.error('Preferences_set: \'' + name + '\' is undefined.'); + return; + } else if (value === undefined) { + console.error('Preferences_set: no value is specified.'); + return; + } + var valueType = typeof value; + var defaultType = typeof DEFAULT_PREFERENCES[name]; + + if (valueType !== defaultType) { + if (valueType === 'number' && defaultType === 'string') { + value = value.toString(); + } else { + console.error('Preferences_set: \'' + value + '\' is a \"' + + valueType + '\", expected a \"' + defaultType + '\".'); + return; + } + } + this.prefs[name] = value; + this.writeToStorage(this.prefs); + }, + + get: function Preferences_get(name) { + var defaultPref = DEFAULT_PREFERENCES[name]; + + if (defaultPref === undefined) { + console.error('Preferences_get: \'' + name + '\' is undefined.'); + return; + } else if (this.initializedPromise.isResolved) { + var pref = this.prefs[name]; + + if (pref !== undefined) { + return pref; + } + } + return defaultPref; + } + }; + + return Preferences; +})(); + +//#if B2G +//Preferences.prototype.writeToStorage = function(prefObj) { +// asyncStorage.setItem('preferences', JSON.stringify(prefObj)); +//}; +// +//Preferences.prototype.readFromStorage = function() { +// var readFromStoragePromise = new PDFJS.Promise(); +// asyncStorage.getItem('preferences', function(prefString) { +// var readPrefs = JSON.parse(prefString); +// readFromStoragePromise.resolve(readPrefs); +// }); +// return readFromStoragePromise; +//}; +//#endif + +//#if !(FIREFOX || MOZCENTRAL || B2G) +Preferences.prototype.writeToStorage = function(prefObj) { + if (isLocalStorageEnabled) { + localStorage.setItem('preferences', JSON.stringify(prefObj)); + } +}; + +Preferences.prototype.readFromStorage = function() { + var readFromStoragePromise = new PDFJS.Promise(); + if (isLocalStorageEnabled) { + var readPrefs = JSON.parse(localStorage.getItem('preferences')); + readFromStoragePromise.resolve(readPrefs); + } + return readFromStoragePromise; +}; +//#endif diff --git a/web/ui_utils.js b/web/ui_utils.js index 0a85321a5..8b2c1f121 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -240,3 +240,16 @@ var Cache = function cacheCache(size) { }; }; +//#if !(FIREFOX || MOZCENTRAL || B2G) +var isLocalStorageEnabled = (function isLocalStorageEnabledClosure() { + // Feature test as per http://diveintohtml5.info/storage.html + // The additional localStorage call is to get around a FF quirk, see + // bug #495747 in bugzilla + try { + return ('localStorage' in window && window['localStorage'] !== null && + localStorage); + } catch (e) { + return false; + } +})(); +//#endif diff --git a/web/viewer.html b/web/viewer.html index 4dc8e69c5..148489cab 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -62,6 +62,8 @@ limitations under the License. + + diff --git a/web/viewer.js b/web/viewer.js index a5b2a4675..ff98f28da 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -16,8 +16,8 @@ */ /* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar, CustomStyle, PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager, - getFileName, getOutputScale, scrollIntoView, getPDFFileNameFromURL, - PDFHistory, Settings, PageView, ThumbnailView, noContextMenuHandler, + getFileName, scrollIntoView, getPDFFileNameFromURL, PDFHistory, + Preferences, Settings, PageView, ThumbnailView, noContextMenuHandler, SecondaryToolbar, PasswordPrompt, PresentationMode */ 'use strict'; @@ -63,6 +63,7 @@ PDFJS.imageResourcesPath = './images/'; var mozL10n = document.mozL10n || document.webL10n; //#include ui_utils.js +//#include preferences.js //#if !(FIREFOX || MOZCENTRAL || B2G) //#include mozPrintCallback_polyfill.js @@ -235,6 +236,10 @@ var PDFView = { case 'auto': scale = Math.min(MAX_AUTO_SCALE, pageWidthScale); break; + default: + console.error('pdfViewSetScale: \'' + value + + '\' is an unknown zoom value.'); + return; } } this.currentScaleValue = value; @@ -814,6 +819,7 @@ var PDFView = { mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}'); document.getElementById('pageNumber').max = pagesCount; + var prefs = PDFView.prefs = new Preferences(); PDFView.documentFingerprint = id; var store = PDFView.store = new Settings(id); @@ -858,17 +864,24 @@ var PDFView = { }); }); + var prefsPromise = prefs.initializedPromise; var storePromise = store.initializedPromise; - PDFJS.Promise.all([firstPagePromise, storePromise]).then(function() { + PDFJS.Promise.all([firstPagePromise, prefsPromise, storePromise]). + then(function() { + var showPreviousViewOnLoad = prefs.get('showPreviousViewOnLoad'); + var defaultZoomValue = prefs.get('defaultZoomValue'); + var storedHash = null; - if (store.get('exists', false)) { + if (showPreviousViewOnLoad && store.get('exists', false)) { var pageNum = store.get('page', '1'); - var zoom = store.get('zoom', PDFView.currentScale); + var zoom = defaultZoomValue || store.get('zoom', PDFView.currentScale); var left = store.get('scrollLeft', '0'); var top = store.get('scrollTop', '0'); storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + left + ',' + top; + } else if (defaultZoomValue) { + storedHash = 'page=1&zoom=' + defaultZoomValue; } // Initialize the browsing history. PDFHistory.initialize(self.documentFingerprint); @@ -920,6 +933,13 @@ var PDFView = { pdfDocument.getOutline().then(function(outline) { self.outline = new DocumentOutlineView(outline); document.getElementById('viewOutline').disabled = !outline; + + if (outline && prefs.get('ifAvailableShowOutlineOnLoad')) { + if (!self.sidebarOpen) { + document.getElementById('sidebarToggle').click(); + } + self.switchSidebarView('outline'); + } }); });