From d44f9f207437384e1ed7004e3843829a5fece0af Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Thu, 22 Dec 2011 22:29:01 +0100 Subject: [PATCH 01/12] Implemented Settings manager. Now remembering scroll positions --- src/core.js | 10 +++++++- src/obj.js | 2 +- web/viewer.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/core.js b/src/core.js index 93cbc72ac..ac140dafe 100644 --- a/src/core.js +++ b/src/core.js @@ -527,6 +527,14 @@ var PDFDocModel = (function PDFDocModelClosure() { this.startXRef, this.mainXRefEntriesOffset); this.catalog = new Catalog(this.xref); + + if(this.xref.trailer && this.xref.trailer.has('ID')) { + var fileID = ''; + this.xref.trailer.get('ID')[0].split('').forEach(function(el) { + fileID += Number(el.charCodeAt(0)).toString(16); + }); + this.fileID = fileID; + } }, get numPages() { var linearization = this.linearization; @@ -560,7 +568,7 @@ var PDFDoc = (function PDFDocClosure() { this.data = data; this.stream = stream; this.pdf = new PDFDocModel(stream); - + this.fileID = this.pdf.fileID; this.catalog = this.pdf.catalog; this.objs = new PDFObjects(); diff --git a/src/obj.js b/src/obj.js index 453014a91..c0e67efbb 100644 --- a/src/obj.js +++ b/src/obj.js @@ -273,7 +273,7 @@ var XRef = (function XRefClosure() { this.entries = []; this.xrefstms = {}; var trailerDict = this.readXRef(startXRef); - + this.trailer = trailerDict; // prepare the XRef cache this.cache = []; diff --git a/web/viewer.js b/web/viewer.js index e2ffcef29..5e8ec773f 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -25,6 +25,61 @@ var Cache = function cacheCache(size) { }; }; +// Settings Manager - This is a utility for saving settings +// First we see if localStorage is available, which isn't pt. in FF due to bug #495747 +// If not, we use FUEL in FF and fallback to Cookies for other browsers. +(function(parent) { +var COOKIE_WORKS = (function() { + document.cookie = 'they=work'; + return document.cookie.length > 0; +})(); + +var LOCALSTORAGE_WORKS = (function() { + try { + if(typeof localStorage != 'undefined') { + return true; + } + } catch(e) { + return false; + } + return true; +})(); + +var extPrefix = 'extensions.uriloader@pdf.js'; + +var Settings = { + set: function(name, val) { + if(location.protocol == 'chrome:' && !LOCALSTORAGE_WORKS) { + Application.prefs.setValue(extPrefix + '.' + name, val); + } else if(LOCALSTORAGE_WORKS) { + localStorage.setItem(name, val); + } else if(COOKIE_WORKS) { + var cookieString = name + '=' + escape(val); + var expire = (new Date((new Date().getTime())+1000*60*60*24*365)).toGMTString(); + cookieString += '; expires='+expire; + document.cookie = cookieString; + } + }, + + get: function(name, defaultValue) { + if(location.protocol == 'chrome:' && !LOCALSTORAGE_WORKS) { + return Application.prefs.getValue(extPrefix + '.' + name, defaultValue); + } else if(LOCALSTORAGE_WORKS) { + return localStorage.getItem(name) || defaultValue; + } else if(COOKIE_WORKS) { + var res = document.cookie.match ( '(^|;) ?' + name + '=([^;]*)(;|$)' ); + if (res) { + return unescape(res[2]); + } else { + return fallback; + } + } + } +}; + +parent.Settings = Settings; +})(this); + var cache = new Cache(kCacheSize); var currentPageNumber = 1; @@ -292,6 +347,15 @@ var PDFView = { pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i; } + var id = pdf.fileID; + if (id) { + var scroll = Settings.get(id + '.scroll', -1); + if (scroll != -1) { + setTimeout(function scrollWindow() { + window.scrollTo(0, scroll); + }, 0); + } + } this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; this.setScale(scale || kDefaultScale, true); @@ -831,6 +895,10 @@ function updateViewarea() { window.addEventListener('scroll', function webViewerScroll(evt) { updateViewarea(); + var fileID; + if((fileID = PDFView.pages[0].content.pdf.fileID)) { + Settings.set(fileID+'.scroll', window.pageYOffset); + } }, true); @@ -888,7 +956,6 @@ window.addEventListener('change', function webViewerChange(evt) { // implemented in Firefox. var file = files[0]; fileReader.readAsBinaryString(file); - document.title = file.name; // URL does not reflect proper document location - hiding some icons. From 0de0e92bc4fa1c09c19fdf4178e589a18ee46051 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Thu, 22 Dec 2011 23:44:42 +0100 Subject: [PATCH 02/12] Added #getFingerprint method to PDFDocModel --- src/core.js | 17 ++++++++++++++++- web/viewer.js | 8 ++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/core.js b/src/core.js index ac140dafe..664ecf33c 100644 --- a/src/core.js +++ b/src/core.js @@ -542,6 +542,21 @@ var PDFDocModel = (function PDFDocModelClosure() { // shadow the prototype getter return shadow(this, 'numPages', num); }, + getFingerprint: function pdfDocGetFingerprint() { + if(this.fileID) { + return this.fileID; + } else { + // If we got no fileID, then we generate one, from the first 100 bytes of PDF + var data = this.stream.bytes.subarray(0, 100); + var hash = calculateMD5(data, 0, data.length); + var strHash = ''; + for(var i = 0, length = hash.length; i < length; i++) { + strHash += Number(hash[i]).toString(16); + } + + return strHash; + } + }, getPage: function pdfDocGetPage(n) { return this.catalog.getPage(n); } @@ -568,7 +583,7 @@ var PDFDoc = (function PDFDocClosure() { this.data = data; this.stream = stream; this.pdf = new PDFDocModel(stream); - this.fileID = this.pdf.fileID; + this.fingerprint = this.pdf.getFingerprint(); this.catalog = this.pdf.catalog; this.objs = new PDFObjects(); diff --git a/web/viewer.js b/web/viewer.js index 5e8ec773f..d4afa8faa 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -347,7 +347,7 @@ var PDFView = { pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i; } - var id = pdf.fileID; + var id = pdf.fingerprint; if (id) { var scroll = Settings.get(id + '.scroll', -1); if (scroll != -1) { @@ -895,9 +895,9 @@ function updateViewarea() { window.addEventListener('scroll', function webViewerScroll(evt) { updateViewarea(); - var fileID; - if((fileID = PDFView.pages[0].content.pdf.fileID)) { - Settings.set(fileID+'.scroll', window.pageYOffset); + var id; + if((id = PDFView.pages[0].content.pdf.fingerprint)) { + Settings.set(id+'.scroll', window.pageYOffset); } }, true); From ac8f0e2c87b66f2ff51bf0b4ef5a1a60814a6c4c Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Fri, 23 Dec 2011 23:36:37 +0100 Subject: [PATCH 03/12] Address yury's comments, and remove unnecessary hash settings --- web/viewer.js | 100 +++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index d4afa8faa..4eeb3a46e 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -28,57 +28,49 @@ var Cache = function cacheCache(size) { // Settings Manager - This is a utility for saving settings // First we see if localStorage is available, which isn't pt. in FF due to bug #495747 // If not, we use FUEL in FF and fallback to Cookies for other browsers. -(function(parent) { -var COOKIE_WORKS = (function() { - document.cookie = 'they=work'; - return document.cookie.length > 0; -})(); +var Settings = (function settingsClosure() { + var isCookiesEnabled = (function() { + document.cookie = 'they=work'; + return document.cookie.length > 0; + })(); -var LOCALSTORAGE_WORKS = (function() { - try { - if(typeof localStorage != 'undefined') { - return true; + var isLocalStorageEnabled = (function localStorageEnabledTest() { + try { + localStorage; + } catch(e) { + return false; } - } catch(e) { - return false; - } - return true; -})(); + return true; + })(); -var extPrefix = 'extensions.uriloader@pdf.js'; + var extPrefix = 'extensions.uriloader@pdf.js'; -var Settings = { - set: function(name, val) { - if(location.protocol == 'chrome:' && !LOCALSTORAGE_WORKS) { - Application.prefs.setValue(extPrefix + '.' + name, val); - } else if(LOCALSTORAGE_WORKS) { - localStorage.setItem(name, val); - } else if(COOKIE_WORKS) { - var cookieString = name + '=' + escape(val); - var expire = (new Date((new Date().getTime())+1000*60*60*24*365)).toGMTString(); - cookieString += '; expires='+expire; - document.cookie = cookieString; - } - }, + return { + set: function settingsSet(name, val) { + if(location.protocol == 'chrome:' && !isLocalStorageEnabled) { + Application.prefs.setValue(extPrefix + '.' + name, val); + } else if(isLocalStorageEnabled) { + localStorage.setItem(name, val); + } else if(isCookiesEnabled) { + var cookieString = name + '=' + escape(val); + var expire = (new Date((new Date().getTime())+1000*60*60*24*365)).toGMTString(); + cookieString += '; expires='+expire; + document.cookie = cookieString; + } + }, - get: function(name, defaultValue) { - if(location.protocol == 'chrome:' && !LOCALSTORAGE_WORKS) { - return Application.prefs.getValue(extPrefix + '.' + name, defaultValue); - } else if(LOCALSTORAGE_WORKS) { - return localStorage.getItem(name) || defaultValue; - } else if(COOKIE_WORKS) { - var res = document.cookie.match ( '(^|;) ?' + name + '=([^;]*)(;|$)' ); - if (res) { - return unescape(res[2]); - } else { - return fallback; + get: function settingsGet(name, defaultValue) { + if(location.protocol == 'chrome:' && !isLocalStorageEnabled) { + return Application.prefs.getValue(extPrefix + '.' + name, defaultValue); + } else if(isLocalStorageEnabled) { + return localStorage.getItem(name) || defaultValue; + } else if(isCookiesEnabled) { + var res = document.cookie.match ( '(^|;) ?' + name + '=([^;]*)(;|$)' ); + return res ? unescape(res[2]) : defaultValue; } } - } -}; - -parent.Settings = Settings; -})(this); + }; +})(); var cache = new Cache(kCacheSize); var currentPageNumber = 1; @@ -347,15 +339,6 @@ var PDFView = { pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i; } - var id = pdf.fingerprint; - if (id) { - var scroll = Settings.get(id + '.scroll', -1); - if (scroll != -1) { - setTimeout(function scrollWindow() { - window.scrollTo(0, scroll); - }, 0); - } - } this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; this.setScale(scale || kDefaultScale, true); @@ -371,8 +354,15 @@ var PDFView = { this.setHash(this.initialBookmark); this.initialBookmark = null; } - else - this.page = 1; + else { + var scroll = Settings.get(pdf.fingerprint + '.scroll', -1); + if (scroll != -1) { + setTimeout(function scrollWindow() { + window.scrollTo(0, scroll); + }, 0); + } else + this.page = 1; + } }, setHash: function pdfViewSetHash(hash) { From c7375745ae4c1332763ff01ccd52c58a75458d35 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Fri, 23 Dec 2011 23:56:01 +0100 Subject: [PATCH 04/12] Too rash. Fixes gjslint errors --- web/viewer.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index 4eeb3a46e..f04023ae8 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -26,7 +26,7 @@ var Cache = function cacheCache(size) { }; // Settings Manager - This is a utility for saving settings -// First we see if localStorage is available, which isn't pt. in FF due to bug #495747 +// First we see if localStorage is available, FF bug #495747 // If not, we use FUEL in FF and fallback to Cookies for other browsers. var Settings = (function settingsClosure() { var isCookiesEnabled = (function() { @@ -37,7 +37,7 @@ var Settings = (function settingsClosure() { var isLocalStorageEnabled = (function localStorageEnabledTest() { try { localStorage; - } catch(e) { + } catch (e) { return false; } return true; @@ -47,25 +47,27 @@ var Settings = (function settingsClosure() { return { set: function settingsSet(name, val) { - if(location.protocol == 'chrome:' && !isLocalStorageEnabled) { - Application.prefs.setValue(extPrefix + '.' + name, val); - } else if(isLocalStorageEnabled) { + if (location.protocol == 'chrome:' && !isLocalStorageEnabled) { + Application.prefs.setValue(extPrefix + '.' + name, val); + } else if (isLocalStorageEnabled) { localStorage.setItem(name, val); - } else if(isCookiesEnabled) { + } else if (isCookiesEnabled) { var cookieString = name + '=' + escape(val); - var expire = (new Date((new Date().getTime())+1000*60*60*24*365)).toGMTString(); - cookieString += '; expires='+expire; - document.cookie = cookieString; - } + var expire = new Date(); + expire.setTime(expire.getTime() + 1000 * 60 * 60 * 24 * 365); + cookieString += '; expires=' + expire.toGMTString(); + document.cookie = cookieString; + } }, get: function settingsGet(name, defaultValue) { - if(location.protocol == 'chrome:' && !isLocalStorageEnabled) { - return Application.prefs.getValue(extPrefix + '.' + name, defaultValue); - } else if(isLocalStorageEnabled) { + if (location.protocol == 'chrome:' && !isLocalStorageEnabled) { + var preferenceName = extPrefix + '.' + name; + return Application.prefs.getValue(preferenceName, defaultValue); + } else if (isLocalStorageEnabled) { return localStorage.getItem(name) || defaultValue; - } else if(isCookiesEnabled) { - var res = document.cookie.match ( '(^|;) ?' + name + '=([^;]*)(;|$)' ); + } else if (isCookiesEnabled) { + var res = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); return res ? unescape(res[2]) : defaultValue; } } @@ -360,7 +362,7 @@ var PDFView = { setTimeout(function scrollWindow() { window.scrollTo(0, scroll); }, 0); - } else + } else this.page = 1; } }, @@ -885,10 +887,8 @@ function updateViewarea() { window.addEventListener('scroll', function webViewerScroll(evt) { updateViewarea(); - var id; - if((id = PDFView.pages[0].content.pdf.fingerprint)) { - Settings.set(id+'.scroll', window.pageYOffset); - } + var fingerprint = PDFView.pages[0].content.pdf.fingerprint; + Settings.set(fingerprint + '.scroll', window.pageYOffset); }, true); From 4ea5b9f771fdb7e3d707f62f9dde0b8b23edda95 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Dec 2011 00:42:46 +0100 Subject: [PATCH 05/12] Remember hash position correctly --- web/viewer.js | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index f04023ae8..a44acb688 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -321,8 +321,21 @@ var PDFView = { this.error('An error occurred while reading the PDF.', e); } var pagesCount = pdf.numPages; + var id = pdf.fingerprint; + var storedHash = null; document.getElementById('numPages').innerHTML = pagesCount; document.getElementById('pageNumber').max = pagesCount; + PDFView.documentFingerprint = id; + + if (Settings.get(id + '.exists', false)) { + var page = Settings.get(id + '.page', '1'); + var zoom = Settings.get(id + '.zoom', PDFView.currentScale); + var left = Settings.get(id + '.scrollLeft', '0'); + var top = Settings.get(id + '.scrollTop', '0'); + + storedHash = 'page=' + page + '&zoom=' + Math.round(zoom * 100); + storedHash += ',' + left + ',' + top; + } var pages = this.pages = []; var pagesRefMap = {}; @@ -356,14 +369,8 @@ var PDFView = { this.setHash(this.initialBookmark); this.initialBookmark = null; } - else { - var scroll = Settings.get(pdf.fingerprint + '.scroll', -1); - if (scroll != -1) { - setTimeout(function scrollWindow() { - window.scrollTo(0, scroll); - }, 0); - } else - this.page = 1; + else if (storedHash) { + this.setHash(storedHash); } }, @@ -390,7 +397,7 @@ var PDFView = { if ('zoom' in params) { var zoomArgs = params.zoom.split(','); // scale,left,top // building destination array - var dest = [null, new Name('XYZ'), (zoomArgs[1] | 0), + var dest = [null, {name: 'XYZ'}, (zoomArgs[1] | 0), (zoomArgs[2] | 0), (zoomArgs[0] | 0) / 100]; var currentPage = this.pages[pageNumber - 1]; currentPage.scrollIntoView(dest); @@ -882,13 +889,19 @@ function updateViewarea() { var topLeft = currentPage.getPagePoint(window.pageXOffset, window.pageYOffset - firstPage.y - kViewerTopMargin); pdfOpenParams += ',' + Math.round(topLeft.x) + ',' + Math.round(topLeft.y); + + var id = PDFView.documentFingerprint; + Settings.set(id + '.exists', true); + Settings.set(id + '.page', pageNumber); + Settings.set(id + '.zoom', PDFView.currentScale); + Settings.set(id + '.scrollLeft', Math.round(topLeft.x)); + Settings.set(id + '.scrollTop', Math.round(topLeft.y)); + document.getElementById('viewBookmark').href = pdfOpenParams; } window.addEventListener('scroll', function webViewerScroll(evt) { updateViewarea(); - var fingerprint = PDFView.pages[0].content.pdf.fingerprint; - Settings.set(fingerprint + '.scroll', window.pageYOffset); }, true); From 4c064eb94a3c915c4d9164194d04aaadd4439cfc Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Dec 2011 00:48:10 +0100 Subject: [PATCH 06/12] Missed function name... --- web/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/viewer.js b/web/viewer.js index a44acb688..d00d50505 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -29,7 +29,7 @@ var Cache = function cacheCache(size) { // First we see if localStorage is available, FF bug #495747 // If not, we use FUEL in FF and fallback to Cookies for other browsers. var Settings = (function settingsClosure() { - var isCookiesEnabled = (function() { + var isCookiesEnabled = (function cookiesEnabledTest() { document.cookie = 'they=work'; return document.cookie.length > 0; })(); From e147485262e5f8f947279d169c3cb2aee9f84d55 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Dec 2011 15:07:24 +0100 Subject: [PATCH 07/12] Refactoring Settings manager, now with limit on memory usage --- src/core.js | 10 ++--- web/viewer.js | 105 +++++++++++++++++++++++++++++--------------------- 2 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/core.js b/src/core.js index 664ecf33c..50abf6a04 100644 --- a/src/core.js +++ b/src/core.js @@ -527,8 +527,7 @@ var PDFDocModel = (function PDFDocModelClosure() { this.startXRef, this.mainXRefEntriesOffset); this.catalog = new Catalog(this.xref); - - if(this.xref.trailer && this.xref.trailer.has('ID')) { + if (this.xref.trailer && this.xref.trailer.has('ID')) { var fileID = ''; this.xref.trailer.get('ID')[0].split('').forEach(function(el) { fileID += Number(el.charCodeAt(0)).toString(16); @@ -543,14 +542,15 @@ var PDFDocModel = (function PDFDocModelClosure() { return shadow(this, 'numPages', num); }, getFingerprint: function pdfDocGetFingerprint() { - if(this.fileID) { + if (this.fileID) { return this.fileID; } else { - // If we got no fileID, then we generate one, from the first 100 bytes of PDF + // If we got no fileID, then we generate one, + // from the first 100 bytes of PDF var data = this.stream.bytes.subarray(0, 100); var hash = calculateMD5(data, 0, data.length); var strHash = ''; - for(var i = 0, length = hash.length; i < length; i++) { + for (var i = 0, length = hash.length; i < length; i++) { strHash += Number(hash[i]).toString(16); } diff --git a/web/viewer.js b/web/viewer.js index d00d50505..36b1299ef 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -28,12 +28,7 @@ var Cache = function cacheCache(size) { // Settings Manager - This is a utility for saving settings // First we see if localStorage is available, FF bug #495747 // If not, we use FUEL in FF and fallback to Cookies for other browsers. -var Settings = (function settingsClosure() { - var isCookiesEnabled = (function cookiesEnabledTest() { - document.cookie = 'they=work'; - return document.cookie.length > 0; - })(); - +var Settings = (function SettingsClosure() { var isLocalStorageEnabled = (function localStorageEnabledTest() { try { localStorage; @@ -42,36 +37,60 @@ var Settings = (function settingsClosure() { } return true; })(); - var extPrefix = 'extensions.uriloader@pdf.js'; + var isExtension = location.protocol == 'chrome:' && !isLocalStorageEnabled; - return { - set: function settingsSet(name, val) { - if (location.protocol == 'chrome:' && !isLocalStorageEnabled) { - Application.prefs.setValue(extPrefix + '.' + name, val); - } else if (isLocalStorageEnabled) { - localStorage.setItem(name, val); - } else if (isCookiesEnabled) { - var cookieString = name + '=' + escape(val); - var expire = new Date(); - expire.setTime(expire.getTime() + 1000 * 60 * 60 * 24 * 365); - cookieString += '; expires=' + expire.toGMTString(); - document.cookie = cookieString; + function Settings(fingerprint) { + var database = null; + var index; + if (isExtension) + database = Application.prefs.getValue(extPrefix + '.database', '{}'); + else if (isLocalStorageEnabled) + database = localStorage.getItem('database') || '{}'; + else + return false; + + database = JSON.parse(database); + if (!('files' in database)) + database.files = []; + if (database.files.length >= 20) + database.files.shift(); + for (var i = 0, length = database.files.length; i < length; i++) { + var branch = database.files[i]; + if (branch.fingerprint == fingerprint) { + index = i; + break; } + } + if (typeof index != 'number') + index = database.files.push({fingerprint: fingerprint}) - 1; + this.file = database.files[index]; + this.database = database; + if (isExtension) + Application.prefs.setValue(extPrefix + '.database', + JSON.stringify(database)); + else if (isLocalStorageEnabled) + localStorage.setItem('database', JSON.stringify(database)); + } + + Settings.prototype = { + set: function settingsSet(name, val) { + var file = this.file; + file[name] = val; + if (isExtension) { + Application.prefs.setValue(extPrefix + '.database', + JSON.stringify(this.database)); + } + else if (isLocalStorageEnabled) + localStorage.setItem('database', JSON.stringify(this.database)); }, get: function settingsGet(name, defaultValue) { - if (location.protocol == 'chrome:' && !isLocalStorageEnabled) { - var preferenceName = extPrefix + '.' + name; - return Application.prefs.getValue(preferenceName, defaultValue); - } else if (isLocalStorageEnabled) { - return localStorage.getItem(name) || defaultValue; - } else if (isCookiesEnabled) { - var res = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); - return res ? unescape(res[2]) : defaultValue; - } + return this.file[name] || defaultValue; } }; + + return Settings; })(); var cache = new Cache(kCacheSize); @@ -326,15 +345,14 @@ var PDFView = { document.getElementById('numPages').innerHTML = pagesCount; document.getElementById('pageNumber').max = pagesCount; PDFView.documentFingerprint = id; + var store = PDFView.store = new Settings(id); + if (store.get('exists', false)) { + var page = store.get('page', '1'); + var zoom = store.get('zoom', PDFView.currentScale); + var left = store.get('scrollLeft', '0'); + var top = store.get('scrollTop', '0'); - if (Settings.get(id + '.exists', false)) { - var page = Settings.get(id + '.page', '1'); - var zoom = Settings.get(id + '.zoom', PDFView.currentScale); - var left = Settings.get(id + '.scrollLeft', '0'); - var top = Settings.get(id + '.scrollTop', '0'); - - storedHash = 'page=' + page + '&zoom=' + Math.round(zoom * 100); - storedHash += ',' + left + ',' + top; + storedHash = 'page=' + page + '&zoom=' + zoom + ',' + left + ',' + top; } var pages = this.pages = []; @@ -371,7 +389,8 @@ var PDFView = { } else if (storedHash) { this.setHash(storedHash); - } + } else + window.scrollTo(0, 0); // Scroll to top is default. }, setHash: function pdfViewSetHash(hash) { @@ -890,12 +909,12 @@ function updateViewarea() { window.pageYOffset - firstPage.y - kViewerTopMargin); pdfOpenParams += ',' + Math.round(topLeft.x) + ',' + Math.round(topLeft.y); - var id = PDFView.documentFingerprint; - Settings.set(id + '.exists', true); - Settings.set(id + '.page', pageNumber); - Settings.set(id + '.zoom', PDFView.currentScale); - Settings.set(id + '.scrollLeft', Math.round(topLeft.x)); - Settings.set(id + '.scrollTop', Math.round(topLeft.y)); + var store = PDFView.store; + store.set('exists', true); + store.set('page', pageNumber); + store.set('zoom', Math.round(PDFView.currentScale * 100)); + store.set('scrollLeft', Math.round(topLeft.x)); + store.set('scrollTop', Math.round(topLeft.y)); document.getElementById('viewBookmark').href = pdfOpenParams; } From 83cb12be7fbadd222c0bd17fd5ac9d589b2eb94b Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Dec 2011 16:07:56 +0100 Subject: [PATCH 08/12] Set page number instead of window.scrollTo, and remove Cookie reference --- web/viewer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index 36b1299ef..ebe93ead6 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -27,7 +27,7 @@ var Cache = function cacheCache(size) { // Settings Manager - This is a utility for saving settings // First we see if localStorage is available, FF bug #495747 -// If not, we use FUEL in FF and fallback to Cookies for other browsers. +// If not, we use FUEL in FF var Settings = (function SettingsClosure() { var isLocalStorageEnabled = (function localStorageEnabledTest() { try { @@ -390,7 +390,7 @@ var PDFView = { else if (storedHash) { this.setHash(storedHash); } else - window.scrollTo(0, 0); // Scroll to top is default. + this.page = 1; }, setHash: function pdfViewSetHash(hash) { From 4358ebc18b51664453a70dba7c763c6ad8b0831c Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Dec 2011 16:14:06 +0100 Subject: [PATCH 09/12] Too rash yet again. Bracket and style nits --- web/viewer.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index ebe93ead6..d0a4db76b 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -12,6 +12,7 @@ var kScrollbarPadding = 40; var kMinScale = 0.25; var kMaxScale = 4.0; var kImageDirectory = './images/'; +var kSettingsMemory = 20; var Cache = function cacheCache(size) { var data = []; @@ -53,7 +54,7 @@ var Settings = (function SettingsClosure() { database = JSON.parse(database); if (!('files' in database)) database.files = []; - if (database.files.length >= 20) + if (database.files.length >= kSettingsMemory) database.files.shift(); for (var i = 0, length = database.files.length; i < length; i++) { var branch = database.files[i]; @@ -77,10 +78,9 @@ var Settings = (function SettingsClosure() { set: function settingsSet(name, val) { var file = this.file; file[name] = val; - if (isExtension) { + if (isExtension) Application.prefs.setValue(extPrefix + '.database', JSON.stringify(this.database)); - } else if (isLocalStorageEnabled) localStorage.setItem('database', JSON.stringify(this.database)); }, @@ -387,9 +387,9 @@ var PDFView = { this.setHash(this.initialBookmark); this.initialBookmark = null; } - else if (storedHash) { + else if (storedHash) this.setHash(storedHash); - } else + else this.page = 1; }, From ae7f2e9fcc961bb157bef40c2abb1f699c5d8927 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Dec 2011 21:14:10 +0100 Subject: [PATCH 10/12] Respect private browsing in extension --- web/viewer.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index d0a4db76b..51dbbc31a 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -40,11 +40,19 @@ var Settings = (function SettingsClosure() { })(); var extPrefix = 'extensions.uriloader@pdf.js'; var isExtension = location.protocol == 'chrome:' && !isLocalStorageEnabled; + var inPrivateBrowsing = false; + if (isExtension) { + var pbs = Components.classes['@mozilla.org/privatebrowsing;1'] + .getService(Components.interfaces.nsIPrivateBrowsingService); + inPrivateBrowsing = pbs.privateBrowsingEnabled; + } function Settings(fingerprint) { var database = null; var index; - if (isExtension) + if (inPrivateBrowsing) + return false; + else if (isExtension) database = Application.prefs.getValue(extPrefix + '.database', '{}'); else if (isLocalStorageEnabled) database = localStorage.getItem('database') || '{}'; @@ -76,6 +84,8 @@ var Settings = (function SettingsClosure() { Settings.prototype = { set: function settingsSet(name, val) { + if (inPrivateBrowsing) + return false; var file = this.file; file[name] = val; if (isExtension) @@ -86,7 +96,10 @@ var Settings = (function SettingsClosure() { }, get: function settingsGet(name, defaultValue) { - return this.file[name] || defaultValue; + if (inPrivateBrowsing) + return defaultValue; + else + return this.file[name] || defaultValue; } }; From c25f8377663e87cae066ea0fbf5eb14f425559d4 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Wed, 28 Dec 2011 19:18:55 -0600 Subject: [PATCH 11/12] Fixes concurrent pages loading (#974 and #626) --- web/viewer.js | 68 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index 51dbbc31a..9da0b498d 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -26,6 +26,39 @@ var Cache = function cacheCache(size) { }; }; +var RenderingQueue = (function RenderingQueueClosure() { + function RenderingQueue() { + this.busy = false; + this.items = []; + } + + RenderingQueue.prototype = { + enqueueDraw: function RenderingQueueEnqueueDraw(item) { + if ('rendering' in item) + return; // is already in the queue + + item.rendering = true; + this.items.push(item); + if (this.items.length > 1) + return; // not first item + + item.draw(this.continueExecution.bind(this)); + }, + continueExecution: function RenderingQueueContinueExecution() { + var item = this.items.shift(); + delete item.rendering; + + if (this.items.length == 0) + return; // queue is empty + + item = this.items[0]; + item.draw(this.continueExecution.bind(this)); + } + }; + + return RenderingQueue; +})(); + // Settings Manager - This is a utility for saving settings // First we see if localStorage is available, FF bug #495747 // If not, we use FUEL in FF @@ -107,12 +140,13 @@ var Settings = (function SettingsClosure() { })(); var cache = new Cache(kCacheSize); +var renderingQueue = new RenderingQueue(); var currentPageNumber = 1; var PDFView = { pages: [], thumbnails: [], - currentScale: kDefaultScale, + currentScale: 0, initialBookmark: document.location.hash.substring(1), setScale: function pdfViewSetScale(val, resetAutoSettings) { @@ -387,7 +421,6 @@ var PDFView = { this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; - this.setScale(scale || kDefaultScale, true); if (pdf.catalog.documentOutline) { this.outline = new DocumentOutlineView(pdf.catalog.documentOutline); @@ -401,9 +434,11 @@ var PDFView = { this.initialBookmark = null; } else if (storedHash) - this.setHash(storedHash); - else + this.setHash(storedHash); + else { + this.setScale(scale || kDefaultScale, true); this.page = 1; + } }, setHash: function pdfViewSetHash(hash) { @@ -704,10 +739,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, }, 0); }; - this.draw = function pageviewDraw() { + this.draw = function pageviewDraw(callback) { if (div.hasChildNodes()) { this.updateStats(); - return false; + callback(); + return; } var canvas = document.createElement('canvas'); @@ -739,13 +775,14 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, this.updateStats(); if (this.onAfterDraw) this.onAfterDraw(); + + cache.push(this); + callback(); }).bind(this), textLayer ); setupAnnotations(this.content, this.scale); div.setAttribute('data-loaded', true); - - return true; }; this.updateStats = function pageViewUpdateStats() { @@ -812,12 +849,16 @@ var ThumbnailView = function thumbnailView(container, page, id, pageRatio) { return ctx; } - this.draw = function thumbnailViewDraw() { - if (this.hasImage) + this.draw = function thumbnailViewDraw(callback) { + if (this.hasImage) { + callback(); return; + } var ctx = getPageDrawContext(); - page.startRendering(ctx, function thumbnailViewDrawStartRendering() {}); + page.startRendering(ctx, function thumbnailViewDrawStartRendering() { + callback(); + }); this.hasImage = true; }; @@ -900,8 +941,7 @@ function updateViewarea() { var visiblePages = PDFView.getVisiblePages(); for (var i = 0; i < visiblePages.length; i++) { var page = visiblePages[i]; - if (PDFView.pages[page.id - 1].draw()) - cache.push(page.view); + renderingQueue.enqueueDraw(PDFView.pages[page.id - 1]); } if (!visiblePages.length) @@ -951,7 +991,7 @@ function updateThumbViewArea() { var visibleThumbs = PDFView.getVisibleThumbs(); for (var i = 0; i < visibleThumbs.length; i++) { var thumb = visibleThumbs[i]; - PDFView.thumbnails[thumb.id - 1].draw(); + renderingQueue.enqueueDraw(PDFView.thumbnails[thumb.id - 1]); } }, delay); } From 1074c75f32be8932bb0974a044be2717830d3954 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Thu, 29 Dec 2011 18:01:47 -0600 Subject: [PATCH 12/12] remove unused field --- web/viewer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/web/viewer.js b/web/viewer.js index 9da0b498d..bb7b0ed01 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -28,7 +28,6 @@ var Cache = function cacheCache(size) { var RenderingQueue = (function RenderingQueueClosure() { function RenderingQueue() { - this.busy = false; this.items = []; }