From 0f0650f426ac12d931109d3c0fd4b249ddb732c0 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 13 Feb 2019 14:00:23 +0100 Subject: [PATCH] Generate the `default_preferences.json` file from `AppOptions` Currently any editing of the preferences require updates in *three* separate files, which isn't a great developer experience to say the least. This has annoyed me sufficiently to write this patch, which moves the definition of all preferences into `AppOptions` and adds a new `gulp` task to generate the `default_preferences.json` file for the builds where it's needed. --- .../content/PdfJsDefaultPreferences.jsm | 2 +- gulpfile.js | 95 +++++++++++++++++-- web/app.js | 6 +- web/app_options.js | 62 ++++++------ web/default_preferences.json | 23 ----- web/preferences.js | 27 +++--- 6 files changed, 141 insertions(+), 74 deletions(-) delete mode 100644 web/default_preferences.json diff --git a/extensions/firefox/content/PdfJsDefaultPreferences.jsm b/extensions/firefox/content/PdfJsDefaultPreferences.jsm index fb640c744..41aadb980 100644 --- a/extensions/firefox/content/PdfJsDefaultPreferences.jsm +++ b/extensions/firefox/content/PdfJsDefaultPreferences.jsm @@ -18,4 +18,4 @@ var EXPORTED_SYMBOLS = ["PdfJsDefaultPreferences"]; var PdfJsDefaultPreferences = - Object.freeze(PDFJSDev.json("$ROOT/web/default_preferences.json")); + Object.freeze(PDFJSDev.json("$ROOT/build/default_preferences.json")); diff --git a/gulpfile.js b/gulpfile.js index d9060f8c2..fe03105b6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -51,6 +51,7 @@ var MOZCENTRAL_BASELINE_DIR = BUILD_DIR + 'mozcentral.baseline/'; var GENERIC_DIR = BUILD_DIR + 'generic/'; var COMPONENTS_DIR = BUILD_DIR + 'components/'; var IMAGE_DECODERS_DIR = BUILD_DIR + 'image_decoders'; +var DEFAULT_PREFERENCES_DIR = BUILD_DIR + 'default_preferences/'; var MINIFIED_DIR = BUILD_DIR + 'minified/'; var JSDOC_BUILD_DIR = BUILD_DIR + 'jsdoc/'; var GH_PAGES_DIR = BUILD_DIR + 'gh-pages/'; @@ -484,6 +485,80 @@ gulp.task('buildnumber', function (done) { }); }); +gulp.task('default_preferences-pre', function() { + console.log(); + console.log('### Building `default_preferences.json`'); + + // Refer to the comment in the 'lib' task below. + function babelPluginReplaceNonWebPackRequire(babel) { + return { + visitor: { + Identifier(path, state) { + if (path.node.name === '__non_webpack_require__') { + path.replaceWith(babel.types.identifier('require')); + } + }, + }, + }; + } + function preprocess(content) { + content = preprocessor2.preprocessPDFJSCode(ctx, content); + return babel.transform(content, { + sourceType: 'module', + presets: undefined, // SKIP_BABEL + plugins: [ + '@babel/plugin-transform-modules-commonjs', + babelPluginReplaceNonWebPackRequire, + ], + }).code; + } + var babel = require('@babel/core'); + var ctx = { + rootPath: __dirname, + saveComments: false, + defines: builder.merge(DEFINES, { + GENERIC: true, + LIB: true, + BUNDLE_VERSION: 0, // Dummy version + BUNDLE_BUILD: 0, // Dummy build + }), + map: { + 'pdfjs-lib': '../pdf', + }, + }; + var preprocessor2 = require('./external/builder/preprocessor2.js'); + var buildLib = merge([ + gulp.src([ + 'src/{display,shared}/*.js', + '!src/shared/{cffStandardStrings,fonts_utils}.js', + 'src/pdf.js', + ], { base: 'src/', }), + gulp.src([ + 'web/*.js', + '!web/{pdfjs,preferences,viewer}.js', + ], { base: '.', }), + ]).pipe(transform('utf8', preprocess)) + .pipe(gulp.dest(DEFAULT_PREFERENCES_DIR + 'lib/')); + return merge([ + buildLib, + gulp.src('external/{streams,url}/*.js', { base: '.', }) + .pipe(gulp.dest(DEFAULT_PREFERENCES_DIR)), + ]); +}); + +gulp.task('default_preferences', gulp.series('default_preferences-pre', + function(done) { + var AppOptionsLib = + require('./' + DEFAULT_PREFERENCES_DIR + 'lib/web/app_options.js'); + var AppOptions = AppOptionsLib.AppOptions; + var OptionKind = AppOptionsLib.OptionKind; + + createStringSource('default_preferences.json', JSON.stringify( + AppOptions.getAll(OptionKind.PREFERENCE), null, 2)) + .pipe(gulp.dest(BUILD_DIR)) + .on('end', done); +})); + gulp.task('locale', function () { var VIEWER_LOCALE_OUTPUT = 'web/locale/'; var METADATA_OUTPUT = 'extensions/firefox/'; @@ -608,7 +683,8 @@ function preprocessHTML(source, defines) { // Builds the generic production viewer that should be compatible with most // modern HTML5 browsers. -gulp.task('generic', gulp.series('buildnumber', 'locale', function () { +gulp.task('generic', gulp.series('buildnumber', 'default_preferences', 'locale', + function() { console.log(); console.log('### Creating generic viewer'); var defines = builder.merge(DEFINES, { GENERIC: true, }); @@ -671,7 +747,8 @@ gulp.task('image_decoders', gulp.series('buildnumber', function() { return createImageDecodersBundle(defines).pipe(gulp.dest(IMAGE_DECODERS_DIR)); })); -gulp.task('minified-pre', gulp.series('buildnumber', 'locale', function () { +gulp.task('minified-pre', gulp.series('buildnumber', 'default_preferences', + 'locale', function() { console.log(); console.log('### Creating minified viewer'); var defines = builder.merge(DEFINES, { MINIFIED: true, GENERIC: true, }); @@ -766,7 +843,8 @@ function preprocessDefaultPreferences(content) { content + '\n'); } -gulp.task('mozcentral-pre', gulp.series('buildnumber', 'locale', function () { +gulp.task('mozcentral-pre', gulp.series('buildnumber', 'default_preferences', + 'locale', function() { console.log(); console.log('### Building mozilla-central extension'); var defines = builder.merge(DEFINES, { MOZCENTRAL: true, SKIP_BABEL: true, }); @@ -816,7 +894,8 @@ gulp.task('mozcentral-pre', gulp.series('buildnumber', 'locale', function () { gulp.task('mozcentral', gulp.series('mozcentral-pre')); -gulp.task('chromium-pre', gulp.series('buildnumber', 'locale', function () { +gulp.task('chromium-pre', gulp.series('buildnumber', 'default_preferences', + 'locale', function() { console.log(); console.log('### Building Chromium extension'); var defines = builder.merge(DEFINES, { CHROME: true, }); @@ -883,7 +962,7 @@ gulp.task('jsdoc', function (done) { }); }); -gulp.task('lib', gulp.series('buildnumber', function () { +gulp.task('lib', gulp.series('buildnumber', 'default_preferences', function() { // When we create a bundle, webpack is run on the source and it will replace // require with __webpack_require__. When we want to use the real require, // __non_webpack_require__ has to be used. @@ -1077,7 +1156,7 @@ gulp.task('unittestcli', gulp.series('testing-pre', 'lib', function(done) { }); })); -gulp.task('lint', function (done) { +gulp.task('lint', gulp.series('default_preferences', function(done) { console.log(); console.log('### Linting JS files'); @@ -1096,7 +1175,7 @@ gulp.task('lint', function (done) { if (!checkChromePreferencesFile( 'extensions/chromium/preferences_schema.json', - 'web/default_preferences.json')) { + 'build/default_preferences.json')) { done(new Error('chromium/preferences_schema is not in sync.')); return; } @@ -1104,7 +1183,7 @@ gulp.task('lint', function (done) { console.log('files checked, no errors found'); done(); }); -}); +})); gulp.task('server', function () { console.log(); diff --git a/web/app.js b/web/app.js index 5c87ee0d2..21cc50d10 100644 --- a/web/app.js +++ b/web/app.js @@ -21,6 +21,7 @@ import { parseQueryString, PresentationModeState, ProgressBar, RendererType, ScrollMode, SpreadMode, TextLayerMode } from './ui_utils'; +import { AppOptions, OptionKind } from './app_options'; import { build, createObjectURL, getDocument, getFilenameFromUrl, GlobalWorkerOptions, InvalidPDFException, LinkTarget, loadScript, MissingPDFException, OPS, @@ -30,7 +31,6 @@ import { import { CursorTool, PDFCursorTools } from './pdf_cursor_tools'; import { PDFRenderingQueue, RenderingStates } from './pdf_rendering_queue'; import { PDFSidebar, SidebarView } from './pdf_sidebar'; -import { AppOptions } from './app_options'; import { OverlayManager } from './overlay_manager'; import { PasswordPrompt } from './password_prompt'; import { PDFAttachmentViewer } from './pdf_attachment_viewer'; @@ -611,7 +611,7 @@ let PDFViewerApplication = { await this.close(); } // Set the necessary global worker parameters, using the available options. - const workerParameters = AppOptions.getAll('worker'); + const workerParameters = AppOptions.getAll(OptionKind.WORKER); for (let key in workerParameters) { GlobalWorkerOptions[key] = workerParameters[key]; } @@ -633,7 +633,7 @@ let PDFViewerApplication = { parameters.docBaseUrl = this.baseUrl; } // Set the necessary API parameters, using the available options. - const apiParameters = AppOptions.getAll('api'); + const apiParameters = AppOptions.getAll(OptionKind.API); for (let key in apiParameters) { parameters[key] = apiParameters[key]; } diff --git a/web/app_options.js b/web/app_options.js index 12686d38b..ef5216ffe 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -17,21 +17,21 @@ import { apiCompatibilityParams } from 'pdfjs-lib'; import { viewerCompatibilityParams } from './viewer_compatibility'; const OptionKind = { - VIEWER: 'viewer', - API: 'api', - WORKER: 'worker', + VIEWER: 0x02, + API: 0x04, + WORKER: 0x08, + PREFERENCE: 0x80, }; /** * PLEASE NOTE: To avoid introducing unnecessary dependencies, we specify the - * values below *explicitly* rather than relying on imported types; - * compare with the format of `default_preferences.json`. + * values below *explicitly* rather than relying on imported types. */ const defaultOptions = { cursorToolOnLoad: { /** @type {number} */ value: 0, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, defaultUrl: { /** @type {string} */ @@ -41,7 +41,7 @@ const defaultOptions = { defaultZoomValue: { /** @type {string} */ value: '', - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, disableHistory: { /** @type {boolean} */ @@ -51,7 +51,7 @@ const defaultOptions = { disablePageLabels: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, /** * The `disablePreferences` is, conditionally, defined below. @@ -59,17 +59,17 @@ const defaultOptions = { enablePrintAutoRotate: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, enableWebGL: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, eventBusDispatchToDOM: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, externalLinkRel: { /** @type {string} */ @@ -79,12 +79,12 @@ const defaultOptions = { externalLinkTarget: { /** @type {number} */ value: 0, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, historyUpdateUrl: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, imageResourcesPath: { /** @type {string} */ @@ -103,47 +103,47 @@ const defaultOptions = { pdfBugEnabled: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, renderer: { /** @type {string} */ value: 'canvas', - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, renderInteractiveForms: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, sidebarViewOnLoad: { /** @type {number} */ value: -1, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, scrollModeOnLoad: { /** @type {number} */ value: -1, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, spreadModeOnLoad: { /** @type {number} */ value: -1, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, textLayerMode: { /** @type {number} */ value: 1, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, useOnlyCssZoom: { /** @type {boolean} */ value: false, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, viewOnLoad: { /** @type {boolean} */ value: 0, - kind: OptionKind.VIEWER, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE, }, cMapPacked: { @@ -160,7 +160,7 @@ const defaultOptions = { disableAutoFetch: { /** @type {boolean} */ value: false, - kind: OptionKind.API, + kind: OptionKind.API + OptionKind.PREFERENCE, }, disableCreateObjectURL: { /** @type {boolean} */ @@ -171,17 +171,17 @@ const defaultOptions = { disableFontFace: { /** @type {boolean} */ value: false, - kind: OptionKind.API, + kind: OptionKind.API + OptionKind.PREFERENCE, }, disableRange: { /** @type {boolean} */ value: false, - kind: OptionKind.API, + kind: OptionKind.API + OptionKind.PREFERENCE, }, disableStream: { /** @type {boolean} */ value: false, - kind: OptionKind.API, + kind: OptionKind.API + OptionKind.PREFERENCE, }, isEvalSupported: { /** @type {boolean} */ @@ -258,8 +258,14 @@ class AppOptions { const options = Object.create(null); for (const name in defaultOptions) { const defaultOption = defaultOptions[name]; - if (kind && kind !== defaultOption.kind) { - continue; + if (kind) { + if ((kind & defaultOption.kind) === 0) { + continue; + } + if ((kind & OptionKind.PREFERENCE) !== 0) { + options[name] = defaultOption.value; + continue; + } } const userOption = userOptions[name]; options[name] = (userOption !== undefined ? userOption : diff --git a/web/default_preferences.json b/web/default_preferences.json deleted file mode 100644 index 22a115b44..000000000 --- a/web/default_preferences.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "viewOnLoad": 0, - "defaultZoomValue": "", - "sidebarViewOnLoad": -1, - "cursorToolOnLoad": 0, - "enableWebGL": false, - "eventBusDispatchToDOM": false, - "pdfBugEnabled": false, - "disableRange": false, - "disableStream": false, - "disableAutoFetch": false, - "disableFontFace": false, - "textLayerMode": 1, - "useOnlyCssZoom": false, - "externalLinkTarget": 0, - "renderer": "canvas", - "renderInteractiveForms": false, - "enablePrintAutoRotate": false, - "disablePageLabels": false, - "historyUpdateUrl": false, - "scrollModeOnLoad": -1, - "spreadModeOnLoad": -1 -} diff --git a/web/preferences.js b/web/preferences.js index 7cc9f3a15..d2fd8bd2b 100644 --- a/web/preferences.js +++ b/web/preferences.js @@ -18,20 +18,25 @@ function getDefaultPreferences() { if (!defaultPreferences) { if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('PRODUCTION')) { defaultPreferences = Promise.resolve( - PDFJSDev.json('$ROOT/web/default_preferences.json')); + PDFJSDev.json('$ROOT/build/default_preferences.json')); } else { - defaultPreferences = new Promise(function (resolve) { - let xhr = new XMLHttpRequest(); - xhr.open('GET', 'default_preferences.json'); - xhr.onload = xhr.onerror = function loaded() { + defaultPreferences = new Promise(function(resolve, reject) { + if (typeof SystemJS === 'object') { + SystemJS.import('./app_options').then(resolve, reject); + } else if (typeof require === 'function') { try { - resolve(JSON.parse(xhr.responseText)); - } catch (e) { - console.error(`Unable to load default preferences: ${e}`); - resolve({}); + resolve(require('./app_options.js')); + } catch (ex) { + reject(ex); } - }; - xhr.send(); + } else { + reject(new Error( + 'SystemJS or CommonJS must be used to load AppOptions.')); + } + }).then(function({ AppOptions, OptionKind, }) { + return AppOptions.getAll(OptionKind.PREFERENCE); + }, function(reason) { + console.error(reason); }); } }