GermanCentralLibraryForTheBlind / readium-js-viewer

ReadiumJS viewer: default web app for Readium.js library
http://readium.org/projects/readiumjs
BSD 3-Clause "New" or "Revised" License
4 stars 0 forks source link

readium-js-viewer

EPUB reader written in HTML, CSS and Javascript.

This Readium software component implements the Readium Chrome extension / app for offline reading ( https://chrome.google.com/webstore/detail/readium/fepbnnnkkadjhjahcafoaglimekefifl ), and the "cloud reader" for online e-books ( http://development.readium.divshot.io or http://readium.divshot.io for stable versions).

Please see https://github.com/readium/readium-shared-js for more information about the underlying rendering engine.

License

BSD-3-Clause ( http://opensource.org/licenses/BSD-3-Clause )

See license.txt.

Prerequisites

Development

Git initialisation

Advanced usage (e.g. TravisCI) - the commands below automate the remote/origin tracking process (this requires a Bash-like shell):

(repeat for each repository / submodule)

Source tree preparation

Note that in some cases, administrator rights may be needed in order to install dependencies, because of NPM-related file access permissions (the console log would clearly show the error). Should this be the case, running sudo npm run prepare usually solves this.

Note that the above command executes the following:

Typical workflow

No RequireJS optimization:

Or to use optimized Javascript bundles (single or multiple):

And finally to update the distribution packages (automatically calls the build task above, so npm run build is redundant):

The above task takes a lot of time (as it builds distributable packages for all ReadiumJS flavours), and is in fact not strictly necessary to test the cloud reader (see npm run http above, using the "no optimise" RequireJS option). Thankfully, the packaged code for the Chrome App / Extension can be quickly generated using this build command instead:

Remember to activate "developer mode" in the Chrome web browser, so that the Readium packaged app / extension can be added directly from the dist/chrome-app folder. Subsequently (after each build), the app can simply be reloaded.

Also note that the built-in local HTTP server functionality (npm run http) is primarily designed to serve the Readium application at development time in its "exploded" form (dev, src, node_modules, etc. folders). However, it is also possible to use any arbitrary HTTP server as long as the root folder is readium-js-viewer (so that the application assets ; CSS, images, fonts ; can be loaded relative to this base URL). Example with the built-in NodeJS server: node node_modules/http-server/bin/http-server -a 127.0.0.1 -p 8080 -c-1 .

Remark: a log of HTTP requests is preserved in http_app-ebooks.log. This file contains ANSI color escape codes, so although it can be read using a regular text editor, it can be rendered in its original format using the shell command: cat http_app.log (on OSX / Linux), or sed "s,x,x,g" http_app-ebooks.log (on Windows).

HTTP CORS (separate domains / origins, app vs. ebooks)

By default, a single HTTP server is launched when using the npm run http task, or its "watch" and "nowatch" variants (usage described in the above "Typical workflow" section). To launch separate local HTTP servers on two different domains (in order to test HTTP CORS cross-origin app vs. ebooks deployment architecture), simply invoke the equivalent tasks named with http2 instead of http. For example: npm run http2. More information about real-world HTTP CORS is given in the "Cloud reader deployment" section below.

Remark: logs of HTTP requests are preserved in two separate files http_app.log and http_ebooks.log. They contains ANSI color escape codes, so although they can be read using a regular text editor, they can be rendered in their original format using the shell command: cat http_app.log (on OSX / Linux), or sed "s,x,x,g" http_app.log (on Windows).

Forking

Assuming a fork of https://github.com/readium/readium-js-viewer is made under USER at https://github.com/USER/readium-js-viewer, the .gitmodules file ( https://github.com/readium/readium-js-viewer/blob/develop/.gitmodules ) will still point to the original submodule URL (at readium, instead of USER). Thankfully, one can simply modify the .gitmodules file by replacing https://github.com/readium/ with https://github.com/USER/, and do this for every submodule (readium-js-viewer > readium-js > readium-shared-js > readium-cfi-js). Then the Git command git submodule sync can be invoked, for each submodule.

Plugins integration

When invoking the npm run build command, the generated build-output folder contains RequireJS module bundles that include the default plugins specified in readium-js/readium-js-shared/plugins/plugins.cson (see the plugins documentation https://github.com/readium/readium-shared-js/blob/develop/PLUGINS.md ). Developers can override the default plugins configuration by using an additional file called plugins-override.cson. This file is git-ignored (not persistent in the Git repository), which means that Readium's default plugins configuration is never at risk of being mistakenly overridden by developers, whilst giving developers the possibility of creating custom builds on their local machines.

For example, the annotations plugin can be activated by adding it to the include section in readium-js/readium-js-shared/plugins/plugins-override.cson. Then, in order to create / remove highlighted selections, simply comment display:none for .icon-annotations in the src/css/viewer.css file (this will enable an additional toolbar button).

RequireJS bundle optimisation

Note that by default, compiled RequireJS bundles are minified / mangled / uglify-ed. You can force the build process to generate non-compressed Javascript bundles by setting the RJS_UGLY environment variable to "no" or "false" (any other value means "yes" / "true").

This may come-in handy when testing / debugging the Chrome Extension (Packaged App) in "developer mode" directly from the dist folder (i.e. without the sourcemaps manually copied into the script folder).

Tests

Mocha-driven UI tests via Selenium (not PhantomJS, but actual installed browsers accessed via WebDriver):

npm run test (runs all of the above)

Via SauceLabs:

npm run test:sauce (runs all of the above)

Travis (Continuous Integration) automatically uses a chromeApp and Firefox test matrix (2x modes), and uses SauceLabs to actually run the test. See https://travis-ci.org/readium/readium-js-viewer/

Distribution

See the dist folder contents (generated by npm run dist):

The source maps are generated separately, so they are effectively an opt-in feature (simply copy/paste them next to their original Javascript file counterparts, e.g. in the scripts folder)

Note that npm run http + dev folder is not the only way to test Readium "locally". The distributable / packaged Readium app in the dist folder can also execute in any arbitrary local HTTP server, such as the built-in NodeJS option node node_modules/http-server/bin/http-server -a 127.0.0.1 -p 8080 -c-1 .. (assuming the current command line folder is readium-js-viewer). Then, simply open the http://127.0.0.1:8080/readium-js-viewer/dist/cloud-reader/index.html?epubs=http://127.0.0.1:8080/readium-js-viewer/epub_content/epub_library.json URL, which explicitely specifies the location of the ebook library (alternatively, you may copy/paste the epub_content folder manually under dist/cloud-reader, and open http://127.0.0.1:8080/readium-js-viewer/dist/cloud-reader/index.html without parameters).

Cloud reader deployment

The cloud-reader distribution folder (see section above) can be uploaded to an HTTP server as-is, in which case a sibling /epub_content/ folder is expected to contain exploded or zipped EPUBs, and the /epub_content/epub_library.json file is expected to describe the available ebooks in the online library (see the existing examples in readium-js-viewer repository). Additionally, the epubs URL parameter (HTTP GET) can be used to specify a different location for the JSON file that describes the ebook library contents, for example: http://domain.com/index.html?epubs=http://otherdomain.com/ebooks.json (assuming both HTTP servers are suitably configured with CORS), or for example http://domain.com/index.html?epubs=EPUBs/ebooks.json (assuming a folder named EPUBs/ exists as a sibling of index.html, and this folder contains the ebooks.json file). Finally, the ebook library can be permanently set to a specific location, by editing cloud-reader/index.html and by replacing the value of epubLibraryPath:

require.config({
config : {
        'readium_js_viewer/ModuleConfig' : {
            'epubLibraryPath': VALUE
        }
});

The cloud-reader-lite distribution does not feature an ebook library, so EPUBs must be specified via the URL parameter (HTTP GET), for example: http://domain.com/index.html?epub=http://otherdomain.com/ebook.epub (assuming both HTTP servers are suitably configured with CORS), or for example http://domain.com/index.html?epub=EPUBs/ebook.epub (assuming a folder named EPUBs/ exists as a sibling of index.html, and this folder contains the ebook.epub file (note that the folder name is arbitrary, and it may in fact follow the default naming convention: epub_content/)).

Example of Readium app hosted at Surge.sh, and EPUBs hosted at DivShot.io: http://readium.surge.sh/?epubs=http://development.readium.divshot.io/epub_content/epub_library.json (note that only DivShot.io specifies HTTP CORS headers, the Surge.sh server does not configure anything special to achieve this unilateral cross-origin resource sharing)

For more information about HTTP CORS, see https://docs.google.com/document/d/1RK_59-75OSE0PA6wexD9rYHQLnNYfoKIpsnH3SmDpUc

NPM (Node Package Manager)

NOTE THAT THIS FEATURE IS NOT FULLY IMPLEMENTED YET (PLEASE REFERENCE THE GITHUB REPOSITORIES INSTEAD FROM YOUR PACKAGE.JSON)

All packages "owned" and maintained by the Readium Foundation are listed here: https://www.npmjs.com/~readium

Note that although Node and NPM natively use the CommonJS format, Readium modules are currently only defined as AMD (RequireJS). This explains why Browserify ( http://browserify.org ) is not used by this Readium project. More information at http://requirejs.org/docs/commonjs.html and http://requirejs.org/docs/node.html

Note: the --dev option after npm install readium-js-viewer can be used to force the download of development dependencies, but this is kind of pointless as the code source and RequireJS build configuration files are missing. See below if you need to hack the code.

How to use (RequireJS bundles / AMD modules)

The build-output directory contains two distinct folders:

Single bundle

The _single-bundle folder contains readium-js-viewer_all.js (and its associated source-map file, as well as a RequireJS bundle index file (which isn't actually needed at runtime, so here just as a reference)), which aggregates all the required code (external library dependencies included, such as Underscore, jQuery, etc.), as well as the "Almond" lightweight AMD loader ( https://github.com/jrburke/almond ).

This means that the full RequireJS library ( http://requirejs.org ) is not actually needed to bootstrap the AMD modules at runtime, as demonstrated by the HTML file in the dev folder (trimmed for brevity):

<html>
<head>

<!-- main code bundle, which includes its own Almond AMD loader (no need for the full RequireJS library) -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_single-bundle/readium-js-viewer_all.js"> </script>

<!-- index.js calls into the above library -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/index.js"> </script>

</head>
<body>
<div id="viewport"> </div>
</body>
</html>

Multiple bundles

The _multiple-bundles folder contains several Javascript bundles (and their respective source-map files, as well as RequireJS bundle index files):

In addition, the folder contains the full RequireJS.js library ( http://requirejs.org ), as the above bundles do no include the lightweight "Almond" AMD loader ( https://github.com/jrburke/almond ).

Usage is demonstrated by the HTML file in the dev folder (trimmed for brevity):

<html>
<head>

<!-- full RequireJS library -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/RequireJS.js"> </script>

<!-- individual bundles: -->

<!-- readium CFI library -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-cfi-js.js"> </script>

<!-- external libraries -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-external-libs.js"> </script>

<!-- readium itself -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-shared-js.js"> </script>

<!-- simple example plugin -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-plugin-example.js"> </script>

<!-- annotations plugin -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-plugin-annotations.js"> </script>

<!-- readium js -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-js.js"> </script>

<!-- readium js viewer -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-js-viewer.js"> </script>

<!-- index.js calls into the above libraries -->
<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/index.js"> </script>

</head>
<body>
<div id="viewport"> </div>
</body>
</html>

Note how the "external libs" set of AMD modules can be explicitly described using the bundles RequireJS configuration directive (this eliminates the apparent opacity of such as large container of library dependencies):


<script type="text/javascript">
requirejs.config({
    baseUrl: '../build-output/_multiple-bundles'
});
</script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-cfi-js.js.bundles.js"> </script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-external-libs.js.bundles.js"> </script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-shared-js.js.bundles.js"> </script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-plugin-example.js.bundles.js"> </script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-plugin-annotations.js.bundles.js"> </script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-js.js.bundles.js"> </script>

<script type="text/javascript" src="https://github.com/GermanCentralLibraryForTheBlind/readium-js-viewer/raw/a11y/./build-output/_multiple-bundles/readium-js-viewer.js.bundles.js"> </script>

CSON vs. JSON (package.json)

CSON = CoffeeScript-Object-Notation ( https://github.com/bevry/cson )

Running the command npm run cson2json will re-generate the package.json JSON file. For more information, see comments in the master ./package/package_base.cson CSON file.

Why CSON? Because it is a lot more readable than JSON, and therefore easier to maintain. The syntax is not only less verbose (separators, etc.), more importantly it allows comments and line breaking!

Although these benefits are not so critical for basic "package" definitions, here package.cson/json declares relatively intricate script tasks that are used in the development workflow. npm run SCRIPT_NAME offers a lightweight technique to handle most build tasks, as NPM CLI utilities are available to perform cross-platform operations (agnostic to the actual command line interface / shell). For more complex build processes, Grunt / Gulp can be used, but these build systems do not necessarily offer the most readable / maintainable options.

Downside: DO NOT invoke npm init or npm install --save --save-dev --save-optional, as this would overwrite / update the JSON, not the master CSON!