From baf91773ec4410dbbed31355cd1bdc016ce6ded9 Mon Sep 17 00:00:00 2001 From: Ventricule Date: Fri, 16 Mar 2018 15:05:56 +0100 Subject: [PATCH] Code totaly rewritted + added pad(url:) support --- .htaccess | 2 +- app.php | 12 - assets/html2opendocument | 1 - assets/htmlpurifier | 1 - assets/parsedown | 1 - assets/parsedown-extra | 1 - assets/spyc | 1 - config.php | 24 +- index.php | 54 +- {assets => libreto/assets}/ajax.php | 0 .../fonts/hkgrotesk/HKGrotesk-Bold.eot | Bin .../fonts/hkgrotesk/HKGrotesk-Bold.svg | 0 .../fonts/hkgrotesk/HKGrotesk-Bold.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-Bold.woff | Bin .../fonts/hkgrotesk/HKGrotesk-Bold.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-BoldItalic.eot | Bin .../fonts/hkgrotesk/HKGrotesk-BoldItalic.svg | 0 .../fonts/hkgrotesk/HKGrotesk-BoldItalic.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-BoldItalic.woff | Bin .../hkgrotesk/HKGrotesk-BoldItalic.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-Italic.eot | Bin .../fonts/hkgrotesk/HKGrotesk-Italic.svg | 0 .../fonts/hkgrotesk/HKGrotesk-Italic.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-Italic.woff | Bin .../fonts/hkgrotesk/HKGrotesk-Italic.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-Light.eot | Bin .../fonts/hkgrotesk/HKGrotesk-Light.svg | 0 .../fonts/hkgrotesk/HKGrotesk-Light.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-Light.woff | Bin .../fonts/hkgrotesk/HKGrotesk-Light.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-LightItalic.eot | Bin .../fonts/hkgrotesk/HKGrotesk-LightItalic.svg | 0 .../fonts/hkgrotesk/HKGrotesk-LightItalic.ttf | Bin .../hkgrotesk/HKGrotesk-LightItalic.woff | Bin .../hkgrotesk/HKGrotesk-LightItalic.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-Medium.eot | Bin .../fonts/hkgrotesk/HKGrotesk-Medium.svg | 0 .../fonts/hkgrotesk/HKGrotesk-Medium.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-Medium.woff | Bin .../fonts/hkgrotesk/HKGrotesk-Medium.woff2 | Bin .../hkgrotesk/HKGrotesk-MediumItalic.eot | Bin .../hkgrotesk/HKGrotesk-MediumItalic.svg | 0 .../hkgrotesk/HKGrotesk-MediumItalic.ttf | Bin .../hkgrotesk/HKGrotesk-MediumItalic.woff | Bin .../hkgrotesk/HKGrotesk-MediumItalic.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-Regular.eot | Bin .../fonts/hkgrotesk/HKGrotesk-Regular.svg | 0 .../fonts/hkgrotesk/HKGrotesk-Regular.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-Regular.woff | Bin .../fonts/hkgrotesk/HKGrotesk-Regular.woff2 | Bin .../fonts/hkgrotesk/HKGrotesk-SemiBold.eot | Bin .../fonts/hkgrotesk/HKGrotesk-SemiBold.svg | 0 .../fonts/hkgrotesk/HKGrotesk-SemiBold.ttf | Bin .../fonts/hkgrotesk/HKGrotesk-SemiBold.woff | Bin .../fonts/hkgrotesk/HKGrotesk-SemiBold.woff2 | Bin .../hkgrotesk/HKGrotesk-SemiBoldItalic.eot | Bin .../hkgrotesk/HKGrotesk-SemiBoldItalic.svg | 0 .../hkgrotesk/HKGrotesk-SemiBoldItalic.ttf | Bin .../hkgrotesk/HKGrotesk-SemiBoldItalic.woff | Bin .../hkgrotesk/HKGrotesk-SemiBoldItalic.woff2 | Bin .../assets}/fonts/jeanluc/jeanlucweb-bold.eot | Bin .../assets}/fonts/jeanluc/jeanlucweb-bold.otf | Bin .../assets}/fonts/jeanluc/jeanlucweb-bold.svg | 0 .../fonts/jeanluc/jeanlucweb-bold.woff | Bin .../assets}/fonts/jeanluc/jeanlucweb-thin.eot | Bin .../assets}/fonts/jeanluc/jeanlucweb-thin.otf | Bin .../assets}/fonts/jeanluc/jeanlucweb-thin.svg | 0 .../fonts/jeanluc/jeanlucweb-thin.woff | Bin .../assets}/fonts/jeanluc/stylesheet.css | 0 .../assets}/fonts/spungold/spungold.eot | Bin .../assets}/fonts/spungold/spungold.svg | 0 .../assets}/fonts/spungold/spungold.ttf | Bin .../assets}/fonts/spungold/spungold.woff | Bin .../assets}/images/carnet-dessine.png | Bin .../assets}/images/libretonet.png | Bin libreto/assets/images/logo.png | Bin 0 -> 45430 bytes {assets => libreto/assets}/images/logo.svg | 0 libreto/assets/js/bindery-controls.min.js | 2 + libreto/assets/js/bindery.min.js | 2 + libreto/assets/js/bindery.umd.js | 3142 +++++++++++++++++ {assets => libreto/assets}/script.js | 6 +- {assets => libreto/assets}/style-index.css | 25 +- {assets => libreto/assets}/style-reader.css | 12 +- {assets => libreto/assets}/style.css | 54 +- {assets => libreto/assets}/texts/colophon.md | 0 {assets => libreto/assets}/texts/homepage.md | 0 .../assets}/texts/translation.yml | 0 libreto/bootstrap.php | 13 + libreto/helpers.php | 43 + libreto/libreto.php | 179 + libreto/pad.php | 166 + libreto/pads.php | 83 + libreto/router.php | 96 + libreto/vendor/load.php | 12 + reader.php | 35 - snippets/controller.php | 8 - snippets/functions.php | 192 - snippets/header.php | 15 - snippets/init.php | 30 - snippets/introduction.php | 14 - snippets/nav.php | 36 - views/languages/home.en.yml | 22 + views/languages/home.fr.yml | 26 + views/languages/libreto.en.yml | 45 + views/languages/libreto.fr.yml | 46 + {snippets => views/snippets}/footer.php | 0 views/snippets/header.php | 12 + views/snippets/introduction.php | 17 + views/snippets/nav.php | 25 + views/templates/bindery.php | 73 + views/templates/export.php | 3 + views/templates/home.php | 37 + views/templates/libreto.php | 17 + views/templates/reader.php | 36 + 114 files changed, 4192 insertions(+), 429 deletions(-) delete mode 100644 app.php delete mode 160000 assets/html2opendocument delete mode 160000 assets/htmlpurifier delete mode 160000 assets/parsedown delete mode 160000 assets/parsedown-extra delete mode 160000 assets/spyc rename {assets => libreto/assets}/ajax.php (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Bold.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Bold.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Bold.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Bold.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Bold.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-BoldItalic.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-BoldItalic.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-BoldItalic.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Italic.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Italic.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Italic.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Italic.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Italic.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Light.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Light.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Light.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Light.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Light.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-LightItalic.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-LightItalic.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-LightItalic.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-LightItalic.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-LightItalic.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Medium.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Medium.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Medium.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Medium.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Medium.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-MediumItalic.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-MediumItalic.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-MediumItalic.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Regular.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Regular.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Regular.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Regular.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-Regular.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBold.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBold.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBold.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBold.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBold.woff2 (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.eot (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.svg (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.ttf (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff (100%) rename {assets => libreto/assets}/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff2 (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-bold.eot (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-bold.otf (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-bold.svg (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-bold.woff (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-thin.eot (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-thin.otf (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-thin.svg (100%) rename {assets => libreto/assets}/fonts/jeanluc/jeanlucweb-thin.woff (100%) rename {assets => libreto/assets}/fonts/jeanluc/stylesheet.css (100%) rename {assets => libreto/assets}/fonts/spungold/spungold.eot (100%) rename {assets => libreto/assets}/fonts/spungold/spungold.svg (100%) rename {assets => libreto/assets}/fonts/spungold/spungold.ttf (100%) rename {assets => libreto/assets}/fonts/spungold/spungold.woff (100%) rename {assets => libreto/assets}/images/carnet-dessine.png (100%) rename {assets => libreto/assets}/images/libretonet.png (100%) create mode 100644 libreto/assets/images/logo.png rename {assets => libreto/assets}/images/logo.svg (100%) create mode 100644 libreto/assets/js/bindery-controls.min.js create mode 100644 libreto/assets/js/bindery.min.js create mode 100644 libreto/assets/js/bindery.umd.js rename {assets => libreto/assets}/script.js (87%) rename {assets => libreto/assets}/style-index.css (92%) rename {assets => libreto/assets}/style-reader.css (93%) rename {assets => libreto/assets}/style.css (86%) rename {assets => libreto/assets}/texts/colophon.md (100%) rename {assets => libreto/assets}/texts/homepage.md (100%) rename {assets => libreto/assets}/texts/translation.yml (100%) create mode 100644 libreto/bootstrap.php create mode 100644 libreto/helpers.php create mode 100644 libreto/libreto.php create mode 100644 libreto/pad.php create mode 100644 libreto/pads.php create mode 100644 libreto/router.php create mode 100644 libreto/vendor/load.php delete mode 100644 reader.php delete mode 100644 snippets/controller.php delete mode 100644 snippets/functions.php delete mode 100644 snippets/header.php delete mode 100644 snippets/init.php delete mode 100644 snippets/introduction.php delete mode 100644 snippets/nav.php create mode 100644 views/languages/home.en.yml create mode 100644 views/languages/home.fr.yml create mode 100644 views/languages/libreto.en.yml create mode 100644 views/languages/libreto.fr.yml rename {snippets => views/snippets}/footer.php (100%) create mode 100644 views/snippets/header.php create mode 100644 views/snippets/introduction.php create mode 100644 views/snippets/nav.php create mode 100644 views/templates/bindery.php create mode 100644 views/templates/export.php create mode 100644 views/templates/home.php create mode 100644 views/templates/libreto.php create mode 100644 views/templates/reader.php diff --git a/.htaccess b/.htaccess index 3c8e810..e549d42 100644 --- a/.htaccess +++ b/.htaccess @@ -1 +1 @@ -FallbackResource /app.php +FallbackResource /index.php diff --git a/app.php b/app.php deleted file mode 100644 index d5bef1b..0000000 --- a/app.php +++ /dev/null @@ -1,12 +0,0 @@ - - - - -
- - -
- -
-
- diff --git a/assets/html2opendocument b/assets/html2opendocument deleted file mode 160000 index 864f014..0000000 --- a/assets/html2opendocument +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 864f014cf1f048a25911c3db361c5796e9f9648f diff --git a/assets/htmlpurifier b/assets/htmlpurifier deleted file mode 160000 index 6d6d885..0000000 --- a/assets/htmlpurifier +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6d6d88512a8146939a9161bb03e95e3e97840439 diff --git a/assets/parsedown b/assets/parsedown deleted file mode 160000 index c999a4b..0000000 --- a/assets/parsedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c999a4b61bfc15d3eed74a40ce814afe6faa21ea diff --git a/assets/parsedown-extra b/assets/parsedown-extra deleted file mode 160000 index 0db5cce..0000000 --- a/assets/parsedown-extra +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0db5cce7354e4b76f155d092ab5eb3981c21258c diff --git a/assets/spyc b/assets/spyc deleted file mode 160000 index 576c42e..0000000 --- a/assets/spyc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 576c42ecbc9630b52a95da3279f07278572c6b15 diff --git a/config.php b/config.php index a90c400..63d71b4 100644 --- a/config.php +++ b/config.php @@ -1,7 +1,19 @@ array( + 'name' => "Framapad", + 'url' => "https://annuel2.framapad.org", + 'default_text' => "–––––", + ), + 'board' => array( + 'name' => "Board", + 'url' => "https://board.net", + 'default_text' => "--", + ) +); + +$options = array( + 'name' => "Libreto", + 'default_provider' => "framapad", + 'providers' => $providers, +); diff --git a/index.php b/index.php index c2e12a7..6a34011 100644 --- a/index.php +++ b/index.php @@ -1,42 +1,26 @@ - - +// load all dependencies +require __DIR__ . DS . 'libreto' . DS . 'vendor' . DS . 'load.php'; - - - - +// load all helpers functions +require __DIR__ . DS . 'libreto' . DS . 'helpers.php'; - Libreto +// load all core classes +function loadClass($classe) { + require __DIR__ . DS . 'libreto' . DS . $classe . '.php'; +} +spl_autoload_register('loadClass'); - - +// load options +require __DIR__ . DS . 'config.php'; - -
- setBreaksEnabled(true)->text($markdown); - echo $html; - ?> -
-
- - -
-
-
- +// create Libreto +$libreto = new Libreto($options); - +// launch +$libreto->launch(); + +// var_dump($libreto); diff --git a/assets/ajax.php b/libreto/assets/ajax.php similarity index 100% rename from assets/ajax.php rename to libreto/assets/ajax.php diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Bold.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Bold.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Bold.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Bold.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Bold.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Bold.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Bold.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Bold.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Bold.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Bold.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Bold.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-BoldItalic.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Italic.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Italic.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Italic.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Italic.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Italic.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Italic.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Italic.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Italic.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Italic.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Italic.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Italic.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Light.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Light.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Light.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Light.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Light.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Light.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Light.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Light.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Light.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Light.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Light.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-LightItalic.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-LightItalic.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-LightItalic.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-LightItalic.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Medium.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Medium.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Medium.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Medium.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Medium.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Medium.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Medium.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Medium.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Medium.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Medium.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Medium.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-MediumItalic.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Regular.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Regular.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Regular.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Regular.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Regular.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Regular.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Regular.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Regular.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-Regular.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-Regular.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-Regular.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBold.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBold.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBold.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBold.woff2 diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.eot b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.eot similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.eot rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.eot diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.svg b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.svg similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.svg rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.svg diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.ttf b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.ttf similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.ttf rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.ttf diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff diff --git a/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff2 b/libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff2 similarity index 100% rename from assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff2 rename to libreto/assets/fonts/hkgrotesk/HKGrotesk-SemiBoldItalic.woff2 diff --git a/assets/fonts/jeanluc/jeanlucweb-bold.eot b/libreto/assets/fonts/jeanluc/jeanlucweb-bold.eot similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-bold.eot rename to libreto/assets/fonts/jeanluc/jeanlucweb-bold.eot diff --git a/assets/fonts/jeanluc/jeanlucweb-bold.otf b/libreto/assets/fonts/jeanluc/jeanlucweb-bold.otf similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-bold.otf rename to libreto/assets/fonts/jeanluc/jeanlucweb-bold.otf diff --git a/assets/fonts/jeanluc/jeanlucweb-bold.svg b/libreto/assets/fonts/jeanluc/jeanlucweb-bold.svg similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-bold.svg rename to libreto/assets/fonts/jeanluc/jeanlucweb-bold.svg diff --git a/assets/fonts/jeanluc/jeanlucweb-bold.woff b/libreto/assets/fonts/jeanluc/jeanlucweb-bold.woff similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-bold.woff rename to libreto/assets/fonts/jeanluc/jeanlucweb-bold.woff diff --git a/assets/fonts/jeanluc/jeanlucweb-thin.eot b/libreto/assets/fonts/jeanluc/jeanlucweb-thin.eot similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-thin.eot rename to libreto/assets/fonts/jeanluc/jeanlucweb-thin.eot diff --git a/assets/fonts/jeanluc/jeanlucweb-thin.otf b/libreto/assets/fonts/jeanluc/jeanlucweb-thin.otf similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-thin.otf rename to libreto/assets/fonts/jeanluc/jeanlucweb-thin.otf diff --git a/assets/fonts/jeanluc/jeanlucweb-thin.svg b/libreto/assets/fonts/jeanluc/jeanlucweb-thin.svg similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-thin.svg rename to libreto/assets/fonts/jeanluc/jeanlucweb-thin.svg diff --git a/assets/fonts/jeanluc/jeanlucweb-thin.woff b/libreto/assets/fonts/jeanluc/jeanlucweb-thin.woff similarity index 100% rename from assets/fonts/jeanluc/jeanlucweb-thin.woff rename to libreto/assets/fonts/jeanluc/jeanlucweb-thin.woff diff --git a/assets/fonts/jeanluc/stylesheet.css b/libreto/assets/fonts/jeanluc/stylesheet.css similarity index 100% rename from assets/fonts/jeanluc/stylesheet.css rename to libreto/assets/fonts/jeanluc/stylesheet.css diff --git a/assets/fonts/spungold/spungold.eot b/libreto/assets/fonts/spungold/spungold.eot similarity index 100% rename from assets/fonts/spungold/spungold.eot rename to libreto/assets/fonts/spungold/spungold.eot diff --git a/assets/fonts/spungold/spungold.svg b/libreto/assets/fonts/spungold/spungold.svg similarity index 100% rename from assets/fonts/spungold/spungold.svg rename to libreto/assets/fonts/spungold/spungold.svg diff --git a/assets/fonts/spungold/spungold.ttf b/libreto/assets/fonts/spungold/spungold.ttf similarity index 100% rename from assets/fonts/spungold/spungold.ttf rename to libreto/assets/fonts/spungold/spungold.ttf diff --git a/assets/fonts/spungold/spungold.woff b/libreto/assets/fonts/spungold/spungold.woff similarity index 100% rename from assets/fonts/spungold/spungold.woff rename to libreto/assets/fonts/spungold/spungold.woff diff --git a/assets/images/carnet-dessine.png b/libreto/assets/images/carnet-dessine.png similarity index 100% rename from assets/images/carnet-dessine.png rename to libreto/assets/images/carnet-dessine.png diff --git a/assets/images/libretonet.png b/libreto/assets/images/libretonet.png similarity index 100% rename from assets/images/libretonet.png rename to libreto/assets/images/libretonet.png diff --git a/libreto/assets/images/logo.png b/libreto/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4abedfcee311eed6f621010ee4d331f80ca50932 GIT binary patch literal 45430 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:i>>>0;(s=r.exec(o))&&!((l=s.index+s[0].length)>d&&(c.push(o.slice(d,s.index)),!n&&s.length>1&&s[0].replace(a,function(){for(var t=1;t1&&s.index=i));)r.lastIndex===s.index&&r.lastIndex++;return d===o.length?!p&&r.test("")||c.push(""):c.push(o.slice(d)),c.length>i?c.slice(0,i):c}),r=[].indexOf,i=function(e,t){if(r)return e.indexOf(t);for(var n=0;n-1||(t.push(e),p(t))}function r(e){var t=l(),n=i(t,e);-1!==n&&(t.splice(n,1),p(t))}function a(e){return i(l(),e)>-1}function l(){var t=e.className;return function(e,t){for(var n=[],o=0;o/g,">")}function y(e){return g(e).replace(/"/g,""")}function v(){}function w(){}function b(e){e.__defineGetter__("parentNode",function(){return this.parentElement})}u.prototype.createTextNode=function(e){var t=new v;return t.textContent=e,t.nodeName="#text",t.nodeType=3,t},u.prototype.createElement=function(e){var t=new m;return t.nodeName=t.tagName=e,t},u.prototype.createComment=function(e){var t=new w;return t.data=e,t},v.prototype=new d,m.prototype=new d,w.prototype=new d,f.prototype.setProperty=function(e,t){this.el._setProperty(this.styles,{name:e,value:t})},f.prototype.getProperty=function(e){return this.el._getProperty(this.styles,e)},f.prototype.__defineGetter__("cssText",function(){var e="";return this.styles.forEach(function(t){e+=t.name+":"+t.value+";"}),e}),f.prototype.__defineSetter__("cssText",function(e){this.styles.length=0,e.split(";").forEach(function(e){var t=e.indexOf(":");if(t){var n=e.slice(0,t).trim(),o=e.slice(t+1).trim();this.setProperty(n,o)}},this)}),m.prototype.nodeType=1,m.prototype.appendChild=function(e){return e.parentElement=this,this.childNodes.push(e),e},m.prototype.setAttribute=function(e,t){"style"==e?this.style.cssText=t:this._setProperty(this.attributes,h,e,t)},m.prototype.getAttribute=function(e){if("style"==e)return this.style.cssText;var t=this._getProperty(this.attributes,e);return void 0!==t?t.value:null},m.prototype.removeAttribute=function(e){if("class"===e)delete this.className;else for(var t=0,n=this.attributes.length;t"),{AREA:!0,BASE:!0,BR:!0,COL:!0,EMBED:!0,HR:!0,IMG:!0,INPUT:!0,KEYGEN:!0,LINK:!0,META:!0,PARAM:!0,SOURCE:!0,TRACK:!0,WBR:!0}[this.nodeName.toUpperCase()]||(e.push(this.innerHTML),e.push("")),e.join("")}),m.prototype.__defineGetter__("textContent",function(){var e="";return this.childNodes.forEach(function(t){e+=t.textContent}),e}),m.prototype.__defineSetter__("textContent",function(e){var t=new v;return t.textContent=e,this.childNodes=[t],e}),m.prototype.addEventListener=function(e,t){},m.prototype.nodeValue=null,v.prototype.nodeType=3,v.prototype.nodeName="#text",v.prototype.__defineGetter__("textContent",function(){return g(this.value||"")}),v.prototype.__defineSetter__("textContent",function(e){this.value=e}),v.prototype.__defineGetter__("nodeValue",function(){return g(this.value||"")}),v.prototype.__defineSetter__("nodeValue",function(e){this.value=e}),v.prototype.__defineGetter__("length",function(){return(this.value||"").length}),v.prototype.replaceData=function(e,t,n){this.value=this.value.slice(0,e)+n+this.value.slice(e+t)},w.prototype.nodeType=8,w.prototype.nodeName="#comment",w.prototype.__defineGetter__("data",function(){return this.value}),w.prototype.__defineSetter__("data",function(e){this.value=e}),w.prototype.__defineGetter__("outerHTML",function(){return"\x3c!--"+g(this.value||"")+"--\x3e"}),w.prototype.__defineGetter__("nodeValue",function(){return g(this.value||"")}),w.prototype.__defineSetter__("nodeValue",function(e){this.value=e}),b(m.prototype),b(w.prototype),b(v.prototype),b(d.prototype);var x,S={Document:u,Node:d,Element:m,Comment:w,Text:v,document:new u},_=(function(e){var t="undefined"==typeof window?S:window,n=t.document,r=t.Text;function i(){var e=[];function t(){var t=[].slice.call(arguments),i=null;function p(t){var c,u,d;if(null==t);else if("string"==typeof t)i?i.appendChild(c=n.createTextNode(t)):(d=o(t,/([\.#]?[^\s#.]+)/),/^\.|#/.test(d[1])&&(i=n.createElement("div")),l(d,function(e){var t=e.substring(1,e.length);e&&(i?"."===e[0]?a(i).add(t):"#"===e[0]&&i.setAttribute("id",t):i=n.createElement(e))}));else if("number"==typeof t||"boolean"==typeof t||t instanceof Date||t instanceof RegExp)i.appendChild(c=n.createTextNode(t.toString()));else if(u=t,"[object Array]"==Object.prototype.toString.call(u))l(t,p);else if(s(t))i.appendChild(c=t);else if(t instanceof r)i.appendChild(c=t);else if("object"==typeof t)for(var f in t)if("function"==typeof t[f])/^on\w+/.test(f)?function(t,n){i.addEventListener?(i.addEventListener(t.substring(2),n[t],!1),e.push(function(){i.removeEventListener(t.substring(2),n[t],!1)})):(i.attachEvent(t,n[t]),e.push(function(){i.detachEvent(t,n[t])}))}(f,t):(i[f]=t[f](),e.push(t[f](function(e){i[f]=e})));else if("style"===f)if("string"==typeof t[f])i.style.cssText=t[f];else for(var h in t[f])!function(n,o){if("function"==typeof o)i.style.setProperty(n,o()),e.push(o(function(e){i.style.setProperty(n,e)}));else var r=t[f][n].match(/(.*)\W+!important\W*$/);r?i.style.setProperty(n,r[1],"important"):i.style.setProperty(n,t[f][n])}(h,t[f][h]);else if("attrs"===f)for(var m in t[f])i.setAttribute(m,t[f][m]);else"data-"===f.substr(0,5)?i.setAttribute(f,t[f]):i[f]=t[f];else if("function"==typeof t){m=t();i.appendChild(c=s(m)?m:n.createTextNode(m)),e.push(t(function(e){s(e)&&c.parentElement?(c.parentElement.replaceChild(e,c),c=e):c.textContent=e}))}return c}for(;t.length;)p(t.shift());return i}return t.cleanup=function(){for(var t=0;t100&&(G=t,w.textContent=e+" Pages")},this.setDone=function(e){w.textContent=e+" Pages"},this.setInvalid=function(){},u.classList.add(E("btn-print"));var R=A(g,v,y);R.classList.add(E("print-options")),l=T.apply(void 0,[{onchange:function(e){return o.setMode(e.target.value)}}].concat(N([C({value:r.PREVIEW},"Preview"),C({value:r.FLIPBOOK},"Flipbook"),C({value:r.PRINT},"Print Preview")].map(function(e){return e.value===n.mode&&(e.selected=!0),e}))));var M=A(l);M.classList.add(E("view-row")),this.element=_(E(".controls"),B,O,M,R,u)}}(); +//# sourceMappingURL=bindery-controls.min.js.map diff --git a/libreto/assets/js/bindery.min.js b/libreto/assets/js/bindery.min.js new file mode 100644 index 0000000..c15c18a --- /dev/null +++ b/libreto/assets/js/bindery.min.js @@ -0,0 +1,2 @@ +var Bindery=function(){"use strict";var e="v2.1.0",t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},r=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:[],n=document.createElement("div");return n.className=e.split(".").filter(function(e){return""!==e}).map(k).join(" "),"string"==typeof t?n.textContent=t:Array.isArray(t)&&t.forEach(function(e){return n.appendChild(e)}),n},P=function(){function e(){n(this,e),this.flowContent=C("content"),this.flowBox=C("flowbox",[this.flowContent]),this.footer=C("footer"),this.background=C("background"),this.element=C("page",[this.background,this.flowBox,this.footer])}return r(e,[{key:"overflowAmount",value:function(){var e=this.flowContent.offsetHeight,t=this.flowBox.offsetHeight;if(0===t)throw Error("Bindery: Trying to flow into a box of zero height.");return e-t}},{key:"hasOverflowed",value:function(){return this.overflowAmount()>-5}},{key:"setLeftRight",value:function(e){if("left"===e)this.side=e,this.element.classList.remove(k("right")),this.element.classList.add(k("left"));else{if("right"!==e)throw Error("Bindery: Setting page to invalid direction"+e);this.side=e,this.element.classList.remove(k("left")),this.element.classList.add(k("right"))}}},{key:"setPreference",value:function(e){"left"===e&&(this.alwaysLeft=!0),"right"===e&&(this.alwaysRight=!0)}},{key:"suppressErrors",get:function(){return this.suppress||!1},set:function(e){this.suppress=e,e?this.element.classList.add(k("is-overflowing")):this.element.classList.remove(k("is-overflowing"))}},{key:"isEmpty",get:function(){return!this.hasOutOfFlowContent&&""===this.flowContent.textContent.trim()&&this.flowContent.offsetHeight<1}},{key:"isLeft",get:function(){return"left"===this.side}},{key:"isRight",get:function(){return"right"===this.side}}],[{key:"isSizeValid",value:function(){document.body.classList.remove(k("viewing"));var t=new e,n=document.querySelector(k(".measure-area"));n||(n=document.body.appendChild(C("measure-area"))),n.innerHTML="",n.appendChild(t.element);var r=t.flowBox.getBoundingClientRect();return n.parentNode.removeChild(n),r.height>100&&r.width>100}}]),e}(),S=function e(t){return!!t.hasAttribute("data-ignore-overflow")||!!t.parentElement&&e(t.parentElement)},x=new(function(){function e(){n(this,e),this.numberOfCalls=0,this.resumeLimit=1/0,this.callsSinceResume=0,this.queuedFunc=null,this.isPaused=!1,this.useDelay=!1,this.delayTime=100,this.lastWaitedTime=0}return r(e,[{key:"throttle",value:function(e){var t=this;this.callsSinceResume+=1,this.callsSinceResume>this.resumeLimit&&this.endResume();var n=performance.now()-this.lastWaitedTime;this.isPaused?this.queuedFunc=e:this.useDelay?setTimeout(e,this.delayTime):this.numberOfCalls<800&&n<50?(this.numberOfCalls+=1,e()):(this.numberOfCalls=0,document.hidden?setTimeout(e,1):requestAnimationFrame(function(n){t.lastWaitedTime=n,e()}))}},{key:"pause",value:function(){return this.isPaused?"Already paused":(this.isPaused=!0,"Paused")}},{key:"resumeDelay",value:function(){this.useDelay=!0,this.resume()}},{key:"finish",value:function(){this.useDelay=!1,this.resume()}},{key:"resume",value:function(){return this.isPaused?(this.isPaused=!1,this.queuedFunc?(this.queuedFunc(),this.queuedFunc=null,"Resuming"):"Layout complete"):"Already running"}},{key:"step",value:function(){if(!this.isPaused)return this.pause();if(this.queuedFunc){var e=this.queuedFunc,t=e.name;return this.queuedFunc=null,e(),t}return"Layout complete"}},{key:"resumeFor",value:function(e){return this.callsSinceResume=0,this.resumeLimit=e,this.resume()}},{key:"endResume",value:function(){console.log("Paused after "+this.resumeLimit),this.resumeLimit=1/0,this.callsSinceResume=0,this.pause()}},{key:"isDebugging",get:function(){return this.useDelay},set:function(e){this.useDelay=e,e&&(window.binderyDebug={pause:this.pause.bind(this),resume:this.resume.bind(this),resumeFor:this.resumeFor.bind(this),step:this.step.bind(this),finish:this.finish.bind(this)},console.log("Bindery: Debug layout with the following: \nbinderyDebug.pause() \nbinderyDebug.resume()\n binderyDebug.resumeFor(n) // pauses after n steps, \nbinderyDebug.step()"))}}]),e}()),E=function(){function e(t){n(this,e),this.successArgs=[],this.errorArgs=[],this.successCallback=null,this.errorCallback=null,this.progressCallback=null,this.chainedThenable=null,this.chainedSuccessCallback=null,this.chainedErrorCallback=null,this.isRejected=!1,this.isResolved=!1,this.resolve=this.resolve.bind(this),this.reject=this.reject.bind(this),this.updateProgress=this.updateProgress.bind(this),t&&t(this.resolve,this.reject,this.updateProgress)}return r(e,[{key:"then",value:function(e){if(this.chainedThenable)return this.chainedThenable.then(e);if(!this.successCallback)return this.successCallback=e,this.isResolved&&this.resolve(),this;if(!this.chainedSuccessCallback)return this.chainedSuccessCallback=e,this.isResolved&&this.resolveChained(),this;throw Error("need real chained then")}},{key:"progress",value:function(e){return this.progressCallback=e,this}},{key:"catch",value:function(e){if(this.chainedThenable)return this.chainedThenable.catch(e);if(!this.errorCallback)return this.errorCallback=e,this.isRejected&&this.reject(),this;if(!this.chainedErrorCallback)return this.chainedErrorCallback=e,this.isRejected&&this.rejectChained(),this;throw Error("need real chained catch")}},{key:"resolve",value:function(){this.isResolved=!0;for(var e=arguments.length,t=Array(e),n=0;n0&&(this.successArgs=t),null!==this.successCallback){var r=void 0;(r=this.successArgs.length>0?this.successCallback.apply(this,a(this.successArgs)):this.successCallback())&&r.then&&(this.chainedThenable=r),this.chainedSuccessCallback&&this.resolveChained()}}},{key:"resolveChained",value:function(){this.chainedThenable?this.chainedThenable.then(this.chainedSuccessCallback):this.chainedSuccessCallback()}},{key:"reject",value:function(){this.isRejected=!0;for(var e=arguments.length,t=Array(e),n=0;n0&&(this.errorArgs=t),null!==this.errorCallback){var r=void 0;(r=this.errorArgs.length>0?this.errorCallback.apply(this,a(this.errorArgs)):this.errorCallback())&&r.then&&(this.chainedThenable=r),this.successCallback&&r&&r.then&&r.then(this.successCallback),this.chainedSuccessCallback&&(r&&r.then?r.then(this.chainedSuccessCallback):this.chainedSuccessCallback()),this.chainedErrorCallback&&this.rejectChained()}}},{key:"rejectChained",value:function(){this.chainedThenable?this.chainedThenable.catch(this.chainedErrorCallback):this.chainedErrorCallback()}},{key:"updateProgress",value:function(){null!==this.progressCallback&&this.progressCallback.apply(this,arguments)}}],[{key:"resolved",value:function(){return new e(function(e){return e()})}}]),e}(),O=function(e,t,n){return new E(function(r,i){t.appendChild(e),n.hasOverflowed()?(t.removeChild(e),x.throttle(i)):x.throttle(r)})},T=function(e,t,n){return new E(function(r,i){var o=e.nodeValue;if(t.appendChild(e),n.hasOverflowed()&&!S(t)){var s=0;!function t(){if(e.nodeValue=o.substr(0,s),n.hasOverflowed()){for(" "===o.charAt(s)&&(s-=1);" "!==o.charAt(s)&&s>0;)s-=1;if(s<1)return e.nodeValue=o,e.parentNode.removeChild(e),void x.throttle(i);var a=o.substr(0,s),l=o.substr(s);e.nodeValue=a;var u=document.createTextNode(l);x.throttle(function(){return r(u)})}else if(s>o.length-1)x.throttle(r);else{for(s+=1;" "!==o.charAt(s)&&s0&&(r="."+[].concat(a(e.classList)).join("."));var i="";return n.length<1&&r.length<2&&(i='("'+e.textContent.substr(0,30).replace(/\s+/g," ")+'...")'),t+n+r+i},I=function(e){return e instanceof R||e instanceof L||e instanceof B},N=function(e){var t=e.filter(I),n=e.filter(function(e){return!t.includes(e)}),r=t.find(function(e){return e instanceof R}),i=t.find(function(e){return e instanceof L});return r?n.push(r):i?n.push(i):n.push.apply(n,a(t)),n},F=function(){function e(t){n(this,e),this.rules=t,this.pageRules=t.filter(function(e){return e.eachPage}),this.beforeAddRules=t.filter(function(e){return e.selector&&e.beforeAdd}),this.afterAddRules=t.filter(function(e){return e.selector&&e.afterAdd}),this.selectorsNotToSplit=t.filter(function(e){return e.avoidSplit}).map(function(e){return e.selector})}return r(e,[{key:"setup",value:function(){this.rules.forEach(function(e){e.setup&&e.setup()})}},{key:"startPage",value:function(e,t){this.rules.forEach(function(n){n.afterPageCreated&&n.afterPageCreated(e,t)})}},{key:"finishEveryPage",value:function(e){this.pageRules.forEach(function(t){e.pages.forEach(function(n){t.eachPage(n,e)})})}},{key:"finishPage",value:function(e,t){this.pageRules.forEach(function(n){n.eachPage(e,t)})}},{key:"beforeAddElement",value:function(e,t,n,r){var i=e;return this.beforeAddRules.filter(function(e){return i.matches(e.selector)}).forEach(function(e){i=e.beforeAdd(i,t,n,r)}),i}},{key:"afterAddElement",value:function(e,t,n,r,i){var o=e,s=this.afterAddRules.filter(function(e){return o.matches(e.selector)});return N(s).forEach(function(e){o=e.afterAdd(o,t,n,r,function(o){return i(o),e.afterAdd(o,t,n,r,function(){console.log("Couldn't apply "+e.name+" to "+_(o)+". Caused overflows twice.")})})}),o}}]),e}(),M=function(e,t){for(var n=t;nr&&(t[e]="")})),""!==t[n]&&(e.heading[n]=t[n])})})},H=function(e,t){for(var n=[],r=t.filter(function(e){return e.customToNextClass}).map(function(e){return e.customToNextClass}),i=t.filter(function(e){return e.customFromPreviousClass}).map(function(e){return e.customFromPreviousClass}),o=e.length-1;o>=0;o-=1){var s=e[o],a=s.cloneNode(!1);if(a.innerHTML="",function(e){e.classList.add(k("continues")),r.forEach(function(t){return e.classList.add(t)})}(s),function(e){e.classList.add(k("continuation")),i.forEach(function(t){return e.classList.add(t)})}(a),"OL"===a.tagName){var l=1;s.hasAttribute("start")&&(l=parseInt(s.getAttribute("start"),10)),o0&&void 0!==arguments[0]&&arguments[0];if(f.pages.length>2e3)throw r("Maximum page count exceeded"),Error("Bindery: Maximum page count exceeded. Suspected runaway layout.");b(f.pageInProgress,e),p=H(p,t);var n=m();if(f.pageInProgress=n,i(f),f.pages.push(n),p[0]&&n.flowContent.appendChild(p[0]),n.hasOverflowed()){var o=u(p);o?(console.warn("Bindery: Content overflows, probably due to a style set on "+_(o)+"."),o.parentNode.removeChild(o)):console.warn("Bindery: Content overflows.")}return n},y=function(e){if(p.pop(),p.length<1)throw Error("Bindery: Attempting to move the top-level element");for(var t=e,n=[];p.length>1&&!J(u(p),h.selectorsNotToSplit);)t=p.pop(),n.unshift(t);t.setAttribute("data-bindery-did-move",!0);var r=t.parentNode;r.removeChild(t),p.length>1&&""===u(p).textContent.trim()&&(r.appendChild(t),t=p.pop(),n.unshift(t),t.parentNode.removeChild(t)),f.pageInProgress.isEmpty||(f.pageInProgress.hasOverflowed()&&(f.pageInProgress.suppressErrors=!0),v()),u(p).appendChild(t),n.forEach(function(e){p.push(e)}),p.push(e)},w=function(e,t){return new E(function(n){t.appendChild(e),g()&&(f.pageInProgress.suppressErrors=!0,v()),n()})},k=function e(t){return new E(function(n,r){T(t,u(p),f.pageInProgress).then(function(t){t?(v(),e(t).then(n).catch(r)):n()}).catch(r)})},x=function(e){return J(e,h.selectorsNotToSplit)&&!S(e)},A=function(e,t){return(x(t)?k(e).catch(function(){return p.length<2?w(e,u(p)):(y(t),k(e))}):O(e,u(p),f.pageInProgress).catch(function(){return g()&&y(t),O(e,u(p),f.pageInProgress)})).catch(function(){return w(e,u(p))})},z=void 0,L=function(e,t){if(U(e))return A(e,t);if(K(e)){var n=performance.now();return q(e).then(function(){return o+=performance.now()-n,z(e)})}return Y(e)?z(e):E.resolved()};z=function(e){return new E(function(t){f.pageInProgress.hasOverflowed()&&g()&&(f.pageInProgress.suppressErrors=!0,v());var n=h.beforeAddElement(e,f,v,m);p[0]?u(p).appendChild(n):f.pageInProgress.flowContent.appendChild(n),p.push(n);var r=[].concat(a(n.childNodes));n.innerHTML="",f.pageInProgress.hasOverflowed()&&g()&&y(n);var i=function(){var e=p.pop();h.afterAddElement(e,f,v,m,function(e){e.parentNode.removeChild(e),v(),u(p).appendChild(e)}),c+=1,f.estimatedProgress=c/s,t()},o=0;!function e(){if(o0&&void 0!==arguments[0]?arguments[0]:{};n(this,e),this.setSize(t.size||ie.size),this.setMargin(t.margin||ie.margin),this.setBleed(t.bleed||ie.bleed)}return r(e,[{key:"setupPaper",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.sheetSizeMode=oe?e.paper||Q.AUTO:Q.AUTO_MARKS,this.printTwoUp=e.layout&&e.layout!==ee.PAGES}},{key:"setSize",value:function(e){p(e),this.size=e}},{key:"setMargin",value:function(e){p(e),this.margin=e}},{key:"setBleed",value:function(e){this.bleed=e}},{key:"setPrintTwoUp",value:function(e){this.printTwoUp=e}},{key:"isSizeValid",value:function(){return this.updateStylesheet(),P.isSizeValid()}},{key:"spreadSizeStyle",value:function(){var e=f(this.size.width);return{height:this.size.height,width:""+2*e.val+e.unit}}},{key:"updateStylesheet",value:function(){var e=void 0,t=document.querySelector("#binderyPageSetup");t?e=t:(e=document.createElement("style")).id="binderyPageSetup";var n=f(this.size.width);e.innerHTML="\n@page { size: "+this.sheetSize.width+" "+this.sheetSize.height+"; }\n"+k(".print-page")+" { width: "+this.sheetSize.width+"; height: "+this.sheetSize.height+";}\n\n"+k(".show-crop")+" "+k(".print-page")+" "+k(".spread-wrapper")+",\n"+k(".show-bleed-marks")+" "+k(".print-page")+" "+k(".spread-wrapper")+" {\n margin: calc("+this.bleed+" + 12pt) auto;\n}\nhtml {\n --bindery-page-width: "+this.size.width+";\n --bindery-page-height: "+this.size.height+";\n}\n"+k(".page-size-rotated")+" {\n height: "+this.size.width+";\n width: "+this.size.height+";\n}\n"+k(".spread-size")+" {\n height: "+this.size.height+";\n width: "+2*n.val+n.unit+";\n}\n"+k(".spread-size-rotated")+" {\n height: "+2*n.val+n.unit+";\n width: "+this.size.height+";\n}\n"+k(".flowbox")+",\n"+k(".footer")+" {\n margin-left: "+this.margin.inner+";\n margin-right: "+this.margin.outer+";\n}\n"+k(".left")+" "+k(".flowbox")+",\n"+k(".left")+" "+k(".footer")+" {\n margin-left: "+this.margin.outer+";\n margin-right: "+this.margin.inner+";\n}\n\n"+k(".left")+" "+k(".running-header")+" {\n left: "+this.margin.outer+";\n}\n"+k(".right")+" "+k(".running-header")+" {\n right: "+this.margin.outer+";\n}\n\n"+k(".flowbox")+" { margin-top: "+this.margin.top+"; }\n"+k(".footer")+"{ margin-bottom: "+this.margin.bottom+"; }\n\n"+k(".bleed-left")+",\n"+k(".bleed-right")+",\n"+k(".crop-left")+",\n"+k(".crop-right")+",\n"+k(".crop-fold")+" {\n top: calc( -12pt - "+this.bleed+" );\n bottom: calc( -12pt - "+this.bleed+" );\n}\n\n"+k(".bleed-top")+",\n"+k(".bleed-bottom")+",\n"+k(".crop-top")+",\n"+k(".crop-bottom")+" {\n left: calc( -12pt - "+this.bleed+" );\n right: calc( -12pt - "+this.bleed+" );\n}\n"+k(".bleed-left")+" { left: -"+this.bleed+"; }\n"+k(".bleed-right")+" { right: -"+this.bleed+"; }\n"+k(".bleed-top")+" { top: -"+this.bleed+"; }\n"+k(".bleed-bottom")+" { bottom: -"+this.bleed+"; }\n\n"+k(".background")+" {\n top: -"+this.bleed+";\n bottom: -"+this.bleed+";\n left: -"+this.bleed+";\n right: -"+this.bleed+";\n}\n\n"+k(".spread")+k(".right")+" > "+k(".background")+" {\n left: calc(-100% - "+this.bleed+");\n}\n"+k(".spread")+k(".left")+" > "+k(".background")+" {\n right: calc(-100% - "+this.bleed+");\n}\n ",document.head.appendChild(e)}},{key:"displaySize",get:function(){return{width:this.printTwoUp?this.spreadSizeStyle().width:this.size.width,height:this.size.height,bleed:this.bleed}}},{key:"sheetSize",get:function(){var e=this.printTwoUp?this.spreadSizeStyle().width:this.size.width,t=this.size.height,n=this.bleed;switch(this.sheetSizeMode){case Q.AUTO:return{width:e,height:t};case Q.AUTO_BLEED:return{width:"calc("+e+" + "+n+" + "+n+")",height:"calc("+t+" + "+n+" + "+n+")"};case Q.AUTO_MARKS:return{width:"calc("+e+" + "+n+" + "+n+" + 24pt)",height:"calc("+t+" + "+n+" + "+n+" + 24pt)"};case Q.LETTER_LANDSCAPE:return{width:ne.height,height:ne.width};case Q.LETTER_PORTRAIT:return ne;case Q.A4_PORTRAIT:return re;case Q.A4_LANDSCAPE:return{width:re.height,height:re.width}}return{width:e,height:t}}}]),e}(),ae=function(t,n){return C(".error",[C(".error-title",t),C(".error-text",n),C(".error-footer","Bindery "+e)])},le=function(e,t){for(;e.length%4!=0;){var n=t();n.element.style.visibility="hidden",e.push(n)}for(var r=[],i=e.length,o=0;o60&&(a=60/e.length),i.style.width=e.length*a+"px";for(var l=function(e){var t=e;t===s&&(t+=1),s=t;var n=4;o.length*n>200&&(n=200/o.length),o.forEach(function(e,r,i){var o=(i.length-Math.abs(r-t+.5))*n;e.style.transform="translate3d("+(rDefault Replacement'),e}}]),t}(),Te=function(e){function t(e){n(this,t);var r=s(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return b.validate(e,{name:"Footnote",selector:b.string,replace:b.func,render:b.func}),r}return o(t,Oe),r(t,[{key:"afterAdd",value:function(e,n,r,o,s){var a=n.pageInProgress.footer.children.length+1,l=C(".footnote"),u=this.render(e,a);return u instanceof HTMLElement?l.appendChild(u):l.innerHTML=u,n.pageInProgress.footer.appendChild(l),i(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"afterAdd",this).call(this,e,n,r,o,function(e){return n.pageInProgress.footer.removeChild(l),s(e)})}},{key:"createReplacement",value:function(e,t){var n=e.pageInProgress.footer.children.length;return this.replace(t,n)}},{key:"replace",value:function(e,t){return e.insertAdjacentHTML("beforeEnd",''+t+""),e}},{key:"render",value:function(e,t){return""+t+" Default footnote (Learn how to change it)"}}]),t}(),Ae=function(e){function t(e){n(this,t);var r=s(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return b.validate(e,{name:"PageReference",selector:b.string,replace:b.func,createTest:b.func}),r}return o(t,Oe),r(t,[{key:"afterAdd",value:function(e,t){var n=this,r=this.createTest(e);if(r){var i=e.parentNode,o=e.cloneNode(!0),s=t.pagesForTest(r),a=c(s),l=this.replace(o,a||"###");return l.classList.add(k("placeholder-pulse")),i.replaceChild(l,e),t.onComplete(function(){var i=l.parentNode,o=e.cloneNode(!0),s=t.pagesForTest(r),a=c(s),u=n.replace(o,a);i.replaceChild(u,l)}),l}return e}},{key:"createTest",value:function(e){var t=e.getAttribute("href");return t?(t=t.replace("#",""),t='[id="'+t+'"]',function(e){return e.querySelector(t)}):null}},{key:"replace",value:function(e,t){return e.insertAdjacentHTML("beforeend",", "+t+""),e}}]),t}(),ze=function(e){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};n(this,t);var r=s(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return b.validate(e,{name:"RunningHeader",render:b.func}),r}return o(t,A),r(t,[{key:"eachPage",value:function(e){if(!e.runningHeader){var t=C(".running-header");e.element.appendChild(t),e.runningHeader=t}e.runningHeader.innerHTML=this.render(e)}},{key:"render",value:function(e){return e.number}}]),t}(),Le={Rule:A,Split:function(e){return new xe(e)},Counter:function(e){return new Ee(e)},FullBleedPage:function(e){return new L(e)},Footnote:function(e){return new Te(e)},RunningHeader:function(e){return new ze(e)},Replace:function(e){return new Oe(e)},FullBleedSpread:function(e){return new R(e)},PageBreak:function(e){return new B(e)},PageReference:function(e){return new Ae(e)},createRule:function(e){return new A(e)}},Re=Le.PageBreak,Be=Le.PageReference,_e=Le.Footnote,Ie=Le.FullBleedPage,Ne=Le.FullBleedSpread,Fe=function(e,t){return e.textContent=""+t,e},Me=[Re({selector:'[book-page-break="both"]',position:"both"}),Re({selector:'[book-page-break="avoid"]',position:"avoid"}),Re({selector:'[book-page-break="after"][book-page-continue="right"]',position:"after",continue:"right"}),Re({selector:'[book-page-break="after"][book-page-continue="left"]',position:"after",continue:"left"}),Re({selector:'[book-page-break="after"][book-page-continue="next"]',position:"after",continue:"next"}),Re({selector:'[book-page-break="before"][book-page-continue="right"]',position:"before",continue:"right"}),Re({selector:'[book-page-break="before"][book-page-continue="left"]',position:"before",continue:"left"}),Re({selector:'[book-page-break="before"][book-page-continue="next"]',position:"before",continue:"next"}),Ie({selector:'[book-full-bleed="page"]'}),Ne({selector:'[book-full-bleed="spread"]'}),_e({selector:"[book-footnote-text]",render:function(e,t){return""+t+""+e.getAttribute("book-footnote-text")}}),Be({selector:"[book-pages-with-text]",replace:Fe,createTest:function(e){var t=e.getAttribute("book-pages-with-text").toLowerCase().trim();return function(e){return e.textContent.toLowerCase().includes(t)}}}),Be({selector:"[book-pages-with-selector]",replace:Fe,createTest:function(e){var t=e.getAttribute("book-pages-with-selector").trim();return function(e){return e.querySelector(t)}}}),Be({selector:"[book-pages-with]",replace:Fe,createTest:function(e){var t=e.textContent.toLowerCase().trim();return function(e){return e.textContent.toLowerCase().includes(t)}}})];!function(e){if(e&&"undefined"!=typeof window){var t=document.createElement("style");t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t)}}('@charset "UTF-8";@media screen{.📖-page{background:#fff;outline:1px solid #ddd;box-shadow:0 2px 4px -1px rgba(0,0,0,.15);overflow:hidden}.📖-show-bleed .📖-page{box-shadow:none;outline:none;overflow:visible}.📖-page:after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;z-index:3}}li.📖-continuation,p.📖-continuation{text-indent:unset!important}li.📖-continuation{list-style:none!important}.📖-out-of-flow{display:none}.📖-page{width:var(--bindery-page-width);height:var(--bindery-page-height);position:relative;display:flex;flex-direction:column;flex-wrap:nowrap}.📖-flowbox{position:relative;margin:60px 40px;margin-bottom:0;flex:1 1 auto;min-height:0}.📖-content{padding:.1px;position:relative}.📖-footer{margin:60px 40px;margin-top:8pt;flex:0 1 auto;z-index:1}.📖-background{position:absolute;z-index:0;overflow:hidden}.📖-left>.📖-background{right:0}.📖-right>.📖-background{left:0}.📖-sup{font-size:.667em}.📖-footer,.📖-running-header{font-size:10pt}.📖-running-header{position:absolute;text-align:center;top:.25in}.📖-left .📖-running-header{left:18pt;text-align:left}.📖-right .📖-running-header{right:18pt;text-align:right}.📖-left .📖-rotate-container.📖-rotate-outward,.📖-left .📖-rotate-container.📖-rotate-spread-clockwise,.📖-right .📖-rotate-container.📖-rotate-inward,.📖-rotate-container.📖-rotate-clockwise{transform:rotate(90deg) translate3d(0,-100%,0);transform-origin:top left}.📖-left .📖-rotate-container.📖-rotate-inward,.📖-left .📖-rotate-container.📖-rotate-spread-counterclockwise,.📖-right .📖-rotate-container.📖-rotate-outward,.📖-rotate-container.📖-rotate-counterclockwise{transform:rotate(-90deg) translate3d(-100%,0,0);transform-origin:top left}.📖-rotate-container{position:absolute}.📖-left .📖-rotate-container.📖-rotate-clockwise .📖-background{bottom:0}.📖-left .📖-rotate-container.📖-rotate-counterclockwise .📖-background,.📖-right .📖-rotate-container.📖-rotate-clockwise .📖-background{top:0}.📖-right .📖-rotate-container.📖-rotate-counterclockwise .📖-background,.📖-rotate-container.📖-rotate-inward .📖-background{bottom:0}.📖-rotate-container.📖-rotate-outward .📖-background{top:0}.📖-right .📖-rotate-container.📖-rotate-spread-clockwise{transform:rotate(90deg) translate3d(0,-50%,0);transform-origin:top left}.📖-right .📖-rotate-container.📖-rotate-spread-counterclockwise{transform:rotate(-90deg) translate3d(-100%,-50%,0);transform-origin:top left}@media screen{.📖-viewing{background:#f4f4f4!important}.📖-root{transition:opacity .2s;opacity:1;background:#f4f4f4;padding:10px;z-index:2;position:relative;padding-top:60px;min-height:90vh}.📖-progress-bar{position:fixed;left:0;top:0;background:var(--bindery-ui-accent,#0000c5);width:0;transition:all .2s;opacity:0;height:0;z-index:2}.📖-in-progress .📖-progress-bar{opacity:1;height:2px}.📖-measure-area{position:fixed;background:#f4f4f4;padding:50px 20px;z-index:2;visibility:hidden;left:0;right:0;bottom:0}.📖-measure-area .📖-page{margin:0 auto 50px}.📖-is-overflowing{border-bottom:1px solid #f0f}.📖-print-page{margin:0 auto}.📖-error{font:16px/1.4 -apple-system,BlinkMacSystemFont,Roboto,sans-serif;padding:15vh 15vw;z-index:3;position:fixed;top:0;left:0;right:0;bottom:0;background:hsla(0,0%,96%,.7)}.📖-error-title{font-size:1.5em;margin-bottom:16px}.📖-error-text{margin-bottom:16px;white-space:pre-line}.📖-error-footer{opacity:.5;font-size:.66em;text-transform:uppercase;letter-spacing:.02em}.📖-show-bleed .📖-print-page{background:#fff;outline:1px solid rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.2);margin:20px auto}.📖-placeholder-pulse{animation:pulse 1s infinite}}@keyframes pulse{0%{opacity:.2}50%{opacity:.5}to{opacity:.2}}@page{margin:0}@media print{.📖-root *{-webkit-print-color-adjust:exact;color-adjust:exact}.📖-controls,.📖-viewing>:not(.📖-root){display:none!important}.📖-print-page{padding:1px;margin:0 auto}.📖-zoom-wrap[style]{transform:none!important}}body.📖-viewing{margin:0}.📖-zoom-wrap{transform-origin:top left;transform-style:preserve-3d;height:calc(100vh - 120px)}[bindery-view-mode=interactive] .📖-zoom-wrap{transform-origin:center left}.📖-viewing>:not(.📖-root):not(.📖-measure-area){display:none!important}.📖-print-page{page-break-after:always;overflow:hidden;align-items:center;transition:all .2s}.📖-print-page,.📖-spread-wrapper{position:relative;display:flex;justify-content:center}.📖-spread-wrapper{margin:0 auto 32px}.📖-print-page .📖-spread-wrapper{margin:0 auto}.📖-flap-holder{perspective:5000px;position:absolute;top:0;right:0;left:0;bottom:0;margin:auto;transform-style:preserve-3d}.📖-flip-sizer{position:relative;margin:auto;padding:0 20px;box-sizing:content-box;height:100%!important}.📖-page3d{margin:auto;width:var(--bindery-page-width);height:var(--bindery-page-height);transform:rotateY(0);transform-style:preserve-3d;transform-origin:left;transition:transform .5s,box-shadow .1s;position:absolute;left:0;right:0;top:0;bottom:0}.📖-page3d:hover{box-shadow:2px 0 4px rgba(0,0,0,.2)}.📖-page3d.flipped{transform:rotateY(-180deg)}.📖-page3d .📖-page{position:absolute;backface-visibility:hidden;-webkit-backface-visibility:hidden;box-shadow:none}.📖-page3d .📖-page3d-front{transform:rotateY(0)}.📖-page3d .📖-page3d-back{transform:rotateY(-180deg)}.📖-print-mark-wrap{display:none;position:absolute;pointer-events:none;top:0;bottom:0;left:0;right:0;z-index:3}.📖-show-bleed-marks .📖-print-mark-wrap,.📖-show-bleed-marks .📖-print-mark-wrap>[class*=bleed],.📖-show-crop .📖-print-mark-wrap,.📖-show-crop .📖-print-mark-wrap>[class*=crop]{display:block}.📖-print-mark-wrap>div{display:none;position:absolute;overflow:hidden}.📖-print-mark-wrap>div:after,.📖-print-mark-wrap>div:before{content:"";display:block;position:absolute}.📖-print-mark-wrap>div:before{top:0;left:0}.📖-print-mark-wrap>div:after{bottom:0;right:0}.📖-bleed-left,.📖-bleed-right,.📖-crop-fold,.📖-crop-left,.📖-crop-right{width:1px;margin:auto}.📖-bleed-left:after,.📖-bleed-left:before,.📖-bleed-right:after,.📖-bleed-right:before,.📖-crop-fold:after,.📖-crop-fold:before,.📖-crop-left:after,.📖-crop-left:before,.📖-crop-right:after,.📖-crop-right:before{width:1px;height:12pt;background-image:linear-gradient(90deg,#000 0,#000 51%,transparent 0);background-size:1px 100%}.📖-bleed-bottom,.📖-bleed-top,.📖-crop-bottom,.📖-crop-top{height:1px}.📖-bleed-bottom:after,.📖-bleed-bottom:before,.📖-bleed-top:after,.📖-bleed-top:before,.📖-crop-bottom:after,.📖-crop-bottom:before,.📖-crop-top:after,.📖-crop-top:before{width:12pt;height:1px;background-image:linear-gradient(180deg,#000 0,#000 51%,transparent 0);background-size:100% 1px}.📖-crop-fold{right:0;left:0}.📖-crop-left{left:0}.📖-crop-right{right:0}.📖-crop-top{top:0}.📖-crop-bottom{bottom:0}.📖-print-meta{padding:12pt;text-align:center;font-family:-apple-system,BlinkMacSystemFont,Roboto,sans-serif;font-size:8pt;display:block!important;position:absolute;bottom:-60pt;left:0;right:0}');var je=function(){function i(){var r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};n(this,i),console.log("📖 Bindery "+e),this.autorun=r.autorun||!0,this.autoupdate=r.autoupdate||!1,x.isDebugging=r.debug||v("debug")||!1,b.validate(r,{name:"makeBook",autorun:b.bool,content:b.any,ControlsComponent:b.any,pageSetup:b.shape({name:"pageSetup",bleed:b.length,margin:b.shape({name:"margin",top:b.length,inner:b.length,outer:b.length,bottom:b.length}),size:b.shape({name:"size",width:b.length,height:b.length})}),view:b.enum.apply(b,a(Object.values($))),printSetup:b.shape({name:"printSetup",layout:b.enum.apply(b,a(Object.values(ee))),marks:b.enum.apply(b,a(Object.values(te))),paper:b.enum.apply(b,a(Object.values(Q)))}),rules:b.array}),this.pageSetup=new se(r.pageSetup),this.pageSetup.setupPaper(r.printSetup);var o=r.printSetup?r.printSetup.layout||ee.PAGES:ee.PAGES,s=r.printSetup?r.printSetup.marks||te.CROP:te.CROP;if(this.viewer=new Se({bindery:this,mode:r.view||$.PREVIEW,marks:s,layout:o,ControlsComponent:r.ControlsComponent}),this.rules=Me,r.rules&&this.addRules(r.rules),r.content)if("string"==typeof r.content){if(this.source=document.querySelector(r.content),!(this.source instanceof HTMLElement))return this.viewer.displayError("Content not specified",'Could not find element that matches selector "'+r.content+'"'),void console.error('Bindery: Could not find element that matches selector "'+r.content+'"');this.autorun&&this.makeBook()}else if("object"===t(r.content)&&r.content.url){var l=r.content.url,u=r.content.selector;this.fetchSource(l,u)}else r.content instanceof HTMLElement?(this.source=r.content,this.autorun&&this.makeBook()):console.error("Bindery: Source must be an element or selector");else this.viewer.displayError("Content not specified","You must include a source element, selector, or url"),console.error("Bindery: You must include a source element or selector")}return r(i,[{key:"fetchSource",value:function(e,t){var n=this;fetch(e).then(function(t){if(404===t.status)n.viewer.displayError("404",'Could not find file at "'+e+'"');else if(200===t.status)return t.text();return""}).then(function(e){var r=document.createElement("div");if(r.innerHTML=e,n.source=r.querySelector(t),!(n.source instanceof HTMLElement))return n.viewer.displayError("Source not specified",'Could not find element that matches selector "'+t+'"'),void console.error('Bindery: Could not find element that matches selector "'+t+'"');n.autorun&&n.makeBook()}).catch(function(t){console.error(t),"file"===window.location.href.split("://")[0]&&n.viewer.displayError("Can't fetch content from \""+e+'"',"Web pages can't fetch content unless they are on a server.")})}},{key:"cancel",value:function(){this.viewer.cancel(),document.body.classList.remove(k("viewing")),this.source.style.display=""}},{key:"addRules",value:function(e){var t=this;e.forEach(function(e){if(!(e instanceof Le.Rule))throw Error("Bindery: The following is not an instance of Bindery.Rule and will be ignored: "+e);t.rules.push(e)})}},{key:"updateBookSilent",value:function(){var e=this;this.layoutComplete=!1,this.source.style.display="";var t=this.source.cloneNode(!0);this.source.style.display="none",document.body.classList.add(k("viewing")),this.pageSetup.updateStylesheet(),X({content:t,rules:this.rules,success:function(t){e.viewer.book=t,e.viewer.render(),e.layoutComplete=!0},progress:function(){},error:function(t){e.layoutComplete=!0,e.viewer.displayError("Layout failed",t)}})}},{key:"makeBook",value:function(e){var t=this;if(this.source){if(this.layoutComplete=!1,!this.pageSetup.isSizeValid())return this.viewer.displayError("Page is too small","Size: "+JSON.stringify(this.pageSize)+" \n Margin: "+JSON.stringify(this.pageMargin)+" \n Try adjusting the sizes or units."),void console.error("Bindery: Cancelled pagination. Page is too small.");this.source.style.display="";var n=this.source.cloneNode(!0);this.source.style.display="none",this.viewer.clear(),document.body.classList.add(k("viewing")),x.isDebugging&&document.body.classList.add(k("debug")),this.pageSetup.updateStylesheet(),this.viewer.setInProgress(),X(n,this.rules).progress(function(e){t.viewer.renderProgress(e)}).then(function(n){t.viewer.book=n,t.viewer.render(),t.layoutComplete=!0,e&&e(),t.viewer.element.classList.remove(k("in-progress")),document.body.classList.remove(k("debug"))}).catch(function(e){t.layoutComplete=!0,t.viewer.element.classList.remove(k("in-progress")),t.viewer.displayError("Layout couldn't complete",e)})}else document.body.classList.add(k("viewing"))}}],[{key:"makeBook",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return e.autorun=!e.autorun||e.autorun,new i(e)}}]),i}();je.version=e;var De=Object.assign(je,Le);return De.View=$,De.Paper=Q,De.Layout=ee,De.Marks=te,De}(); +//# sourceMappingURL=bindery.min.js.map diff --git a/libreto/assets/js/bindery.umd.js b/libreto/assets/js/bindery.umd.js new file mode 100644 index 0000000..b2b11c4 --- /dev/null +++ b/libreto/assets/js/bindery.umd.js @@ -0,0 +1,3142 @@ +/* 📖 Bindery v2.1.0 */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Bindery = factory()); +}(this, (function () { 'use strict'; + +var BINDERY_VERSION = 'v2.1.0' + +function ___$insertStyle(css) { + if (!css) { + return; + } + if (typeof window === 'undefined') { + return; + } + + var style = document.createElement('style'); + + style.setAttribute('type', 'text/css'); + style.innerHTML = css; + document.head.appendChild(style); + + return css; +} + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + + + + + + + + + + + +var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; + +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); + + + + + + + +var get = function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } +}; + +var inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; +}; + + + + + + + + + + + +var possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; +}; + + + + + + + + + + + + + + + + + + + +var toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +var Book = function () { + function Book() { + classCallCheck(this, Book); + + this.pages = []; + this.queued = []; + this.isComplete = false; + this.estimatedProgress = 0; + } + + createClass(Book, [{ + key: "pagesForSelector", + + + // arguments: selector : String + // return: pages : [ Int ] + // if no matches: [] + value: function pagesForSelector(sel) { + return this.pagesForTest(function (page) { + return page.element.querySelector(sel); + }); + } + // arguments: testFunc : (element) => bool + // return: pages : [ Int ] + // if no matches: [] + + }, { + key: "pagesForTest", + value: function pagesForTest(testFunc) { + return this.pages.filter(function (pg) { + return testFunc(pg.element); + }).map(function (pg) { + return pg.number; + }); + } + }, { + key: "onComplete", + value: function onComplete(func) { + if (!this.isComplete) this.queued.push(func);else func(); + } + }, { + key: "setCompleted", + value: function setCompleted() { + this.isComplete = true; + this.estimatedProgress = 1; + this.queued.forEach(function (func) { + func(); + }); + this.queued = []; + } + }, { + key: "pageCount", + get: function get$$1() { + return this.pages.length; + } + }]); + return Book; +}(); + +var last = function last(arr) { + return arr[arr.length - 1]; +}; + +var makeRanges = function makeRanges(arr) { + var str = ''; + var prevNum = arr[0]; + var isInARange = false; + arr.forEach(function (num, i) { + var isLast = i === arr.length - 1; + var isAdjacent = num === prevNum + 1; + + if (i === 0) { + str += '' + num; + } else if (isLast) { + if (isAdjacent) { + str += '\u2013' + num; + } else if (isInARange) { + str += '\u2013' + prevNum + ', ' + num; + } else { + str += ', ' + num; + } + } else if (isAdjacent) { + isInARange = true; + } else if (isInARange && !isAdjacent) { + isInARange = false; + str += '\u2013' + prevNum + ', ' + num; + } else { + str += ', ' + num; + } + prevNum = num; + }); + // return `${str} - [${arr}]`; + return str; +}; + +var cssNumberRegEx = /^([+-]?[0-9]+(.?[0-9]+)?)(px|in|cm|mm|pt|pc)$/; + +var isValidLength = function isValidLength(str) { + return cssNumberRegEx.test(str); +}; +var isValidSize = function isValidSize(size) { + Object.keys(size).forEach(function (k) { + if (!isValidLength(size[k])) { + if (typeof size[k] === 'number') { + throw Error('Size is missing units { ' + k + ': ' + size[k] + ' }'); + } else { + throw Error('Invalid size { ' + k + ': ' + size[k] + ' }'); + } + } + }); +}; + +var parseVal = function parseVal(str) { + var matches = str.match(cssNumberRegEx); + return { + val: Number(matches[1]), + unit: matches[3] + }; +}; + +var validate = function validate(opts, validOpts) { + var isValid = true; + Object.keys(opts).forEach(function (k) { + if (!validOpts[k]) { + console.error('Bindery: \'' + validOpts.name + '\' doesn\'t have property \'' + k + '\''); + isValid = false; + } else { + var val = opts[k]; + var checker = validOpts[k]; + if (!checker(val)) { + console.error('Bindery: For property \'' + validOpts.name + '.' + k + '\', ' + JSON.stringify(val) + ' is not a valid value of type ' + checker.name); + isValid = false; + } + } + }); + return isValid; +}; + +var isObj = function isObj(val) { + return (typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object'; +}; +var isFunc = function isFunc(val) { + return typeof val === 'function'; +}; +var isBool = function isBool(val) { + return typeof val === 'boolean'; +}; +var isStr = function isStr(val) { + return typeof val === 'string'; +}; +var isArr = function isArr(val) { + return Array.isArray(val); +}; + +var OptionType = { + enum: function _enum() { + for (var _len = arguments.length, enumCases = Array(_len), _key = 0; _key < _len; _key++) { + enumCases[_key] = arguments[_key]; + } + + var enumCheck = function enumCheck(str) { + return enumCases.includes(str); + }; + Object.defineProperty(enumCheck, 'name', { writable: true }); + enumCheck.name = 'enum ( \'' + enumCases.join('\' | \'') + '\' )'; + return enumCheck; + }, + any: function any() { + return true; + }, + + string: isStr, + length: isValidLength, + bool: isBool, + func: isFunc, + obj: isObj, + array: isArr, + shape: function shape(validShape) { + return function (userShape) { + return isObj(userShape) && validate(userShape, validShape); + }; + }, + + validate: validate +}; + +// via https://css-tricks.com/snippets/javascript/get-url-variables/ +var urlQuery = (function (variable) { + var query = window.location.search.substring(1); + var vars = query.split('&'); + for (var i = 0; i < vars.length; i += 1) { + var pair = vars[i].split('='); + if (pair[0] === variable) { + return pair[1]; + } + } + return false; +}); + +// const p = 'bindery-'; +var p = '📖-'; + +var prefix = function prefix(str) { + return '' + p + str; +}; +var prefixClass = function prefixClass(str) { + return '.' + prefix(str); +}; + +var c = function c(str) { + if (str[0] === '.') { + return prefixClass(str.substr(1)); + } + return prefix(str); +}; + +// Small utility to create div with namespaced classes +var el = function el(className) { + var content = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + + var div = document.createElement('div'); + div.className = className.split('.').filter(function (txt) { + return txt !== ''; + }).map(c).join(' '); + + if (typeof content === 'string') { + div.textContent = content; + } else if (Array.isArray(content)) { + content.forEach(function (child) { + return div.appendChild(child); + }); + } + return div; +}; + +var Page = function () { + function Page() { + classCallCheck(this, Page); + + this.flowContent = el('content'); + this.flowBox = el('flowbox', [this.flowContent]); + this.footer = el('footer'); + this.background = el('background'); + this.element = el('page', [this.background, this.flowBox, this.footer]); + } + + createClass(Page, [{ + key: 'overflowAmount', + value: function overflowAmount() { + var contentH = this.flowContent.offsetHeight; + var boxH = this.flowBox.offsetHeight; + + if (boxH === 0) { + throw Error('Bindery: Trying to flow into a box of zero height.'); + } + + return contentH - boxH; + } + }, { + key: 'hasOverflowed', + value: function hasOverflowed() { + return this.overflowAmount() > -5; + } + }, { + key: 'setLeftRight', + value: function setLeftRight(dir) { + if (dir === 'left') { + this.side = dir; + this.element.classList.remove(c('right')); + this.element.classList.add(c('left')); + } else if (dir === 'right') { + this.side = dir; + this.element.classList.remove(c('left')); + this.element.classList.add(c('right')); + } else { + throw Error('Bindery: Setting page to invalid direction' + dir); + } + } + }, { + key: 'setPreference', + value: function setPreference(dir) { + if (dir === 'left') this.alwaysLeft = true; + if (dir === 'right') this.alwaysRight = true; + } + }, { + key: 'suppressErrors', + get: function get$$1() { + return this.suppress || false; + }, + set: function set$$1(newVal) { + this.suppress = newVal; + if (newVal) { + this.element.classList.add(c('is-overflowing')); + } else { + this.element.classList.remove(c('is-overflowing')); + } + } + }, { + key: 'isEmpty', + get: function get$$1() { + return !this.hasOutOfFlowContent && this.flowContent.textContent.trim() === '' && this.flowContent.offsetHeight < 1; + } + }, { + key: 'isLeft', + get: function get$$1() { + return this.side === 'left'; + } + }, { + key: 'isRight', + get: function get$$1() { + return this.side === 'right'; + } + }], [{ + key: 'isSizeValid', + value: function isSizeValid() { + document.body.classList.remove(c('viewing')); + + var testPage = new Page(); + var measureArea = document.querySelector(c('.measure-area')); + if (!measureArea) measureArea = document.body.appendChild(el('measure-area')); + + measureArea.innerHTML = ''; + measureArea.appendChild(testPage.element); + var box = testPage.flowBox.getBoundingClientRect(); + + measureArea.parentNode.removeChild(measureArea); + + return box.height > 100 && box.width > 100; // TODO: Number is arbitrary + } + }]); + return Page; +}(); + +// TODO: Combine isSplittable and shouldIgnoreOverflow +// Walk up the tree to see if we are within +// an overflow-ignoring node +var shouldIgnoreOverflow = function shouldIgnoreOverflow(element) { + if (element.hasAttribute('data-ignore-overflow')) return true; + if (element.parentElement) return shouldIgnoreOverflow(element.parentElement); + return false; +}; + +// When there is no debugDelay, +// the throttler will occassionally use rAF +// to prevent stack overflow +// and browser lockup + +var MAX_CALLS = 800; +var MAX_TIME = 50; // ms + +var Scheduler = function () { + function Scheduler() { + classCallCheck(this, Scheduler); + + this.numberOfCalls = 0; + this.resumeLimit = Infinity; + this.callsSinceResume = 0; + this.queuedFunc = null; + this.isPaused = false; + this.useDelay = false; + this.delayTime = 100; + + this.lastWaitedTime = 0; + } + + createClass(Scheduler, [{ + key: 'throttle', + value: function throttle(func) { + var _this = this; + + this.callsSinceResume += 1; + + if (this.callsSinceResume > this.resumeLimit) { + this.endResume(); + } + + var handlerTime = performance.now() - this.lastWaitedTime; + + if (this.isPaused) { + this.queuedFunc = func; + } else if (this.useDelay) { + setTimeout(func, this.delayTime); + } else if (this.numberOfCalls < MAX_CALLS && handlerTime < MAX_TIME) { + this.numberOfCalls += 1; + func(); + } else { + this.numberOfCalls = 0; + if (document.hidden) { + // Tab in background + setTimeout(func, 1); + } else { + requestAnimationFrame(function (t) { + _this.lastWaitedTime = t; + func(); + }); + } + } + } + }, { + key: 'pause', + value: function pause() { + if (this.isPaused) return 'Already paused'; + this.isPaused = true; + return 'Paused'; + } + }, { + key: 'resumeDelay', + value: function resumeDelay() { + this.useDelay = true; + this.resume(); + } + }, { + key: 'finish', + value: function finish() { + this.useDelay = false; + this.resume(); + } + }, { + key: 'resume', + value: function resume() { + if (this.isPaused) { + this.isPaused = false; + if (this.queuedFunc) { + this.queuedFunc(); + this.queuedFunc = null; + } else { + return 'Layout complete'; + } + return 'Resuming'; + } + return 'Already running'; + } + }, { + key: 'step', + value: function step() { + if (!this.isPaused) { + return this.pause(); + } + if (this.queuedFunc) { + var queued = this.queuedFunc; + var n = queued.name; + this.queuedFunc = null; + queued(); + return n; + } + return 'Layout complete'; + } + }, { + key: 'resumeFor', + value: function resumeFor(n) { + this.callsSinceResume = 0; + this.resumeLimit = n; + return this.resume(); + } + }, { + key: 'endResume', + value: function endResume() { + console.log('Paused after ' + this.resumeLimit); + this.resumeLimit = Infinity; + this.callsSinceResume = 0; + this.pause(); + } + }, { + key: 'isDebugging', + get: function get$$1() { + return this.useDelay; + }, + set: function set$$1(newValue) { + this.useDelay = newValue; + if (newValue) { + window.binderyDebug = { + pause: this.pause.bind(this), + resume: this.resume.bind(this), + resumeFor: this.resumeFor.bind(this), + step: this.step.bind(this), + finish: this.finish.bind(this) + }; + console.log('Bindery: Debug layout with the following: \nbinderyDebug.pause() \nbinderyDebug.resume()\n binderyDebug.resumeFor(n) // pauses after n steps, \nbinderyDebug.step()'); + } + } + }]); + return Scheduler; +}(); + +var scheduler = new Scheduler(); + +// promise-inspired thenable. +// really just to make callbacks cleaner, +// not guarenteed to be asynchronous. +// (if then and catch aren't registered yet, +// it waits until they are). + +var Thenable = function () { + function Thenable(func) { + classCallCheck(this, Thenable); + + this.successArgs = []; + this.errorArgs = []; + + this.successCallback = null; + this.errorCallback = null; + this.progressCallback = null; + + this.chainedThenable = null; + this.chainedSuccessCallback = null; + this.chainedErrorCallback = null; + + this.isRejected = false; + this.isResolved = false; + + this.resolve = this.resolve.bind(this); + this.reject = this.reject.bind(this); + this.updateProgress = this.updateProgress.bind(this); + + if (func) func(this.resolve, this.reject, this.updateProgress); + } + + createClass(Thenable, [{ + key: 'then', + value: function then(func) { + if (this.chainedThenable) { + return this.chainedThenable.then(func); + } + + if (!this.successCallback) { + this.successCallback = func; + if (this.isResolved) this.resolve(); + return this; + } else if (!this.chainedSuccessCallback) { + this.chainedSuccessCallback = func; + if (this.isResolved) this.resolveChained(); + // console.log('attached chained then'); + return this; + } + throw Error('need real chained then'); + } + }, { + key: 'progress', + value: function progress(func) { + this.progressCallback = func; + return this; + } + }, { + key: 'catch', + value: function _catch(func) { + if (this.chainedThenable) { + return this.chainedThenable.catch(func); + } + + if (!this.errorCallback) { + this.errorCallback = func; + if (this.isRejected) this.reject(); + return this; + } else if (!this.chainedErrorCallback) { + this.chainedErrorCallback = func; + if (this.isRejected) this.rejectChained(); + // console.log('attached chained error'); + return this; + } + throw Error('need real chained catch'); + } + }, { + key: 'resolve', + value: function resolve() { + this.isResolved = true; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + if (args.length > 0) this.successArgs = args; + if (this.successCallback !== null) { + // console.log('applying then'); + var result = void 0; + if (this.successArgs.length > 0) { + result = this.successCallback.apply(this, toConsumableArray(this.successArgs)); + } else { + result = this.successCallback(); + } + if (result && result.then) this.chainedThenable = result; + if (this.chainedSuccessCallback) this.resolveChained(); + } else { + // console.log('waiting for then'); + } + } + }, { + key: 'resolveChained', + value: function resolveChained() { + if (this.chainedThenable) this.chainedThenable.then(this.chainedSuccessCallback);else this.chainedSuccessCallback(); + } + }, { + key: 'reject', + value: function reject() { + this.isRejected = true; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + if (args.length > 0) this.errorArgs = args; + if (this.errorCallback !== null) { + // console.log('applying catch'); + var result = void 0; + if (this.errorArgs.length > 0) { + result = this.errorCallback.apply(this, toConsumableArray(this.errorArgs)); + } else { + result = this.errorCallback(); + } + if (result && result.then) { + this.chainedThenable = result; + } + if (this.successCallback) { + if (result && result.then) { + // console.log('forwarded unused then'); + result.then(this.successCallback); + } + } + if (this.chainedSuccessCallback) { + if (result && result.then) { + // console.log('forwarded chained then'); + result.then(this.chainedSuccessCallback); + } else this.chainedSuccessCallback(); + } + if (this.chainedErrorCallback) this.rejectChained(); + } else { + // console.log('waiting for catch'); + } + } + }, { + key: 'rejectChained', + value: function rejectChained() { + if (this.chainedThenable) this.chainedThenable.catch(this.chainedErrorCallback);else this.chainedErrorCallback(); + } + }, { + key: 'updateProgress', + value: function updateProgress() { + if (this.progressCallback !== null) { + this.progressCallback.apply(this, arguments); + } + } + }], [{ + key: 'resolved', + value: function resolved() { + return new Thenable(function (resolve) { + return resolve(); + }); + } + }]); + return Thenable; +}(); + +// Try adding a text node in one go +var addTextNode = function addTextNode(textNode, parent, page) { + return new Thenable(function (resolve, reject) { + parent.appendChild(textNode); + + if (page.hasOverflowed()) { + parent.removeChild(textNode); + scheduler.throttle(reject); + } else { + scheduler.throttle(resolve); + } + }); +}; + +// Try adding a text node by incrementally adding words +// until it just barely doesnt overflow. +// Binary search would probably be better but its not currenty +// the bottleneck. +var addTextNodeIncremental = function addTextNodeIncremental(textNode, parent, page) { + return new Thenable(function (resolve, reject) { + var originalText = textNode.nodeValue; + parent.appendChild(textNode); + + if (!page.hasOverflowed() || shouldIgnoreOverflow(parent)) { + scheduler.throttle(resolve); + return; + } + + var pos = 0; + + var splitTextStep = function splitTextStep() { + textNode.nodeValue = originalText.substr(0, pos); + + if (page.hasOverflowed()) { + // Back out to word boundary + if (originalText.charAt(pos) === ' ') pos -= 1; // TODO: redundant + while (originalText.charAt(pos) !== ' ' && pos > 0) { + pos -= 1; + }if (pos < 1) { + textNode.nodeValue = originalText; + textNode.parentNode.removeChild(textNode); + scheduler.throttle(reject); + return; + } + + // console.log(`Text breaks at ${pos}: ${originalText.substr(0, pos)}`); + + var fittingText = originalText.substr(0, pos); + var overflowingText = originalText.substr(pos); + textNode.nodeValue = fittingText; + + // Start on new page + var remainingTextNode = document.createTextNode(overflowingText); + scheduler.throttle(function () { + return resolve(remainingTextNode); + }); + return; + } + if (pos > originalText.length - 1) { + scheduler.throttle(resolve); + return; + } + + pos += 1; + while (originalText.charAt(pos) !== ' ' && pos < originalText.length) { + pos += 1; + }scheduler.throttle(splitTextStep); + }; + + splitTextStep(); + }); +}; + +var Rule = function Rule(options) { + var _this = this; + + classCallCheck(this, Rule); + + this.name = options.name ? options.name : 'Unnamed Bindery Rule'; + this.selector = ''; + + Object.keys(options).forEach(function (key) { + _this[key] = options[key]; + }); +}; + +var OutOfFlow = function (_Rule) { + inherits(OutOfFlow, _Rule); + + function OutOfFlow(options) { + classCallCheck(this, OutOfFlow); + + var _this = possibleConstructorReturn(this, (OutOfFlow.__proto__ || Object.getPrototypeOf(OutOfFlow)).call(this, options)); + + _this.name = 'Out of Flow'; + return _this; + } + + createClass(OutOfFlow, [{ + key: 'beforeAdd', + value: function beforeAdd(elmt) { + // Avoid breaking inside this element. Once it's completely added, + // it will moved onto the background layer. + + elmt.setAttribute('data-ignore-overflow', true); + return elmt; + } + }, { + key: 'afterAdd', + value: function afterAdd(elmt, book, continueOnNewPage, makeNewPage) { + this.createOutOfFlowPages(elmt, book, makeNewPage); + + // Catches cases when we didn't need to create a new page. but unclear + if (this.continue !== 'same' || book.pageInProgress.hasOutOfFlowContent) { + continueOnNewPage(true); + if (this.continue === 'left' || this.continue === 'right') { + book.pageInProgress.setPreference(this.continue); + } + } + + return elmt; + } + }]); + return OutOfFlow; +}(Rule); + +// Options: +// selector: String + +var FullBleedPage = function (_OutOfFlow) { + inherits(FullBleedPage, _OutOfFlow); + + function FullBleedPage(options) { + classCallCheck(this, FullBleedPage); + + options.continue = options.continue || 'same'; + options.rotate = options.rotate || 'none'; + + var _this = possibleConstructorReturn(this, (FullBleedPage.__proto__ || Object.getPrototypeOf(FullBleedPage)).call(this, options)); + + OptionType.validate(options, { + name: 'FullBleedPage', + selector: OptionType.string, + continue: OptionType.enum('next', 'same', 'left', 'right'), + rotate: OptionType.enum('none', 'inward', 'outward', 'clockwise', 'counterclockwise') + }); + return _this; + } + + createClass(FullBleedPage, [{ + key: 'createOutOfFlowPages', + value: function createOutOfFlowPages(elmt, book, makeNewPage) { + elmt.parentNode.removeChild(elmt); + + var newPage = void 0; + if (book.pageInProgress.isEmpty) { + newPage = book.pageInProgress; + } else { + newPage = makeNewPage(); + book.pages.push(newPage); + } + if (this.rotate !== 'none') { + var rotateContainer = el('.rotate-container.page-size-rotated.rotate-' + this.rotate); + rotateContainer.appendChild(newPage.background); + newPage.element.appendChild(rotateContainer); + } + newPage.background.appendChild(elmt); + newPage.hasOutOfFlowContent = true; + } + }]); + return FullBleedPage; +}(OutOfFlow); + +// Options: +// selector: String + +var FullBleedSpread = function (_OutOfFlow) { + inherits(FullBleedSpread, _OutOfFlow); + + function FullBleedSpread(options) { + classCallCheck(this, FullBleedSpread); + + options.continue = options.continue || 'same'; + options.rotate = options.rotate || 'none'; + + var _this = possibleConstructorReturn(this, (FullBleedSpread.__proto__ || Object.getPrototypeOf(FullBleedSpread)).call(this, options)); + + OptionType.validate(options, { + name: 'FullBleedSpread', + selector: OptionType.string, + continue: OptionType.enum('next', 'same', 'left', 'right'), + rotate: OptionType.enum('none', 'clockwise', 'counterclockwise') + }); + return _this; + } + + createClass(FullBleedSpread, [{ + key: 'createOutOfFlowPages', + value: function createOutOfFlowPages(elmt, book, makeNewPage) { + var _this2 = this; + + elmt.parentNode.removeChild(elmt); + + var leftPage = void 0; + if (book.pageInProgress.isEmpty) { + leftPage = book.pageInProgress; + } else { + leftPage = makeNewPage(); + book.pages.push(leftPage); + } + + var rightPage = makeNewPage(); + book.pages.push(rightPage); + + if (this.rotate !== 'none') { + [leftPage, rightPage].forEach(function (page) { + var rotateContainer = el('.rotate-container.spread-size-rotated.rotate-spread-' + _this2.rotate); + rotateContainer.appendChild(page.background); + page.element.appendChild(rotateContainer); + }); + } + + leftPage.background.appendChild(elmt); + leftPage.element.classList.add(c('spread')); + leftPage.setPreference('left'); + leftPage.isOutOfFlow = this.continue === 'same'; + leftPage.hasOutOfFlowContent = true; + + rightPage.background.appendChild(elmt.cloneNode(true)); + rightPage.element.classList.add(c('spread')); + rightPage.setPreference('right'); + rightPage.isOutOfFlow = this.continue === 'same'; + rightPage.hasOutOfFlowContent = true; + } + }]); + return FullBleedSpread; +}(OutOfFlow); + +var PageBreak = function (_Rule) { + inherits(PageBreak, _Rule); + + function PageBreak(options) { + classCallCheck(this, PageBreak); + + options.position = options.position || 'before'; + options.continue = options.continue || 'next'; + + var _this = possibleConstructorReturn(this, (PageBreak.__proto__ || Object.getPrototypeOf(PageBreak)).call(this, options)); + + OptionType.validate(options, { + name: 'PageBreak', + selector: OptionType.string, + continue: OptionType.enum('next', 'left', 'right'), + position: OptionType.enum('before', 'after', 'both', 'avoid') + }); + return _this; + } + + createClass(PageBreak, [{ + key: 'beforeAdd', + value: function beforeAdd(elmt, book, continueOnNewPage) { + if (this.position === 'before' || this.position === 'both') { + if (!book.pageInProgress.isEmpty) { + continueOnNewPage(); + } + if (this.continue !== 'next') { + book.pageInProgress.setPreference(this.continue); + } + } + return elmt; + } + }, { + key: 'afterAdd', + value: function afterAdd(elmt, book, continueOnNewPage) { + if (this.position === 'after' || this.position === 'both') { + var newPage = continueOnNewPage(true); + if (this.continue !== 'next') { + newPage.setPreference(this.continue); + } + } + return elmt; + } + }, { + key: 'avoidSplit', + get: function get$$1() { + return this.position === 'avoid'; + } + }]); + return PageBreak; +}(Rule); + +var elementToString = function elementToString(node) { + var tag = node.tagName.toLowerCase(); + var id = node.id ? '#' + node.id : ''; + + var classes = ''; + if (node.classList.length > 0) { + classes = '.' + [].concat(toConsumableArray(node.classList)).join('.'); + } + + var text = ''; + if (id.length < 1 && classes.length < 2) { + text = '("' + node.textContent.substr(0, 30).replace(/\s+/g, ' ') + '...")'; + } + return tag + id + classes + text; +}; + +var isFullPageRule = function isFullPageRule(rule) { + return rule instanceof FullBleedSpread || rule instanceof FullBleedPage || rule instanceof PageBreak; +}; + +var dedupe = function dedupe(inputRules) { + var conflictRules = inputRules.filter(isFullPageRule); + var uniqueRules = inputRules.filter(function (rule) { + return !conflictRules.includes(rule); + }); + + var firstSpreadRule = conflictRules.find(function (rule) { + return rule instanceof FullBleedSpread; + }); + var firstPageRule = conflictRules.find(function (rule) { + return rule instanceof FullBleedPage; + }); + + // Only apply one fullpage or fullspread + if (firstSpreadRule) uniqueRules.push(firstSpreadRule);else if (firstPageRule) uniqueRules.push(firstPageRule);else uniqueRules.push.apply(uniqueRules, toConsumableArray(conflictRules)); // multiple pagebreaks are ok + + return uniqueRules; +}; + +var RuleSet = function () { + function RuleSet(rules) { + classCallCheck(this, RuleSet); + + this.rules = rules; + this.pageRules = rules.filter(function (r) { + return r.eachPage; + }); + this.beforeAddRules = rules.filter(function (r) { + return r.selector && r.beforeAdd; + }); + this.afterAddRules = rules.filter(function (r) { + return r.selector && r.afterAdd; + }); + this.selectorsNotToSplit = rules.filter(function (rule) { + return rule.avoidSplit; + }).map(function (rule) { + return rule.selector; + }); + } + + createClass(RuleSet, [{ + key: 'setup', + value: function setup() { + this.rules.forEach(function (rule) { + if (rule.setup) rule.setup(); + }); + } + }, { + key: 'startPage', + value: function startPage(pg, book) { + this.rules.forEach(function (rule) { + if (rule.afterPageCreated) rule.afterPageCreated(pg, book); + }); + } + }, { + key: 'finishEveryPage', + value: function finishEveryPage(book) { + this.pageRules.forEach(function (rule) { + book.pages.forEach(function (page) { + rule.eachPage(page, book); + }); + }); + } + }, { + key: 'finishPage', + value: function finishPage(page, book) { + this.pageRules.forEach(function (rule) { + rule.eachPage(page, book); + }); + } + }, { + key: 'beforeAddElement', + value: function beforeAddElement(element, book, continueOnNewPage, makeNewPage) { + var addedElement = element; + + var matchingRules = this.beforeAddRules.filter(function (rule) { + return addedElement.matches(rule.selector); + }); + // const uniqueRules = dedupeRules(matchingRules); + + matchingRules.forEach(function (rule) { + addedElement = rule.beforeAdd(addedElement, book, continueOnNewPage, makeNewPage); + }); + return addedElement; + } + }, { + key: 'afterAddElement', + value: function afterAddElement(originalElement, book, continueOnNewPage, makeNewPage, moveToNext) { + var addedElement = originalElement; + + var matchingRules = this.afterAddRules.filter(function (rule) { + return addedElement.matches(rule.selector); + }); + var uniqueRules = dedupe(matchingRules); + + // TODO: + // While this does catch overflows, it introduces a few new bugs. + // It is pretty aggressive to move the entire node to the next page. + // - 1. there is no guarentee it will fit on the new page + // - 2. if it has childNodes, those side effects will not be undone, + // which means footnotes will get left on previous page. + // - 3. if it is a large paragraph, it will leave a large gap. the + // ideal approach would be to only need to invalidate + // the last line of text. + + uniqueRules.forEach(function (rule) { + addedElement = rule.afterAdd(addedElement, book, continueOnNewPage, makeNewPage, function (problemElement) { + moveToNext(problemElement); + return rule.afterAdd(problemElement, book, continueOnNewPage, makeNewPage, function () { + console.log('Couldn\'t apply ' + rule.name + ' to ' + elementToString(problemElement) + '. Caused overflows twice.'); + }); + }); + }); + return addedElement; + } + }]); + return RuleSet; +}(); + +var indexOfNextInFlowPage = function indexOfNextInFlowPage(pages, startIndex) { + for (var i = startIndex; i < pages.length; i += 1) { + if (!pages[i].isOutOfFlow) { + return i; + } + } + return startIndex; +}; + +// Given an array of pages with alwaysLeft, alwaysRight, and isOutOfFlow +// properties. +// +// Orders them so that alwaysLeft and alwaysRight are true. + +// If the page is 'in flow', order must be respected, so extra blank pages +// are inserted. +// +// If the page is 'out of flow', we'd prefer not to add a blank page. +// Instead it floats backwards in the book, pulling the next +// in-flow page forward. If several 'out of flow' pages +// are next to each other, they will remain in order, all being pushed +// backward together. + + +var orderPages = function orderPages(pages, makeNewPage) { + var orderedPages = pages.slice(); + + for (var i = 0; i < orderedPages.length; i += 1) { + var page = orderedPages[i]; + var isLeft = i % 2 !== 0; + + if (isLeft && page.alwaysRight || !isLeft && page.alwaysLeft) { + if (page.isOutOfFlow) { + var indexToSwap = indexOfNextInFlowPage(orderedPages, i + 1); + var pageToMoveUp = orderedPages[indexToSwap]; + orderedPages.splice(indexToSwap, 1); + orderedPages.splice(i, 0, pageToMoveUp); + } else { + orderedPages.splice(i, 0, makeNewPage()); + } + } + } + return orderedPages; +}; + +var annotatePages = function annotatePages(pages) { + // ——— + // NUMBERING + + // TODO: Pass in facingpages options + var facingPages = true; + if (facingPages) { + pages.forEach(function (page, i) { + page.number = i + 1; + page.setLeftRight(i % 2 === 0 ? 'right' : 'left'); + }); + } else { + pages.forEach(function (page) { + page.setLeftRight('right'); + }); + } + + // ——— + // RUNNING HEADERS + + // Sections to annotate with. + // This should be a hierarchical list of selectors. + // Every time one is selected, it annotates all following pages + // and clears any subselectors. + // TODO: Make this configurable + var running = { h1: '', h2: '', h3: '', h4: '', h5: '', h6: '' }; + + pages.forEach(function (page) { + page.heading = {}; + Object.keys(running).forEach(function (tagName, i) { + var element = page.element.querySelector(tagName); + if (element) { + running[tagName] = element.textContent; + // clear remainder + Object.keys(running).forEach(function (tag, j) { + if (j > i) running[tag] = ''; + }); + } + if (running[tagName] !== '') { + page.heading[tagName] = running[tagName]; + } + }); + }); +}; + +// @param rules: array of Bindery.Rules +// @return: A new function that clones the given +// breadcrumb according to those rules. (original : Array) => clone : Array +// +// The breadcrumb is an array of nested elments, +// for example .content > article > p > a). +// +// It's shallowly cloned every time we move to the next page, +// to create the illusion that nodes are continuing from page +// to page. +// +// The transition can be customized by setting a Split rule, +// which lets you add classes to the original and cloned element +// to customize styling. + +var breadcrumbClone = function breadcrumbClone(origBreadcrumb, rules) { + var newBreadcrumb = []; + + // TODO check if element actually matches + var toNextClasses = rules.filter(function (rule) { + return rule.customToNextClass; + }).map(function (rule) { + return rule.customToNextClass; + }); + var fromPrevClasses = rules.filter(function (rule) { + return rule.customFromPreviousClass; + }).map(function (rule) { + return rule.customFromPreviousClass; + }); + + var markAsToNext = function markAsToNext(node) { + node.classList.add(c('continues')); + toNextClasses.forEach(function (cl) { + return node.classList.add(cl); + }); + }; + + var markAsFromPrev = function markAsFromPrev(node) { + node.classList.add(c('continuation')); + fromPrevClasses.forEach(function (cl) { + return node.classList.add(cl); + }); + }; + + for (var i = origBreadcrumb.length - 1; i >= 0; i -= 1) { + var original = origBreadcrumb[i]; + var clone = original.cloneNode(false); // shallow + clone.innerHTML = ''; + + markAsToNext(original); + markAsFromPrev(clone); + + // Special case for ordered lists + if (clone.tagName === 'OL') { + // restart numbering + var prevStart = 1; + if (original.hasAttribute('start')) { + // the OL is also a continuation + prevStart = parseInt(original.getAttribute('start'), 10); + } + if (i < origBreadcrumb.length - 1 && origBreadcrumb[i + 1].tagName === 'LI') { + // the first list item is a continuation + prevStart -= 1; + } + var prevCount = original.children.length; + var newStart = prevStart + prevCount; + clone.setAttribute('start', newStart); + } + + if (i < origBreadcrumb.length - 1) clone.appendChild(newBreadcrumb[i + 1]); + newBreadcrumb[i] = clone; + } + + return newBreadcrumb; +}; + +// Note: Doesn't ever reject, since missing images +// shouldn't prevent layout from resolving + +var waitForImage = function waitForImage(image) { + return new Thenable(function (resolve) { + var pollForSize = setInterval(function () { + if (image.naturalWidth) { + clearInterval(pollForSize); + resolve(); + } + }, 10); + + image.addEventListener('error', function () { + clearInterval(pollForSize); + resolve(); + }); + image.src = image.src; + }); +}; + +// Bindery +// paginate +// Utils +var MAXIMUM_PAGE_LIMIT = 2000; + +var isTextNode = function isTextNode(node) { + return node.nodeType === Node.TEXT_NODE; +}; +var isElement = function isElement(node) { + return node.nodeType === Node.ELEMENT_NODE; +}; +var isScript = function isScript(node) { + return node.tagName === 'SCRIPT'; +}; +var isImage = function isImage(node) { + return node.tagName === 'IMG'; +}; +var isUnloadedImage = function isUnloadedImage(node) { + return isImage(node) && !node.naturalWidth; +}; +var isContent = function isContent(node) { + return isElement(node) && !isScript(node); +}; + +var sec = function sec(ms) { + return (ms / 1000).toFixed(2); +}; + +// Walk up the tree to see if we can safely +// insert a split into this node. +var isSplittable = function isSplittable(element, selectorsNotToSplit) { + if (selectorsNotToSplit.some(function (sel) { + return element.matches(sel); + })) { + if (element.hasAttribute('data-bindery-did-move') || element.classList.contains(c('continuation'))) { + return true; // ignore rules and split it anyways. + } + return false; + } + if (element.parentElement) { + return isSplittable(element.parentElement, selectorsNotToSplit); + } + return true; +}; + +var paginate$1 = function paginate(content, rules) { + return new Thenable(function (paginateResolve, paginateReject, progress) { + // SETUP + var layoutWaitingTime = 0; + var elementCount = 0; + var elementsProcessed = 0; + + var ruleSet = new RuleSet(rules); + var measureArea = document.body.appendChild(el('.measure-area')); + + var breadcrumb = []; // Keep track of position in original tree + var book = new Book(); + + var canSplit = function canSplit() { + return !shouldIgnoreOverflow(last(breadcrumb)); + }; + + var makeNewPage = function makeNewPage() { + var newPage = new Page(); + measureArea.appendChild(newPage.element); + + ruleSet.startPage(newPage, book); + return newPage; + }; + + var finishPage = function finishPage(page, ignoreOverflow) { + if (page && page.hasOverflowed()) { + console.warn('Bindery: Page overflowing', book.pageInProgress.element); + if (!page.suppressErrors && !ignoreOverflow) { + paginateReject('Moved to new page when last one is still overflowing'); + throw Error('Bindery: Moved to new page when last one is still overflowing'); + } + } + + // finished with this page, can display + book.pages = orderPages(book.pages, makeNewPage); + annotatePages(book.pages); + if (page) ruleSet.finishPage(page, book); + }; + + // Creates clones for ever level of tag + // we were in when we overflowed the last page + var continueOnNewPage = function continueOnNewPage() { + var ignoreOverflow = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (book.pages.length > MAXIMUM_PAGE_LIMIT) { + paginateReject('Maximum page count exceeded'); + throw Error('Bindery: Maximum page count exceeded. Suspected runaway layout.'); + } + + finishPage(book.pageInProgress, ignoreOverflow); + + breadcrumb = breadcrumbClone(breadcrumb, rules); + var newPage = makeNewPage(); + + book.pageInProgress = newPage; + progress(book); + + book.pages.push(newPage); + + if (breadcrumb[0]) { + newPage.flowContent.appendChild(breadcrumb[0]); + } + + // make sure the cloned page is valid. + if (newPage.hasOverflowed()) { + var suspect = last(breadcrumb); + if (suspect) { + console.warn('Bindery: Content overflows, probably due to a style set on ' + elementToString(suspect) + '.'); + suspect.parentNode.removeChild(suspect); + } else { + console.warn('Bindery: Content overflows.'); + } + } + + return newPage; + }; + + // Shifts this element to the next page. If any of its + // ancestors cannot be split across page, it will + // step up the tree to find the first ancestor + // that can be split, and move all of that descendants + // to the next page. + var moveElementToNextPage = function moveElementToNextPage(nodeToMove) { + // So this node won't get cloned. TODO: this is unclear + breadcrumb.pop(); + + if (breadcrumb.length < 1) { + throw Error('Bindery: Attempting to move the top-level element'); + } + + // find the nearest splittable parent + var willMove = nodeToMove; + var pathToRestore = []; + while (breadcrumb.length > 1 && !isSplittable(last(breadcrumb), ruleSet.selectorsNotToSplit)) { + // console.log('Not OK to split:', last(breadcrumb)); + willMove = breadcrumb.pop(); + pathToRestore.unshift(willMove); + } + + // Once a node is moved to a new page, it should no longer trigger another + // move. otherwise tall elements will endlessly get shifted to the next page + willMove.setAttribute('data-bindery-did-move', true); + + var parent = willMove.parentNode; + parent.removeChild(willMove); + + if (breadcrumb.length > 1 && last(breadcrumb).textContent.trim() === '') { + parent.appendChild(willMove); + willMove = breadcrumb.pop(); + pathToRestore.unshift(willMove); + willMove.parentNode.removeChild(willMove); + } + + // If the page is empty when this node is removed, + // then it won't help to move it to the next page. + // Instead continue here until the node is done. + if (!book.pageInProgress.isEmpty) { + if (book.pageInProgress.hasOverflowed()) { + book.pageInProgress.suppressErrors = true; + } + continueOnNewPage(); + } + + // append node as first in new page + last(breadcrumb).appendChild(willMove); + + // restore subpath + pathToRestore.forEach(function (restore) { + breadcrumb.push(restore); + }); + + breadcrumb.push(nodeToMove); + }; + + var addTextWithoutChecks = function addTextWithoutChecks(child, parent) { + return new Thenable(function (resolve) { + parent.appendChild(child); + if (canSplit()) { + book.pageInProgress.suppressErrors = true; + continueOnNewPage(); + } + resolve(); + }); + }; + + var addSplittableText = function addSplittableText(text) { + return new Thenable(function (resolve, reject) { + addTextNodeIncremental(text, last(breadcrumb), book.pageInProgress).then(function (remainder) { + if (remainder) { + continueOnNewPage(); + addSplittableText(remainder).then(resolve).catch(reject); + } else { + resolve(); + } + }).catch(reject); + }); + }; + + var canSplitParent = function canSplitParent(parent) { + return isSplittable(parent, ruleSet.selectorsNotToSplit) && !shouldIgnoreOverflow(parent); + }; + + var addTextChild = function addTextChild(child, parent) { + return (canSplitParent(parent) ? addSplittableText(child).catch(function () { + if (breadcrumb.length < 2) return addTextWithoutChecks(child, last(breadcrumb)); + moveElementToNextPage(parent); + return addSplittableText(child); + }) : addTextNode(child, last(breadcrumb), book.pageInProgress).catch(function () { + if (canSplit()) moveElementToNextPage(parent); + return addTextNode(child, last(breadcrumb), book.pageInProgress); + })).catch(function () { + return addTextWithoutChecks(child, last(breadcrumb)); + }); + }; + + var addElementNode = void 0; + + var addChild = function addChild(child, parent) { + if (isTextNode(child)) { + return addTextChild(child, parent); + } else if (isUnloadedImage(child)) { + var imgStart = performance.now(); + return waitForImage(child).then(function () { + layoutWaitingTime += performance.now() - imgStart; + return addElementNode(child); + }); + } else if (isContent(child)) { + return addElementNode(child); + } + + // Skip comments and unknown nodes + return Thenable.resolved(); + }; + + // Adds an element node by clearing its childNodes, then inserting them + // one by one recursively until thet overflow the page + addElementNode = function addElementNode(elementToAdd) { + return new Thenable(function (resolve) { + if (book.pageInProgress.hasOverflowed() && canSplit()) { + book.pageInProgress.suppressErrors = true; + continueOnNewPage(); + } + var element = ruleSet.beforeAddElement(elementToAdd, book, continueOnNewPage, makeNewPage); + + if (!breadcrumb[0]) book.pageInProgress.flowContent.appendChild(element);else last(breadcrumb).appendChild(element); + + breadcrumb.push(element); + + var childNodes = [].concat(toConsumableArray(element.childNodes)); + element.innerHTML = ''; + + // Overflows when empty + if (book.pageInProgress.hasOverflowed() && canSplit()) { + moveElementToNextPage(element); + } + + var finishAdding = function finishAdding() { + // We're now done with this element and its children, + // so we pop up a level + var addedChild = breadcrumb.pop(); + ruleSet.afterAddElement(addedChild, book, continueOnNewPage, makeNewPage, function (el) { + el.parentNode.removeChild(el); + continueOnNewPage(); + last(breadcrumb).appendChild(el); + }); + elementsProcessed += 1; + book.estimatedProgress = elementsProcessed / elementCount; + resolve(); + }; + + var index = 0; + var addNext = function addNext() { + if (index < childNodes.length) { + var child = childNodes[index]; + index += 1; + addChild(child, element).then(addNext); + } else { + finishAdding(); + } + }; + + // kick it off + addNext(); + }); + }; + + (function () { + var startLayoutTime = window.performance.now(); + + ruleSet.setup(); + content.style.margin = 0; + content.style.padding = 0; + elementCount = content.querySelectorAll('*').length; + continueOnNewPage(); + addElementNode(content).then(function () { + document.body.removeChild(measureArea); + + book.pages = orderPages(book.pages, makeNewPage); + annotatePages(book.pages); + + book.setCompleted(); + ruleSet.finishEveryPage(book); + + var endLayoutTime = window.performance.now(); + var totalTime = endLayoutTime - startLayoutTime; + var layoutTime = totalTime - layoutWaitingTime; + + console.log('\uD83D\uDCD6 Book ready in ' + sec(totalTime) + 's (Layout: ' + sec(layoutTime) + 's, Waiting for images: ' + sec(layoutWaitingTime) + 's)'); + + paginateResolve(book); + }); + })(); + }); +}; + +var Mode = Object.freeze({ + FLIPBOOK: 'view_flipbook', + PREVIEW: 'view_preview', + PRINT: 'view_print' +}); + +var Paper = Object.freeze({ + AUTO: 'paper_auto', + AUTO_BLEED: 'paper_auto_bleed', + AUTO_MARKS: 'paper_auto_marks', + LETTER_PORTRAIT: 'paper_letter_p', + LETTER_LANDSCAPE: 'paper_letter_l', + A4_PORTRAIT: 'paper_a4_p', + A4_LANDSCAPE: 'paper_a4_l' +}); + +var Layout = Object.freeze({ + PAGES: 'layout_pages', + SPREADS: 'layout_spreads', + BOOKLET: 'layout_booklet' +}); + +var Marks = Object.freeze({ + NONE: 'marks_none', + SPREADS: 'layout_spreads', + BOTH: 'marks_both' +}); + +var letter = { width: '8.5in', height: '11in' }; +var a4 = { width: '210mm', height: '297mm' }; +var defaultPageSetup = { + bleed: '12pt', + size: { width: '4in', height: '6in' }, + margin: { + inner: '24pt', + outer: '24pt', + bottom: '40pt', + top: '48pt' + } +}; + +var supportsCustomPageSize = !!window.chrome && !!window.chrome.webstore; + +var PageSetup = function () { + function PageSetup() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, PageSetup); + + this.setSize(opts.size || defaultPageSetup.size); + this.setMargin(opts.margin || defaultPageSetup.margin); + this.setBleed(opts.bleed || defaultPageSetup.bleed); + } + + createClass(PageSetup, [{ + key: 'setupPaper', + value: function setupPaper() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + this.sheetSizeMode = supportsCustomPageSize ? opts.paper || Paper.AUTO : Paper.AUTO_MARKS; + this.printTwoUp = opts.layout && opts.layout !== Layout.PAGES; + } + }, { + key: 'setSize', + value: function setSize(size) { + isValidSize(size); + this.size = size; + } + }, { + key: 'setMargin', + value: function setMargin(margin) { + isValidSize(margin); + this.margin = margin; + } + }, { + key: 'setBleed', + value: function setBleed(newBleed) { + this.bleed = newBleed; + } + }, { + key: 'setPrintTwoUp', + value: function setPrintTwoUp(newVal) { + this.printTwoUp = newVal; + } + }, { + key: 'isSizeValid', + value: function isSizeValid() { + this.updateStylesheet(); + return Page.isSizeValid(); + } + }, { + key: 'spreadSizeStyle', + value: function spreadSizeStyle() { + var w = parseVal(this.size.width); + return { + height: this.size.height, + width: '' + w.val * 2 + w.unit + }; + } + }, { + key: 'updateStylesheet', + value: function updateStylesheet() { + var sheet = void 0; + var existing = document.querySelector('#binderyPageSetup'); + if (existing) { + sheet = existing; + } else { + sheet = document.createElement('style'); + sheet.id = 'binderyPageSetup'; + } + var w = parseVal(this.size.width); + + sheet.innerHTML = '\n@page { size: ' + this.sheetSize.width + ' ' + this.sheetSize.height + '; }\n' + c('.print-page') + ' { width: ' + this.sheetSize.width + '; height: ' + this.sheetSize.height + ';}\n\n' + c('.show-crop') + ' ' + c('.print-page') + ' ' + c('.spread-wrapper') + ',\n' + c('.show-bleed-marks') + ' ' + c('.print-page') + ' ' + c('.spread-wrapper') + ' {\n margin: calc(' + this.bleed + ' + 12pt) auto;\n}\nhtml {\n --bindery-page-width: ' + this.size.width + ';\n --bindery-page-height: ' + this.size.height + ';\n}\n' + c('.page-size-rotated') + ' {\n height: ' + this.size.width + ';\n width: ' + this.size.height + ';\n}\n' + c('.spread-size') + ' {\n height: ' + this.size.height + ';\n width: ' + w.val * 2 + w.unit + ';\n}\n' + c('.spread-size-rotated') + ' {\n height: ' + w.val * 2 + w.unit + ';\n width: ' + this.size.height + ';\n}\n' + c('.flowbox') + ',\n' + c('.footer') + ' {\n margin-left: ' + this.margin.inner + ';\n margin-right: ' + this.margin.outer + ';\n}\n' + c('.left') + ' ' + c('.flowbox') + ',\n' + c('.left') + ' ' + c('.footer') + ' {\n margin-left: ' + this.margin.outer + ';\n margin-right: ' + this.margin.inner + ';\n}\n\n' + c('.left') + ' ' + c('.running-header') + ' {\n left: ' + this.margin.outer + ';\n}\n' + c('.right') + ' ' + c('.running-header') + ' {\n right: ' + this.margin.outer + ';\n}\n\n' + c('.flowbox') + ' { margin-top: ' + this.margin.top + '; }\n' + c('.footer') + '{ margin-bottom: ' + this.margin.bottom + '; }\n\n' + c('.bleed-left') + ',\n' + c('.bleed-right') + ',\n' + c('.crop-left') + ',\n' + c('.crop-right') + ',\n' + c('.crop-fold') + ' {\n top: calc( -12pt - ' + this.bleed + ' );\n bottom: calc( -12pt - ' + this.bleed + ' );\n}\n\n' + c('.bleed-top') + ',\n' + c('.bleed-bottom') + ',\n' + c('.crop-top') + ',\n' + c('.crop-bottom') + ' {\n left: calc( -12pt - ' + this.bleed + ' );\n right: calc( -12pt - ' + this.bleed + ' );\n}\n' + c('.bleed-left') + ' { left: -' + this.bleed + '; }\n' + c('.bleed-right') + ' { right: -' + this.bleed + '; }\n' + c('.bleed-top') + ' { top: -' + this.bleed + '; }\n' + c('.bleed-bottom') + ' { bottom: -' + this.bleed + '; }\n\n' + c('.background') + ' {\n top: -' + this.bleed + ';\n bottom: -' + this.bleed + ';\n left: -' + this.bleed + ';\n right: -' + this.bleed + ';\n}\n\n' + c('.spread') + c('.right') + ' > ' + c('.background') + ' {\n left: calc(-100% - ' + this.bleed + ');\n}\n' + c('.spread') + c('.left') + ' > ' + c('.background') + ' {\n right: calc(-100% - ' + this.bleed + ');\n}\n '; + document.head.appendChild(sheet); + } + }, { + key: 'displaySize', + get: function get$$1() { + var width = this.printTwoUp ? this.spreadSizeStyle().width : this.size.width; + var height = this.size.height; + var bleed = this.bleed; + + return { + width: width, + height: height, + bleed: bleed + }; + } + }, { + key: 'sheetSize', + get: function get$$1() { + var width = this.printTwoUp ? this.spreadSizeStyle().width : this.size.width; + var height = this.size.height; + var b = this.bleed; + + switch (this.sheetSizeMode) { + case Paper.AUTO: + return { width: width, height: height }; + case Paper.AUTO_BLEED: + return { + width: 'calc(' + width + ' + ' + b + ' + ' + b + ')', + height: 'calc(' + height + ' + ' + b + ' + ' + b + ')' + }; + case Paper.AUTO_MARKS: + // TODO: 24pt marks is hardcoded + return { + width: 'calc(' + width + ' + ' + b + ' + ' + b + ' + 24pt)', + height: 'calc(' + height + ' + ' + b + ' + ' + b + ' + 24pt)' + }; + case Paper.LETTER_LANDSCAPE: + return { width: letter.height, height: letter.width }; + case Paper.LETTER_PORTRAIT: + return letter; + case Paper.A4_PORTRAIT: + return a4; + case Paper.A4_LANDSCAPE: + return { width: a4.height, height: a4.width }; + default: + } + return { width: width, height: height }; + } + }]); + return PageSetup; +}(); + +/* global BINDERY_VERSION */ + +var errorView = function (title, text) { + return el('.error', [el('.error-title', title), el('.error-text', text), el('.error-footer', 'Bindery ' + BINDERY_VERSION)]); +}; + +var orderPagesBooklet = function orderPagesBooklet(pages, makePage) { + while (pages.length % 4 !== 0) { + var spacerPage = makePage(); + spacerPage.element.style.visibility = 'hidden'; + pages.push(spacerPage); + } + var bookletOrder = []; + var len = pages.length; + + for (var i = 0; i < len / 2; i += 2) { + bookletOrder.push(pages[len - 1 - i]); + bookletOrder.push(pages[i]); + bookletOrder.push(pages[i + 1]); + bookletOrder.push(pages[len - 2 - i]); + } + + return bookletOrder; +}; + +var padPages = function padPages(pages, makePage) { + if (pages.length % 2 !== 0) { + var pg = makePage(); + pages.push(pg); + } + var spacerPage = makePage(); + var spacerPage2 = makePage(); + spacerPage.element.style.visibility = 'hidden'; + spacerPage2.element.style.visibility = 'hidden'; + pages.unshift(spacerPage); + pages.push(spacerPage2); + + return pages; +}; + +var twoPageSpread = function twoPageSpread(children) { + return el('.spread-wrapper.spread-size', children); +}; +var onePageSpread = function onePageSpread(children) { + return el('.spread-wrapper.page-size', children); +}; + +var renderGridLayout = function renderGridLayout(pages, isTwoUp) { + var gridLayout = document.createDocumentFragment(); + if (isTwoUp) { + for (var i = 0; i < pages.length; i += 2) { + var wrap = twoPageSpread([pages[i].element, pages[i + 1].element]); + gridLayout.appendChild(wrap); + } + } else { + pages.forEach(function (pg) { + var wrap = onePageSpread([pg.element]); + gridLayout.appendChild(wrap); + }); + } + + return gridLayout; +}; + +var directions = ['top', 'bottom', 'left', 'right']; +var bleedMarks = function bleedMarks() { + return directions.map(function (dir) { + return el('.bleed-' + dir); + }); +}; +var cropMarks = function cropMarks() { + return directions.map(function (dir) { + return el('.crop' + dir); + }); +}; + +var printMarksSingle = function printMarksSingle() { + return el('.print-mark-wrap', [].concat(toConsumableArray(cropMarks()), toConsumableArray(bleedMarks()))); +}; + +var printMarksSpread = function printMarksSpread() { + return el('.print-mark-wrap', [el('.crop-fold')].concat(toConsumableArray(cropMarks()), toConsumableArray(bleedMarks()))); +}; + +var bookletMeta = function bookletMeta(i, len) { + var isFront = i % 4 === 0; + var sheetIndex = parseInt((i + 1) / 4, 10) + 1; + return el('.print-meta', 'Sheet ' + sheetIndex + ' of ' + len / 4 + ': ' + (isFront ? 'Outside' : 'Inside')); +}; + +var twoPageSpread$1 = function twoPageSpread(children) { + return el('.spread-wrapper.spread-size', children); +}; +var onePageSpread$1 = function onePageSpread(children) { + return el('.spread-wrapper.page-size', children); +}; + +var renderPrintLayout = function renderPrintLayout(pages, isTwoUp, isBooklet) { + var printLayout = document.createDocumentFragment(); + + var marks = isTwoUp ? printMarksSpread : printMarksSingle; + var spread = isTwoUp ? twoPageSpread$1 : onePageSpread$1; + + var printSheet = function printSheet(children) { + return el('.print-page', [spread(children)]); + }; + + if (isTwoUp) { + for (var i = 0; i < pages.length; i += 2) { + var spreadMarks = marks(); + if (isBooklet) { + var meta = bookletMeta(i, pages.length); + spreadMarks.appendChild(meta); + } + var sheet = printSheet([pages[i].element, pages[i + 1].element, spreadMarks]); + printLayout.appendChild(sheet); + } + } else { + pages.forEach(function (pg) { + var sheet = printSheet([pg.element, marks()]); + printLayout.appendChild(sheet); + }); + } + + return printLayout; +}; + +var renderFlipLayout = function renderFlipLayout(pages, doubleSided) { + var flipLayout = document.createDocumentFragment(); + var sizer = el('.spread-size.flip-sizer'); + var flapHolder = el('.spread-size.flap-holder'); + sizer.appendChild(flapHolder); + flipLayout.appendChild(sizer); + var flaps = []; + var currentLeaf = -1; + + var leftOffset = 4; + if (pages.length * leftOffset > 60) { + leftOffset = 60 / pages.length; + } + flapHolder.style.width = pages.length * leftOffset + 'px'; + + var setLeaf = function setLeaf(n) { + var newLeaf = n; + if (newLeaf === currentLeaf) newLeaf += 1; + currentLeaf = newLeaf; + + var zScale = 4; + if (flaps.length * zScale > 200) zScale = 200 / flaps.length; + + flaps.forEach(function (flap, i, arr) { + // + 0.5 so left and right are even + var z = (arr.length - Math.abs(i - newLeaf + 0.5)) * zScale; + flap.style.transform = 'translate3d(' + (i < newLeaf ? 4 : 0) + 'px,0,' + z + 'px) rotateY(' + (i < newLeaf ? -180 : 0) + 'deg)'; + }); + }; + + var leafIndex = 0; + + var _loop = function _loop(i) { + leafIndex += 1; + var li = leafIndex; + var flap = el('.page3d'); + flap.addEventListener('click', function () { + var newLeaf = li - 1; + setLeaf(newLeaf); + }); + + var rightPage = pages[i].element; + var leftPage = void 0; + rightPage.classList.add(c('page3d-front')); + flap.appendChild(rightPage); + if (doubleSided) { + flap.classList.add(c('doubleSided')); + leftPage = pages[i + 1].element; + leftPage.classList.add(c('page3d-back')); + flap.appendChild(leftPage); + } else { + leftPage = el('.page.page3d-back'); + flap.appendChild(leftPage); + } + // TODO: Dynamically add/remove pages. + // Putting 1000s of elements onscreen + // locks up the browser. + + flap.style.left = i * leftOffset + 'px'; + + flaps.push(flap); + flapHolder.appendChild(flap); + }; + + for (var i = 1; i < pages.length - 1; i += doubleSided ? 2 : 1) { + _loop(i); + } + + setLeaf(0); + return flipLayout; +}; + +// import Controls from './Controls'; +var modeAttr = {}; +modeAttr[Mode.PREVIEW] = 'preview'; +modeAttr[Mode.PRINT] = 'print'; +modeAttr[Mode.FLIPBOOK] = 'flip'; + +var Viewer = function () { + function Viewer(_ref) { + var _this = this; + + var bindery = _ref.bindery, + mode = _ref.mode, + layout = _ref.layout, + marks = _ref.marks, + ControlsComponent = _ref.ControlsComponent; + classCallCheck(this, Viewer); + + this.book = null; + this.pageSetup = bindery.pageSetup; + + this.progressBar = el('.progress-bar'); + this.zoomBox = el('zoom-wrap'); + this.element = el('root', [this.progressBar, this.zoomBox]); + + this.doubleSided = true; + this.printArrange = layout; + + this.setMarks(marks); + this.mode = mode; + this.element.setAttribute('bindery-view-mode', modeAttr[this.mode]); + this.currentLeaf = 0; + + this.listenForPrint(); + this.listenForResize(); + + this.setPrint = this.setPrint.bind(this); + + if (ControlsComponent) { + this.controls = new ControlsComponent({ Mode: Mode, Paper: Paper, Layout: Layout, Marks: Marks }, // Available options + { // Initial props + paper: this.pageSetup.sheetSizeMode, + layout: this.printArrange, + mode: this.mode, + marks: marks + }, { // Actions + setMode: function setMode(newMode) { + if (newMode === _this.mode) return; + _this.mode = newMode; + _this.render(); + }, + setPaper: this.setSheetSize.bind(this), + setLayout: this.setPrintArrange.bind(this), + setMarks: this.setMarks.bind(this), + getPageSize: function getPageSize() { + return _this.pageSetup.displaySize; + } + }); + this.element.appendChild(this.controls.element); + } + + this.element.classList.add(c('in-progress')); + + document.body.appendChild(this.element); + } + + // Automatically switch into print mode + + + createClass(Viewer, [{ + key: 'listenForPrint', + value: function listenForPrint() { + var _this2 = this; + + if (window.matchMedia) { + var mediaQueryList = window.matchMedia('print'); + mediaQueryList.addListener(function (mql) { + if (mql.matches) { + // before print + _this2.setPrint(); + } else { + // after print + } + }); + } + document.body.addEventListener('keydown', function (e) { + if ((e.ctrlKey || e.metaKey) && e.keyCode === 80) { + e.preventDefault(); + _this2.setPrint(); + setTimeout(function () { + window.print(); + }, 10); + } + }); + } + }, { + key: 'listenForResize', + value: function listenForResize() { + var _this3 = this; + + window.addEventListener('resize', function () { + if (!_this3.throttleResize) { + _this3.updateZoom(); + _this3.throttleResize = setTimeout(function () { + _this3.throttleResize = null; + }, 20); + } + }); + } + }, { + key: 'setInProgress', + value: function setInProgress() { + this.element.classList.add(c('in-progress')); + if (this.controls) this.controls.setInProgress(); + } + }, { + key: 'setSheetSize', + value: function setSheetSize(newVal) { + var _this4 = this; + + this.pageSetup.sheetSizeMode = newVal; + this.pageSetup.updateStylesheet(); + + if (this.mode !== Mode.PRINT) { + this.setPrint(); + } + this.updateZoom(); + setTimeout(function () { + _this4.updateZoom(); + }, 300); + } + }, { + key: 'setPrintArrange', + value: function setPrintArrange(newVal) { + if (newVal === this.printArrange) return; + this.printArrange = newVal; + + this.pageSetup.setPrintTwoUp(this.isTwoUp); + this.pageSetup.updateStylesheet(); + + if (this.mode === Mode.PRINT) { + this.render(); + } else { + this.setPrint(); + } + } + }, { + key: 'setMarks', + value: function setMarks(newVal) { + switch (newVal) { + case Marks.NONE: + this.isShowingCropMarks = false; + this.isShowingBleedMarks = false; + break; + case Marks.CROP: + this.isShowingCropMarks = true; + this.isShowingBleedMarks = false; + break; + case Marks.BLEED: + this.isShowingCropMarks = false; + this.isShowingBleedMarks = true; + break; + case Marks.BOTH: + this.isShowingCropMarks = true; + this.isShowingBleedMarks = true; + break; + default: + } + } + }, { + key: 'displayError', + value: function displayError(title, text) { + if (!this.element.parentNode) { + document.body.appendChild(this.element); + } + if (!this.error) { + this.error = errorView(title, text); + this.element.appendChild(this.error); + } + } + }, { + key: 'clear', + value: function clear() { + this.book = null; + this.lastSpreadInProgress = null; // TODO: Make this clearer, after first render + this.zoomBox.innerHTML = ''; + } + }, { + key: 'cancel', + value: function cancel() { + // TODO this doesn't work if the target is an existing node + if (this.element.parentNode) { + this.element.parentNode.removeChild(this.element); + } + } + }, { + key: 'toggleBleed', + value: function toggleBleed() { + this.element.classList.add(c('show-bleed')); + } + }, { + key: 'toggleDouble', + value: function toggleDouble() { + this.doubleSided = !this.doubleSided; + this.render(); + } + }, { + key: 'setPrint', + value: function setPrint() { + if (this.mode === Mode.PRINT) return; + this.mode = Mode.PRINT; + this.render(); + } + }, { + key: 'render', + value: function render() { + var _this5 = this; + + if (!this.book) return; + var _document = document, + body = _document.body; + + if (!this.element.parentNode) { + body.appendChild(this.element); + } + + this.flaps = []; + body.classList.add(c('viewing')); + this.element.setAttribute('bindery-view-mode', modeAttr[this.mode]); + + var scrollMax = body.scrollHeight - body.offsetHeight; + var scrollPct = body.scrollTop / scrollMax; + + if (this.controls) this.controls.setDone(this.book.pages.length); + this.progressBar.style.width = '100%'; + + window.requestAnimationFrame(function () { + if (_this5.mode === Mode.PREVIEW) _this5.renderGrid();else if (_this5.mode === Mode.FLIPBOOK) _this5.renderInteractive();else if (_this5.mode === Mode.PRINT) _this5.renderPrint();else _this5.renderGrid(); + + body.scrollTop = scrollMax * scrollPct; + _this5.updateZoom(); + }); + } + }, { + key: 'renderProgress', + value: function renderProgress(book) { + var _this6 = this; + + this.book = book; + + this.progressBar.style.width = this.book.estimatedProgress * 100 + '%'; + + if (this.controls) { + this.controls.updateProgress(this.book.pages.length, this.book.estimatedProgress); + } + + var sideBySide = this.mode === Mode.PREVIEW || this.mode === Mode.PRINT && this.printArrange !== Layout.PAGES; + var limit = sideBySide ? 2 : 1; + + var makeSpread = function makeSpread() { + for (var _len = arguments.length, arg = Array(_len), _key = 0; _key < _len; _key++) { + arg[_key] = arguments[_key]; + } + + return el('.spread-wrapper', [].concat(arg)); + }; + + this.book.pages.forEach(function (page, i) { + // If hasn't been added, or not in spread yet + if (!_this6.zoomBox.contains(page.element) || page.element.parentNode === _this6.zoomBox) { + if (_this6.lastSpreadInProgress && _this6.lastSpreadInProgress.children.length < limit) { + _this6.lastSpreadInProgress.appendChild(page.element); + } else { + if (i === 0 && sideBySide) { + var spacer = new Page(); + spacer.element.style.visibility = 'hidden'; + _this6.lastSpreadInProgress = makeSpread(spacer.element, page.element); + } else { + _this6.lastSpreadInProgress = makeSpread(page.element); + } + _this6.zoomBox.appendChild(_this6.lastSpreadInProgress); + } + } + }); + + if (this.book.pageInProgress) { + this.zoomBox.appendChild(this.book.pageInProgress.element); + } + + this.updateZoom(); + } + }, { + key: 'updateZoom', + value: function updateZoom() { + if (this.zoomBox.firstElementChild) { + var scrollPct = document.body.scrollTop / document.body.scrollHeight; + var viewerRect = this.zoomBox.getBoundingClientRect(); + var contentW = this.zoomBox.firstElementChild.getBoundingClientRect().width; + var scale = Math.min(1, viewerRect.width / contentW); + + this.zoomBox.style.transform = 'scale(' + scale + ')'; + document.body.scrollTop = document.body.scrollHeight * scrollPct; + } + } + }, { + key: 'renderPrint', + value: function renderPrint() { + this.element.classList.add(c('show-bleed')); + + this.zoomBox.innerHTML = ''; + + var isBooklet = this.printArrange === Layout.BOOKLET; + + var pages = this.book.pages.slice(); + if (this.printArrange === Layout.SPREADS) { + pages = padPages(pages, function () { + return new Page(); + }); + } else if (isBooklet) { + pages = orderPagesBooklet(pages, function () { + return new Page(); + }); + } + + var fragment = renderPrintLayout(pages, this.isTwoUp, isBooklet); + this.zoomBox.appendChild(fragment); + } + }, { + key: 'renderGrid', + value: function renderGrid() { + this.zoomBox.innerHTML = ''; + + this.element.classList.remove(c('show-bleed')); + + var pages = this.book.pages.slice(); + + if (this.doubleSided) pages = padPages(pages, function () { + return new Page(); + }); + + var fragment = renderGridLayout(pages, this.doubleSided); + this.zoomBox.appendChild(fragment); + } + }, { + key: 'renderInteractive', + value: function renderInteractive() { + this.zoomBox.innerHTML = ''; + this.flaps = []; + + this.element.classList.remove(c('show-bleed')); + + var pages = padPages(this.book.pages.slice(), function () { + return new Page(); + }); + + var fragment = renderFlipLayout(pages, this.doubleSided); + this.zoomBox.appendChild(fragment); + } + }, { + key: 'isTwoUp', + get: function get$$1() { + return this.printArrange !== Layout.PAGES; + } + }, { + key: 'isShowingCropMarks', + get: function get$$1() { + return this.element.classList.contains(c('show-crop')); + }, + set: function set$$1(newVal) { + if (newVal) { + this.element.classList.add(c('show-crop')); + this.setPrint(); + } else { + this.element.classList.remove(c('show-crop')); + } + } + }, { + key: 'isShowingBleedMarks', + get: function get$$1() { + return this.element.classList.contains(c('show-bleed-marks')); + }, + set: function set$$1(newVal) { + if (newVal) { + this.element.classList.add(c('show-bleed-marks')); + this.setPrint(); + } else { + this.element.classList.remove(c('show-bleed-marks')); + } + } + }]); + return Viewer; +}(); + +var Split = function (_Rule) { + inherits(Split, _Rule); + + function Split(options) { + classCallCheck(this, Split); + + options.toNext = options.toNext || 'split-to-next'; + options.fromPrevious = options.fromPrevious || 'split-from-previous'; + + var _this = possibleConstructorReturn(this, (Split.__proto__ || Object.getPrototypeOf(Split)).call(this, options)); + + OptionType.validate(options, { + name: 'Split', + selector: OptionType.string, + toNext: OptionType.string, + fromPrevious: OptionType.string + }); + return _this; + } + + createClass(Split, [{ + key: 'customToNextClass', + get: function get$$1() { + return this.toNext; + } + }, { + key: 'customFromPreviousClass', + get: function get$$1() { + return this.fromPrevious; + } + }]); + return Split; +}(Rule); + +var Counter = function (_Rule) { + inherits(Counter, _Rule); + + function Counter(options) { + classCallCheck(this, Counter); + + var _this = possibleConstructorReturn(this, (Counter.__proto__ || Object.getPrototypeOf(Counter)).call(this, options)); + + _this.selector = '*'; + _this.counterValue = 0; + OptionType.validate(options, { + name: 'Counter', + replaceEl: OptionType.string, + resetEl: OptionType.string, + incrementEl: OptionType.string, + replace: OptionType.func + }); + return _this; + } + + createClass(Counter, [{ + key: 'setup', + value: function setup() { + this.counterValue = 0; + } + }, { + key: 'beforeAdd', + value: function beforeAdd(el$$1) { + if (el$$1.matches(this.incrementEl)) { + this.counterValue += 1; + } + if (el$$1.matches(this.resetEl)) { + this.counterValue = 0; + } + if (el$$1.matches(this.replaceEl)) { + return this.createReplacement(el$$1); + } + return el$$1; + } + }, { + key: 'createReplacement', + value: function createReplacement(element) { + return this.replace(element, this.counterValue); + } + }, { + key: 'replace', + value: function replace(element, counterValue) { + element.textContent = counterValue; + return element; + } + }]); + return Counter; +}(Rule); + +// Options: +// selector: String +// replace: function (HTMLElement) => HTMLElement + +var Replace = function (_Rule) { + inherits(Replace, _Rule); + + function Replace(options) { + classCallCheck(this, Replace); + + var _this = possibleConstructorReturn(this, (Replace.__proto__ || Object.getPrototypeOf(Replace)).call(this, options)); + + _this.name = 'Replace'; + return _this; + } + + createClass(Replace, [{ + key: 'afterAdd', + value: function afterAdd(element, book, continueOnNewPage, makeNewPage, overflowCallback) { + var parent = element.parentNode; + if (!parent) { + throw Error('Bindery: Rule assumes element has been added but it has no parent.', element); + } + var defensiveClone = element.cloneNode(true); + var replacement = this.createReplacement(book, defensiveClone); + parent.replaceChild(replacement, element); + + if (book.pageInProgress.hasOverflowed()) { + parent.replaceChild(element, replacement); + + return overflowCallback(element); + } + + return replacement; + } + }, { + key: 'createReplacement', + value: function createReplacement(book, element) { + return this.replace(element); + } + }, { + key: 'replace', + value: function replace(element) { + element.insertAdjacentHTML('beforeEnd', 'Default Replacement'); + return element; + } + }]); + return Replace; +}(Rule); + +// Options: +// selector: String +// replace: function (HTMLElement, number) => HTMLElement +// render: function (Page) => HTMLElement + +var Footnote = function (_Replace) { + inherits(Footnote, _Replace); + + function Footnote(options) { + classCallCheck(this, Footnote); + + var _this = possibleConstructorReturn(this, (Footnote.__proto__ || Object.getPrototypeOf(Footnote)).call(this, options)); + + OptionType.validate(options, { + name: 'Footnote', + selector: OptionType.string, + replace: OptionType.func, + render: OptionType.func + }); + return _this; + } + + createClass(Footnote, [{ + key: 'afterAdd', + value: function afterAdd(element, book, continueOnNewPage, makeNewPage, overflowCallback) { + var number = book.pageInProgress.footer.children.length + 1; + + var footnote = el('.footnote'); + var contents = this.render(element, number); + if (contents instanceof HTMLElement) footnote.appendChild(contents);else footnote.innerHTML = contents; + + book.pageInProgress.footer.appendChild(footnote); + + return get(Footnote.prototype.__proto__ || Object.getPrototypeOf(Footnote.prototype), 'afterAdd', this).call(this, element, book, continueOnNewPage, makeNewPage, function (overflowEl) { + book.pageInProgress.footer.removeChild(footnote); + return overflowCallback(overflowEl); + }); + } + }, { + key: 'createReplacement', + value: function createReplacement(book, element) { + var number = book.pageInProgress.footer.children.length; + return this.replace(element, number); + } + }, { + key: 'replace', + value: function replace(element, number) { + element.insertAdjacentHTML('beforeEnd', '' + number + ''); + return element; + } + }, { + key: 'render', + value: function render(element, number) { + return '' + number + ' Default footnote (Learn how to change it)'; + } + }]); + return Footnote; +}(Replace); + +// Options: +// selector: String +// replace: function (HTMLElement, number) => HTMLElement + +var PageReference = function (_Replace) { + inherits(PageReference, _Replace); + + function PageReference(options) { + classCallCheck(this, PageReference); + + var _this = possibleConstructorReturn(this, (PageReference.__proto__ || Object.getPrototypeOf(PageReference)).call(this, options)); + + OptionType.validate(options, { + name: 'PageReference', + selector: OptionType.string, + replace: OptionType.func, + createTest: OptionType.func + }); + return _this; + } + + createClass(PageReference, [{ + key: 'afterAdd', + value: function afterAdd(elmt, book) { + var _this2 = this; + + var test = this.createTest(elmt); + if (test) { + // Temporary, to make sure it'll fit + var parent = elmt.parentNode; + var tempClone = elmt.cloneNode(true); + var tempNumbers = book.pagesForTest(test); + var tempRanges = makeRanges(tempNumbers); + var temp = this.replace(tempClone, tempRanges || '###'); + temp.classList.add(c('placeholder-pulse')); + parent.replaceChild(temp, elmt); + + book.onComplete(function () { + var tempParent = temp.parentNode; + var finalClone = elmt.cloneNode(true); + var pageNumbers = book.pagesForTest(test); + var pageRanges = makeRanges(pageNumbers); + var newEl = _this2.replace(finalClone, pageRanges); + tempParent.replaceChild(newEl, temp); + }); + + return temp; + } + return elmt; + } + }, { + key: 'createTest', + value: function createTest(element) { + var selector = element.getAttribute('href'); + if (selector) { + selector = selector.replace('#', ''); + // extra resilient in case it starts with a number ie wikipedia + selector = '[id="' + selector + '"]'; + return function (el$$1) { + return el$$1.querySelector(selector); + }; + } + return null; + } + }, { + key: 'replace', + value: function replace(original, number) { + original.insertAdjacentHTML('beforeend', ', ' + number + ''); + return original; + } + }]); + return PageReference; +}(Replace); + +// Options: +// selector: String +// render: function (Page) => HTMLElement +// TODO selectorHierarchy: [ String ], ie [ 'h1', 'h2', 'h3.chapter' ] + +var RunningHeader = function (_Rule) { + inherits(RunningHeader, _Rule); + + function RunningHeader() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, RunningHeader); + + var _this = possibleConstructorReturn(this, (RunningHeader.__proto__ || Object.getPrototypeOf(RunningHeader)).call(this, options)); + + OptionType.validate(options, { + name: 'RunningHeader', + render: OptionType.func + }); + return _this; + } + + createClass(RunningHeader, [{ + key: 'eachPage', + value: function eachPage(page) { + if (!page.runningHeader) { + var elmt = el('.running-header'); + page.element.appendChild(elmt); + page.runningHeader = elmt; + } + page.runningHeader.innerHTML = this.render(page); + } + }, { + key: 'render', + value: function render(page) { + return page.number; + } + }]); + return RunningHeader; +}(Rule); + +var Rules = { + Rule: Rule, + Split: function Split$$1(options) { + return new Split(options); + }, + Counter: function Counter$$1(options) { + return new Counter(options); + }, + FullBleedPage: function FullBleedPage$$1(options) { + return new FullBleedPage(options); + }, + Footnote: function Footnote$$1(options) { + return new Footnote(options); + }, + RunningHeader: function RunningHeader$$1(options) { + return new RunningHeader(options); + }, + Replace: function Replace$$1(options) { + return new Replace(options); + }, + FullBleedSpread: function FullBleedSpread$$1(options) { + return new FullBleedSpread(options); + }, + PageBreak: function PageBreak$$1(options) { + return new PageBreak(options); + }, + PageReference: function PageReference$$1(options) { + return new PageReference(options); + }, + createRule: function createRule(options) { + return new Rule(options); + } +}; + +var PageBreak$1 = Rules.PageBreak; +var PageReference$1 = Rules.PageReference; +var Footnote$1 = Rules.Footnote; +var FullBleedPage$1 = Rules.FullBleedPage; +var FullBleedSpread$1 = Rules.FullBleedSpread; + + +var replacer = function replacer(element, number) { + element.textContent = '' + number; + return element; +}; + +var defaultRules = [PageBreak$1({ selector: '[book-page-break="both"]', position: 'both' }), PageBreak$1({ selector: '[book-page-break="avoid"]', position: 'avoid' }), PageBreak$1({ selector: '[book-page-break="after"][book-page-continue="right"]', position: 'after', continue: 'right' }), PageBreak$1({ selector: '[book-page-break="after"][book-page-continue="left"]', position: 'after', continue: 'left' }), PageBreak$1({ selector: '[book-page-break="after"][book-page-continue="next"]', position: 'after', continue: 'next' }), PageBreak$1({ selector: '[book-page-break="before"][book-page-continue="right"]', position: 'before', continue: 'right' }), PageBreak$1({ selector: '[book-page-break="before"][book-page-continue="left"]', position: 'before', continue: 'left' }), PageBreak$1({ selector: '[book-page-break="before"][book-page-continue="next"]', position: 'before', continue: 'next' }), FullBleedPage$1({ selector: '[book-full-bleed="page"]' }), FullBleedSpread$1({ selector: '[book-full-bleed="spread"]' }), Footnote$1({ + selector: '[book-footnote-text]', + render: function render(element, number) { + var txt = element.getAttribute('book-footnote-text'); + return '' + number + '' + txt; + } +}), PageReference$1({ + selector: '[book-pages-with-text]', + replace: replacer, + createTest: function createTest(element) { + var term = element.getAttribute('book-pages-with-text').toLowerCase().trim(); + return function (page) { + var txt = page.textContent.toLowerCase(); + return txt.includes(term); + }; + } +}), PageReference$1({ + selector: '[book-pages-with-selector]', + replace: replacer, + createTest: function createTest(element) { + var sel = element.getAttribute('book-pages-with-selector').trim(); + return function (page) { + return page.querySelector(sel); + }; + } +}), PageReference$1({ + selector: '[book-pages-with]', + replace: replacer, + createTest: function createTest(element) { + var term = element.textContent.toLowerCase().trim(); + return function (page) { + var txt = page.textContent.toLowerCase(); + return txt.includes(term); + }; + } +})]; + +___$insertStyle("@charset \"UTF-8\";@media screen{.📖-page{background:#fff;outline:1px solid #ddd;box-shadow:0 2px 4px -1px rgba(0,0,0,.15);overflow:hidden}.📖-show-bleed .📖-page{box-shadow:none;outline:none;overflow:visible}.📖-page:after{content:\"\";position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;z-index:3}}li.📖-continuation,p.📖-continuation{text-indent:unset!important}li.📖-continuation{list-style:none!important}.📖-out-of-flow{display:none}.📖-page{width:var(--bindery-page-width);height:var(--bindery-page-height);position:relative;display:flex;flex-direction:column;flex-wrap:nowrap}.📖-flowbox{position:relative;margin:60px 40px;margin-bottom:0;flex:1 1 auto;min-height:0}.📖-content{padding:.1px;position:relative}.📖-footer{margin:60px 40px;margin-top:8pt;flex:0 1 auto;z-index:1}.📖-background{position:absolute;z-index:0;overflow:hidden}.📖-left>.📖-background{right:0}.📖-right>.📖-background{left:0}.📖-sup{font-size:.667em}.📖-footer,.📖-running-header{font-size:10pt}.📖-running-header{position:absolute;text-align:center;top:.25in}.📖-left .📖-running-header{left:18pt;text-align:left}.📖-right .📖-running-header{right:18pt;text-align:right}.📖-left .📖-rotate-container.📖-rotate-outward,.📖-left .📖-rotate-container.📖-rotate-spread-clockwise,.📖-right .📖-rotate-container.📖-rotate-inward,.📖-rotate-container.📖-rotate-clockwise{transform:rotate(90deg) translate3d(0,-100%,0);transform-origin:top left}.📖-left .📖-rotate-container.📖-rotate-inward,.📖-left .📖-rotate-container.📖-rotate-spread-counterclockwise,.📖-right .📖-rotate-container.📖-rotate-outward,.📖-rotate-container.📖-rotate-counterclockwise{transform:rotate(-90deg) translate3d(-100%,0,0);transform-origin:top left}.📖-rotate-container{position:absolute}.📖-left .📖-rotate-container.📖-rotate-clockwise .📖-background{bottom:0}.📖-left .📖-rotate-container.📖-rotate-counterclockwise .📖-background,.📖-right .📖-rotate-container.📖-rotate-clockwise .📖-background{top:0}.📖-right .📖-rotate-container.📖-rotate-counterclockwise .📖-background,.📖-rotate-container.📖-rotate-inward .📖-background{bottom:0}.📖-rotate-container.📖-rotate-outward .📖-background{top:0}.📖-right .📖-rotate-container.📖-rotate-spread-clockwise{transform:rotate(90deg) translate3d(0,-50%,0);transform-origin:top left}.📖-right .📖-rotate-container.📖-rotate-spread-counterclockwise{transform:rotate(-90deg) translate3d(-100%,-50%,0);transform-origin:top left}@media screen{.📖-viewing{background:#f4f4f4!important}.📖-root{transition:opacity .2s;opacity:1;background:#f4f4f4;padding:10px;z-index:2;position:relative;padding-top:60px;min-height:90vh}.📖-progress-bar{position:fixed;left:0;top:0;background:var(--bindery-ui-accent,#0000c5);width:0;transition:all .2s;opacity:0;height:0;z-index:2}.📖-in-progress .📖-progress-bar{opacity:1;height:2px}.📖-measure-area{position:fixed;background:#f4f4f4;padding:50px 20px;z-index:2;visibility:hidden;left:0;right:0;bottom:0}.📖-measure-area .📖-page{margin:0 auto 50px}.📖-is-overflowing{border-bottom:1px solid #f0f}.📖-print-page{margin:0 auto}.📖-error{font:16px/1.4 -apple-system,BlinkMacSystemFont,Roboto,sans-serif;padding:15vh 15vw;z-index:3;position:fixed;top:0;left:0;right:0;bottom:0;background:hsla(0,0%,96%,.7)}.📖-error-title{font-size:1.5em;margin-bottom:16px}.📖-error-text{margin-bottom:16px;white-space:pre-line}.📖-error-footer{opacity:.5;font-size:.66em;text-transform:uppercase;letter-spacing:.02em}.📖-show-bleed .📖-print-page{background:#fff;outline:1px solid rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.2);margin:20px auto}.📖-placeholder-pulse{animation:pulse 1s infinite}}@keyframes pulse{0%{opacity:.2}50%{opacity:.5}to{opacity:.2}}@page{margin:0}@media print{.📖-root *{-webkit-print-color-adjust:exact;color-adjust:exact}.📖-controls,.📖-viewing>:not(.📖-root){display:none!important}.📖-print-page{padding:1px;margin:0 auto}.📖-zoom-wrap[style]{transform:none!important}}body.📖-viewing{margin:0}.📖-zoom-wrap{transform-origin:top left;transform-style:preserve-3d;height:calc(100vh - 120px)}[bindery-view-mode=interactive] .📖-zoom-wrap{transform-origin:center left}.📖-viewing>:not(.📖-root):not(.📖-measure-area){display:none!important}.📖-print-page{page-break-after:always;overflow:hidden;align-items:center;transition:all .2s}.📖-print-page,.📖-spread-wrapper{position:relative;display:flex;justify-content:center}.📖-spread-wrapper{margin:0 auto 32px}.📖-print-page .📖-spread-wrapper{margin:0 auto}.📖-flap-holder{perspective:5000px;position:absolute;top:0;right:0;left:0;bottom:0;margin:auto;transform-style:preserve-3d}.📖-flip-sizer{position:relative;margin:auto;padding:0 20px;box-sizing:content-box;height:100%!important}.📖-page3d{margin:auto;width:var(--bindery-page-width);height:var(--bindery-page-height);transform:rotateY(0);transform-style:preserve-3d;transform-origin:left;transition:transform .5s,box-shadow .1s;position:absolute;left:0;right:0;top:0;bottom:0}.📖-page3d:hover{box-shadow:2px 0 4px rgba(0,0,0,.2)}.📖-page3d.flipped{transform:rotateY(-180deg)}.📖-page3d .📖-page{position:absolute;backface-visibility:hidden;-webkit-backface-visibility:hidden;box-shadow:none}.📖-page3d .📖-page3d-front{transform:rotateY(0)}.📖-page3d .📖-page3d-back{transform:rotateY(-180deg)}.📖-print-mark-wrap{display:none;position:absolute;pointer-events:none;top:0;bottom:0;left:0;right:0;z-index:3}.📖-show-bleed-marks .📖-print-mark-wrap,.📖-show-bleed-marks .📖-print-mark-wrap>[class*=bleed],.📖-show-crop .📖-print-mark-wrap,.📖-show-crop .📖-print-mark-wrap>[class*=crop]{display:block}.📖-print-mark-wrap>div{display:none;position:absolute;overflow:hidden}.📖-print-mark-wrap>div:after,.📖-print-mark-wrap>div:before{content:\"\";display:block;position:absolute}.📖-print-mark-wrap>div:before{top:0;left:0}.📖-print-mark-wrap>div:after{bottom:0;right:0}.📖-bleed-left,.📖-bleed-right,.📖-crop-fold,.📖-crop-left,.📖-crop-right{width:1px;margin:auto}.📖-bleed-left:after,.📖-bleed-left:before,.📖-bleed-right:after,.📖-bleed-right:before,.📖-crop-fold:after,.📖-crop-fold:before,.📖-crop-left:after,.📖-crop-left:before,.📖-crop-right:after,.📖-crop-right:before{width:1px;height:12pt;background-image:linear-gradient(90deg,#000 0,#000 51%,transparent 0);background-size:1px 100%}.📖-bleed-bottom,.📖-bleed-top,.📖-crop-bottom,.📖-crop-top{height:1px}.📖-bleed-bottom:after,.📖-bleed-bottom:before,.📖-bleed-top:after,.📖-bleed-top:before,.📖-crop-bottom:after,.📖-crop-bottom:before,.📖-crop-top:after,.📖-crop-top:before{width:12pt;height:1px;background-image:linear-gradient(180deg,#000 0,#000 51%,transparent 0);background-size:100% 1px}.📖-crop-fold{right:0;left:0}.📖-crop-left{left:0}.📖-crop-right{right:0}.📖-crop-top{top:0}.📖-crop-bottom{bottom:0}.📖-print-meta{padding:12pt;text-align:center;font-family:-apple-system,BlinkMacSystemFont,Roboto,sans-serif;font-size:8pt;display:block!important;position:absolute;bottom:-60pt;left:0;right:0}"); + +/* global BINDERY_VERSION */ + +var Bindery = function () { + function Bindery() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + classCallCheck(this, Bindery); + + console.log('\uD83D\uDCD6 Bindery ' + BINDERY_VERSION); + + this.autorun = opts.autorun || true; + this.autoupdate = opts.autoupdate || false; + scheduler.isDebugging = opts.debug || urlQuery('debug') || false; + + OptionType.validate(opts, { + name: 'makeBook', + autorun: OptionType.bool, + content: OptionType.any, + ControlsComponent: OptionType.any, + pageSetup: OptionType.shape({ + name: 'pageSetup', + bleed: OptionType.length, + margin: OptionType.shape({ + name: 'margin', + top: OptionType.length, + inner: OptionType.length, + outer: OptionType.length, + bottom: OptionType.length + }), + size: OptionType.shape({ + name: 'size', + width: OptionType.length, + height: OptionType.length + }) + }), + view: OptionType.enum.apply(OptionType, toConsumableArray(Object.values(Mode))), + printSetup: OptionType.shape({ + name: 'printSetup', + layout: OptionType.enum.apply(OptionType, toConsumableArray(Object.values(Layout))), + marks: OptionType.enum.apply(OptionType, toConsumableArray(Object.values(Marks))), + paper: OptionType.enum.apply(OptionType, toConsumableArray(Object.values(Paper))) + }), + rules: OptionType.array + }); + + this.pageSetup = new PageSetup(opts.pageSetup); + this.pageSetup.setupPaper(opts.printSetup); + + var startLayout = opts.printSetup ? opts.printSetup.layout || Layout.PAGES : Layout.PAGES; + var startMarks = opts.printSetup ? opts.printSetup.marks || Marks.CROP : Marks.CROP; + this.viewer = new Viewer({ + bindery: this, + mode: opts.view || Mode.PREVIEW, + marks: startMarks, + layout: startLayout, + ControlsComponent: opts.ControlsComponent + }); + + this.rules = defaultRules; + if (opts.rules) this.addRules(opts.rules); + + if (!opts.content) { + this.viewer.displayError('Content not specified', 'You must include a source element, selector, or url'); + console.error('Bindery: You must include a source element or selector'); + } else if (typeof opts.content === 'string') { + this.source = document.querySelector(opts.content); + if (!(this.source instanceof HTMLElement)) { + this.viewer.displayError('Content not specified', 'Could not find element that matches selector "' + opts.content + '"'); + console.error('Bindery: Could not find element that matches selector "' + opts.content + '"'); + return; + } + if (this.autorun) { + this.makeBook(); + } + } else if (_typeof(opts.content) === 'object' && opts.content.url) { + var url = opts.content.url; + var selector = opts.content.selector; + this.fetchSource(url, selector); + } else if (opts.content instanceof HTMLElement) { + this.source = opts.content; + if (this.autorun) { + this.makeBook(); + } + } else { + console.error('Bindery: Source must be an element or selector'); + } + } + + // Convenience constructor + + + createClass(Bindery, [{ + key: 'fetchSource', + value: function fetchSource(url, selector) { + var _this = this; + + fetch(url).then(function (response) { + if (response.status === 404) { + _this.viewer.displayError('404', 'Could not find file at "' + url + '"'); + } else if (response.status === 200) { + return response.text(); + } + return ''; + }).then(function (fetchedContent) { + var wrapper = document.createElement('div'); + wrapper.innerHTML = fetchedContent; + _this.source = wrapper.querySelector(selector); + if (!(_this.source instanceof HTMLElement)) { + _this.viewer.displayError('Source not specified', 'Could not find element that matches selector "' + selector + '"'); + console.error('Bindery: Could not find element that matches selector "' + selector + '"'); + return; + } + if (_this.autorun) { + _this.makeBook(); + } + }).catch(function (error) { + console.error(error); + var scheme = window.location.href.split('://')[0]; + if (scheme === 'file') { + _this.viewer.displayError('Can\'t fetch content from "' + url + '"', 'Web pages can\'t fetch content unless they are on a server.'); + } + }); + } + }, { + key: 'cancel', + value: function cancel() { + this.viewer.cancel(); + document.body.classList.remove(c('viewing')); + this.source.style.display = ''; + } + }, { + key: 'addRules', + value: function addRules(newRules) { + var _this2 = this; + + newRules.forEach(function (rule) { + if (rule instanceof Rules.Rule) { + _this2.rules.push(rule); + } else { + throw Error('Bindery: The following is not an instance of Bindery.Rule and will be ignored: ' + rule); + } + }); + } + }, { + key: 'updateBookSilent', + value: function updateBookSilent() { + var _this3 = this; + + this.layoutComplete = false; + + this.source.style.display = ''; + var content = this.source.cloneNode(true); + this.source.style.display = 'none'; + + document.body.classList.add(c('viewing')); + + this.pageSetup.updateStylesheet(); + + paginate$1({ + content: content, + rules: this.rules, + success: function success(book) { + _this3.viewer.book = book; + _this3.viewer.render(); + _this3.layoutComplete = true; + }, + progress: function progress() {}, + error: function error(_error) { + _this3.layoutComplete = true; + _this3.viewer.displayError('Layout failed', _error); + } + }); + } + }, { + key: 'makeBook', + value: function makeBook(doneBinding) { + var _this4 = this; + + if (!this.source) { + document.body.classList.add(c('viewing')); + return; + } + + this.layoutComplete = false; + + if (!this.pageSetup.isSizeValid()) { + this.viewer.displayError('Page is too small', 'Size: ' + JSON.stringify(this.pageSize) + ' \n Margin: ' + JSON.stringify(this.pageMargin) + ' \n Try adjusting the sizes or units.'); + console.error('Bindery: Cancelled pagination. Page is too small.'); + return; + } + + this.source.style.display = ''; + var content = this.source.cloneNode(true); + this.source.style.display = 'none'; + + // In case we're updating an existing layout + this.viewer.clear(); + + document.body.classList.add(c('viewing')); + if (scheduler.isDebugging) document.body.classList.add(c('debug')); + + this.pageSetup.updateStylesheet(); + + this.viewer.setInProgress(); + + paginate$1(content, this.rules).progress(function (book) { + _this4.viewer.renderProgress(book); + }).then(function (book) { + _this4.viewer.book = book; + _this4.viewer.render(); + + _this4.layoutComplete = true; + if (doneBinding) doneBinding(); + _this4.viewer.element.classList.remove(c('in-progress')); + document.body.classList.remove(c('debug')); + }).catch(function (error) { + _this4.layoutComplete = true; + _this4.viewer.element.classList.remove(c('in-progress')); + _this4.viewer.displayError('Layout couldn\'t complete', error); + }); + } + }], [{ + key: 'makeBook', + value: function makeBook() { + var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + opts.autorun = opts.autorun ? opts.autorun : true; + return new Bindery(opts); + } + }]); + return Bindery; +}(); + +Bindery.version = BINDERY_VERSION; + +var BinderyWithRules = Object.assign(Bindery, Rules); +BinderyWithRules.View = Mode; +BinderyWithRules.Paper = Paper; +BinderyWithRules.Layout = Layout; +BinderyWithRules.Marks = Marks; + +return BinderyWithRules; + +}))); +//# sourceMappingURL=bindery.umd.js.map diff --git a/assets/script.js b/libreto/assets/script.js similarity index 87% rename from assets/script.js rename to libreto/assets/script.js index ba9223a..a717cd6 100644 --- a/assets/script.js +++ b/libreto/assets/script.js @@ -4,11 +4,7 @@ $(document ).ready( function() { $(this).parent().addClass('active').siblings().removeClass('active'); var name = $(this).attr('data-name-encoded'); var currentUrl = window.location.href.split('://')[1].split('/'); - if (use_subdomain) { - var newUrl = '/' + name; - } else { - var newUrl = '/' + currentUrl[1] + '/' + name;; - } + var newUrl = '/' + currentUrl[1] + '/' + name; window.history.pushState("", "", newUrl); $('article').addClass('loading'); }); diff --git a/assets/style-index.css b/libreto/assets/style-index.css similarity index 92% rename from assets/style-index.css rename to libreto/assets/style-index.css index 11be227..72d132d 100644 --- a/assets/style-index.css +++ b/libreto/assets/style-index.css @@ -63,7 +63,7 @@ Jean-Luc typeface Copyright (c) 2010 Atelier Carvalho Bernau body { font-family: "HKGrotesk"; - font-size: 18pt; + font-size: 16pt; padding: 0; margin: 0; } @@ -132,34 +132,23 @@ form { input[type=input] { font-family: "HKGrotesk"; - font-size: 18pt; + font-size: 16pt; background: none; - border: 1px solid #00da53; - padding: 1rem 2rem; + border: 1px solid #000; + padding: 1rem; width: 100%; margin-bottom: 1rem; } button[type=submit] { font-family: "HKGrotesk"; - font-size: 18pt; - background: #00da53; + font-size: 16pt; + background: #000; color: #fff; border: 0px solid #ccc; - padding: 1rem 2rem; + padding: 1rem; width: 100%; margin-bottom: 1rem; cursor: pointer; border-radius: 2rem; } - -div[class^="lang-"] { - display: none; -} -.current-lang-fr .lang-fr { - display: block; -} - -.current-lang-en .lang-en { - display: block; -} diff --git a/assets/style-reader.css b/libreto/assets/style-reader.css similarity index 93% rename from assets/style-reader.css rename to libreto/assets/style-reader.css index 3491201..faccd2d 100644 --- a/assets/style-reader.css +++ b/libreto/assets/style-reader.css @@ -30,7 +30,10 @@ body { font-family: 'HKGrotesk'; font-size: 16px; - padding: 1rem; +} + +main { + padding: 1rem; max-width: 40rem; } @@ -52,3 +55,10 @@ hr { border-bottom: 1px solid #ccc; margin-bottom: 1rem; } + +img { + max-width: 100%; + height: auto; + margin: auto; + display: block; +} diff --git a/assets/style.css b/libreto/assets/style.css similarity index 86% rename from assets/style.css rename to libreto/assets/style.css index bd05d2e..7361ec7 100644 --- a/assets/style.css +++ b/libreto/assets/style.css @@ -83,16 +83,31 @@ a { hr { border: none; - border-bottom: 1px solid #ccc; - margin-bottom: 1rem; + border-bottom: 1px solid #ddd; + margin: 1rem 0 ; +} + +code { + font-size: .8rem; + padding: .1rem .3rem; + background: #eee; + font-family: 'whoismono', monospace; + border: .5px solid #ddd; + margin: .1rem 0; + display: inline-block; +} + +header p { + margin: 0; } header ul { - margin: 1rem; + margin: 0; + margin-bottom: 1rem; } header li { list-style-type: "– "; - margin-left: 1.1rem; + margin-left: .8rem; list-style-position: outside; } @@ -102,7 +117,8 @@ header u { } header .full a { - border-bottom: 1px solid #ccc; + border: 0; + text-decoration: underline; } #container { @@ -116,18 +132,18 @@ header .full a { header { flex: 2; - padding: 1rem; - padding-top: 3rem; + padding: 3rem 1.5rem 1.5rem 1.5rem; overflow-y: auto; overflow-x: hidden; z-index: 2; - border-right: 1px solid #ccc; + border-right: 1px solid #ddd; position: relative; + font-size: 1rem; } nav { flex: 1; - border-right: 1px solid #ccc; + border-right: 1px solid #ddd; flex-direction: column; display: flex; } @@ -156,7 +172,7 @@ nav li { font-family: 'spungold'; font-size: 1.2rem; padding: 1rem; - border-bottom: 1px solid #ccc; + border-bottom: 1px solid #ddd; } nav li.active a { @@ -164,12 +180,12 @@ nav li.active a { } nav li.settings { - background-color: #ccc; - border-bottom: 1px solid #B3B3B3; + background-color: #eee; + border-bottom: 1px solid #ddd; } nav li.settings:last-child { - border-bottom: 1px solid #ccc; + border-bottom: 1px solid #ddd; } nav ul.menu { @@ -177,8 +193,8 @@ nav ul.menu { } nav ul.helpers { - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; margin-top: -1px; } @@ -192,7 +208,7 @@ nav ul.helpers li { nav ul.helpers li { border: 0; - border-right: 1px solid #ccc; + border-right: 1px solid #ddd; } nav ul.helpers li:last-child { @@ -205,6 +221,11 @@ iframe { border: none; } +header .full { + margin-bottom: 3rem; + font-size: .9rem; +} + header .colophon { font-size: .8rem; display: flex; @@ -229,6 +250,7 @@ header.close div.full { header.close { flex: none; + padding: 1rem; } header.close div { diff --git a/assets/texts/colophon.md b/libreto/assets/texts/colophon.md similarity index 100% rename from assets/texts/colophon.md rename to libreto/assets/texts/colophon.md diff --git a/assets/texts/homepage.md b/libreto/assets/texts/homepage.md similarity index 100% rename from assets/texts/homepage.md rename to libreto/assets/texts/homepage.md diff --git a/assets/texts/translation.yml b/libreto/assets/texts/translation.yml similarity index 100% rename from assets/texts/translation.yml rename to libreto/assets/texts/translation.yml diff --git a/libreto/bootstrap.php b/libreto/bootstrap.php new file mode 100644 index 0000000..51d701f --- /dev/null +++ b/libreto/bootstrap.php @@ -0,0 +1,13 @@ +router()->template(); + $language = $libreto->language(); + $filename = $template . "." . $language . ".yml"; + $dictionnary = Spyc::YAMLLoad(ROOT . DS . 'views' . DS . 'languages' . DS . $filename); + if(array_key_exists($keyword, $dictionnary)): + $text = $dictionnary[$keyword]; + return ($markdown ? parsedown($text) : $text); + else: + return $keyword; + endif; +} + +function parsedown($markdown){ + global $Parsedown; + $html = $Parsedown + ->setBreaksEnabled(true) # enables automatic line breaks + ->text($markdown); + return $html; +} + +function startsWith($haystack, $needle) +{ + $length = strlen($needle); + return (substr($haystack, 0, $length) === $needle); +} + +function endsWith($haystack, $needle) +{ + $length = strlen($needle); + + return $length === 0 || + (substr($haystack, -$length) === $needle); +} diff --git a/libreto/libreto.php b/libreto/libreto.php new file mode 100644 index 0000000..3961bda --- /dev/null +++ b/libreto/libreto.php @@ -0,0 +1,179 @@ + "Libreto", + 'url' => $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER["SERVER_NAME"], + 'default_provider' => 'framapad', + ); + + return $defaults; + } + + public function __construct($options) { + + $this->pads = new Pads(); + $this->router = new Router(); + $this->options = array_merge($this->defaults(), $options); + + $this->set_provider(); + $this->set_name(); + $this->set_language(); + $this->set_mode(); + + } + + public function launch(){ + + $this->set_menu(); + $this->set_pads(); + + // Load template + include ROOT . DS . "views" . DS . "templates" . DS . $this->router()->template() . ".php"; + + } + + public function set_provider(){ + $name = $this->router()->provider() ?: $this->options('default_provider'); + $providers = $this->options('providers'); + if ($name && array_key_exists($name, $providers)) : + $this->provider = $providers[$name]; + endif; + return; + } + + public function provider($key = 'url'){ + return $this->provider[$key]; + } + + public function set_name(){ + $this->name = $this->router()->name(); + } + + public function set_language() { + $language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); + switch ($language){ + case "fr": + $this->language = "fr"; + return "fr"; + break; + + default: + $this->language = "en"; + return "en"; + break; + } + } + + public function language() + { + return $this->language; + } + + public function set_mode() { + if (!isset($_SESSION['mode'])) { + $_SESSION['mode'] = 'read'; + } + if(isset($_GET['mode'])): + if($_GET['mode'] == "write") : + $_SESSION['mode'] = 'write'; + else : + $_SESSION['mode'] = 'read'; + endif; + // redirect to same page without url parameters + $url = strtok($_SERVER["REQUEST_URI"],'?'); + header('Location: ' . $url ); + endif; + $this->mode = $_SESSION['mode']; + } + + public function set_menu(){ + $this->pads()->push('Menu (type: settings visibility: private)'); + $pad = $this->pads()->find('Menu'); + $menu = array_values(array_filter(preg_split('/\r\n|\r|\n/', $pad->txt()))); + $menu = array_map('trim', $menu); + // if menu is filled with default text, make it empty + if(count($menu)): + if( strpos($menu[0], $this->provider('default_text')) === 0 ) : + $menu = array(); + endif; + endif; + $this->menu = $menu; + } + + public function set_pads(){ + $this->pads->push($this->menu); + // find the requested pad or else the first of the menu list + $pad = $this->router()->pad() ?: $this->pads->first(); + // select requested pad + if ($pad): + $pad->select(); + endif; + } + + public function router(){ + // Router + return $this->router; + } + + public function name() { + return $this->name; + } + + public function pads() { + return $this->pads; + } + + public function credits() { + $Parsedown->text(file_get_contents("/libreto/assets/texts/colophon.md")); + } + + public function mode(){ + return $this->mode; + } + + public function options($key){ + if(array_key_exists($key, $this->options)): + return $this->options[$key]; + endif; + return; + } + + public function export(){ + + $title = $this->name(); + $introduction = $this->pads()->find('about')->html(); + + $pads = $this->pads()->children(); + $chapters = array(); + foreach($pads as $pad) : + $chapter = $pad->name(); + $html = $pad->html(); + $chapters[] = array("title" => $chapter, "html" => $html); + endforeach; + + $odt = new \CatoTH\HTML2OpenDocument\Text(); + $odt->addHtmlTextBlock('

' . $title . '

'); + $odt->addHtmlTextBlock($introduction); + foreach ($chapters as $chapter) { + $odt->addHtmlTextBlock('

' . $chapter['title'] . '

'); + $odt->addHtmlTextBlock($chapter['html']); + } + $odt->finishAndOutputOdt('libreto-' . $title . '.odt'); + + } + +} diff --git a/libreto/pad.php b/libreto/pad.php new file mode 100644 index 0000000..989abb5 --- /dev/null +++ b/libreto/pad.php @@ -0,0 +1,166 @@ +color = "#000"; + $this->options = $this->defaults(); + $this->name = trim(preg_replace('/(?=[^\]])\([a-z0-9_-]+:.*?\)/', '', $input)); + + $search = preg_match('/(?=[^\]])\([a-z0-9_-]+:.*?\)/', $input, $options); + if($search): + $this->set_options($options[0]); + endif; + $this->set_urls(); + + } + + public function defaults(){ + $defaults = array( + 'color' => "#000000", + 'type' => "default", + 'url' => false, + 'visibility' => 'visible' + ); + + return $defaults; + } + + public function set_options($options) { + $tag = trim( rtrim( ltrim( $options, '(' ), ')' ) ); + $attributes = "color|url|type|visibility"; + $search = preg_split('!(' . $attributes . '):!i', $tag, false, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); + + $num = 0; + $attr = array(); + // get an associative array attribute=>value + foreach($search as $key) : + if(!isset($search[$num+1])) break; + $key = trim($search[$num]); + $value = trim($search[$num+1]); + $this->options[$key] = $value; + $num = $num+2; + endforeach; + } + + public function options($key){ + if(array_key_exists($key, $this->options)): + return $this->options[$key]; + endif; + return; + } + + public function set_urls() { + global $libreto; + + if($this->options['url']): + $title = array_slice(explode('/', trim('/', $this->options['url'])), -1)[0]; + $url = trim($this->options['url'], '/ '); + else: + $title = urlencode(strtolower($libreto->options('name'))) . "+" . urlencode(strtolower($libreto->name())) . "+" . urlencode(strtolower($this->name)); + $url = $libreto->provider('url') . "/p/" . $title; + endif; + + $this->url = array( + "pad" => $url . $libreto->options('pads_params'), + "reader" => "/reader/" . urlencode($libreto->name()) . '/' . urlencode($this->name), + "txt" => $url . "/export/txt", + "markdown" => $url . "/export/markdown" + ); + + } + + public function type(){ + if(array_key_exists('type', $this->options)): + return $this->options['type']; + endif; + return false; + } + + public function color(){ + if(array_key_exists('color', $this->options)): + return $this->options['color']; + endif; + return false; + } + + public function select() { + $this->selected = true; + return $this; + } + + public function selected(){ + return $this->selected; + } + + public function url($format = 'pad') { + global $libreto; + if($format == "pad"): + if($libreto->mode() == "read"): + return $this->url['reader']; + else: + return $this->url['pad']; + endif; + endif; + return $this->url[$format]; + } + + public function name() { + return $this->name; + } + + public function txt() { + $txt = file_get_contents($this->url('txt')); + return $txt; + } + + public function html() { + + global $Parsedown, $Purifier; + + $markdown = file_get_contents($this->url('markdown')); + // remove \url{} tags + $markdown = preg_replace('#\\\url\{(.+)\}#i', '$1', $markdown); + // replace underline tags + $markdown = preg_replace('#underline(.+)underline#', '$1', $markdown); + // strip slashes + $markdown = stripslashes($markdown); + // parse + $html = $Parsedown->text($markdown); + // sanitize + $html = $Purifier->purify($html); + // return + return $html; + + } + + public function css(){ + $css = strip_tags(file_get_contents($this->url('txt'))); + return $css; + } + + public function visible($filter = false){ + global $libreto; + if($filter) : + $filter = (array)$filter; + else: + $filter = $libreto->mode() == 'read' ? array('visible') : array('visible', 'private'); + endif; + + if(in_array($this->options('visibility'), $filter )) + { + return true; + } + return false; + } + +} diff --git a/libreto/pads.php b/libreto/pads.php new file mode 100644 index 0000000..616a9d0 --- /dev/null +++ b/libreto/pads.php @@ -0,0 +1,83 @@ +push($pads); + } + + public function push($pads){ + $pads = (array)$pads; + foreach ($pads as $pad) : + if(endsWith($pad, '.css')): + $this->pads[] = new Pad($pad . ' (type: settings visibility: private)'); + else: + $this->pads[] = new Pad($pad); + endif; + endforeach; + return $this; + } + + public function css() { + if($css = $this->find('style.css')): + return $css->css(); + endif; + return false; + } + + public function find($p){ + foreach($this->pads as $pad) : + if (strtolower($pad->name()) == strtolower($p)): + return $pad; + endif; + endforeach; + return false; + } + + public function children($filter = false) { + global $libreto; + $pads = array_filter($this->pads, function($pad) use ($filter) { + if($pad->visible($filter)) { return true; } + return false; + }); + $pads = array_values($pads); + return $pads; + } + + public function first() { + $pads = $this->children(); + if(array_key_exists(0, $pads)): + return $pads[0]; + endif; + return; + } + + public function selected(){ + foreach ($this->pads as $pad) { + if($pad->selected()) { return $pad; } + } + return false; + } + + public function selectActivePad() { + + global $libreto; + + // set default pad + $default = $this->first() ?: $this->find("help"); + + // set requested pad + $pad = $libreto->router()->pad() ?: $default; + + $pad->select(); + + return $pad; + + } + +} diff --git a/libreto/router.php b/libreto/router.php new file mode 100644 index 0000000..a7ff709 --- /dev/null +++ b/libreto/router.php @@ -0,0 +1,96 @@ +split(); + } + + public function split() { + + // directories + $directories = explode( '/', trim($_SERVER['REQUEST_URI'], '/') ); + $this->directories = array_filter(array_map("urldecode", $directories)); + + // subdomain + $server_name = explode(".",$_SERVER["SERVER_NAME"]); + if (array_key_exists(0, $server_name) && array_key_exists(2, $server_name)): + $name = urldecode($server_name[0]); + $this->subdomain = strtok( $name ,'?'); + endif; + + } + + public function provider(){ + return $this->subdomain; + } + + public function template(){ + if( array_key_exists(0, $this->directories) ): + $templates = glob(ROOT . DS . "views" . DS . "templates" . DS . "*.php"); + $templates = array_map(function($file) { + return basename($file, ".php"); + }, $templates); + $directory = strtolower($this->directories[0]); + if( in_array($directory, $templates) ): + return $directory; + else: + return "libreto"; + endif; + else: + return "home"; + endif; + } + + public function name(){ + + global $libreto; + + if($this->template() != "libreto"): + $n = 1; + else: + $n = 0; + endif; + + if (array_key_exists($n + 0, $this->directories)): + $name = urldecode($this->directories[$n + 0]); + $name = strtok( $name ,'?'); + return $name; + else: + return false; + endif; + + } + + public function pad(){ + + global $libreto; + + if($this->template() != "libreto"): + $n = 1; + else: + $n = 0; + endif; + + if (array_key_exists($n + 1, $this->directories)): + $name = $this->directories[$n + 1]; + else: + return false; + endif; + + if ($pad = $libreto->pads()->find($name)): + if ($pad->visible()) : + return $pad; + endif; + else: + return false; + endif; + + } + +} diff --git a/libreto/vendor/load.php b/libreto/vendor/load.php new file mode 100644 index 0000000..79b4fb3 --- /dev/null +++ b/libreto/vendor/load.php @@ -0,0 +1,12 @@ +setBreaksEnabled(true); diff --git a/reader.php b/reader.php deleted file mode 100644 index d70983d..0000000 --- a/reader.php +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - Pad reader - - " . $css . "" : "" ?> - - - - - - - diff --git a/snippets/controller.php b/snippets/controller.php deleted file mode 100644 index 8c9d831..0000000 --- a/snippets/controller.php +++ /dev/null @@ -1,8 +0,0 @@ -setBreaksEnabled(true); - -function get_homepage() { - $homepage = get_html(get_url("introduction", "markdown")); - $exerpt = trim(strip_tags($homepage)); - if(strpos($exerpt, "–––––") === 0): - $homepage = get_html(get_url("help", "markdown")); - endif; - return $homepage; -} - -function get_pads_list() { - global $libreto_name, $custom_css; - $pads_list = file(get_url("menu", "txt")); - $pads_list = array_map('trim', $pads_list); - // if pad is filled with default text, make pads_list empty - $firstline = $pads_list[0]; - if( strpos($firstline, "–––––") === 0 ) : - $pads_list = false; - endif; - // if a pad is named style.css, use it as css file - if($pads_list): - foreach ($pads_list as $key=>$pad_name) : - if($pad_name == "style.css"): - array_splice($pads_list, $key, 1); - $custom_css = get_url($pad_name, "txt"); - endif; - endforeach; - endif; - return $pads_list; -} - -function get_url($name, $format = "pad") { - global $pads_host, $instance_name, $pads_params, $libreto_name; - - $server = "http://" . $_SERVER["SERVER_NAME"]; - $pads_prefix = urlencode(strtolower($instance_name)) . "+" . urlencode($libreto_name) . "+"; - $pad_name = $pads_prefix . urlencode($name); - $css_name = $pads_prefix . urlencode("style.css"); - $pad_url = $pads_host . "/p/" . $pad_name; - - if($name == 'help') : - $pad_url = "https://annuel2.framapad.org/p/libreto-help"; - if ($format == "markdown") { - return $pad_url . "/export/markdown"; - } else { - return $server . "/reader.php?host=$pads_host&pad=libreto-help&css=$css_name"; - } - endif; - - switch ($format) : - case 'pad': - if($_SESSION['mode'] == "write") : - return $pad_url . $pads_params ; - else: - //var_dump($pad_url); - return $server . "/reader.php?host=$pads_host&pad=$pad_name&css=$css_name" ; - endif; - break; - - default: - return $pad_url . "/export/" . $format ; - break; - endswitch; -} - -function get_html($markdown_url) { - global $Parsedown, $Purifier; - $markdown = file_get_contents($markdown_url); - // remove \url{} tags - $markdown = preg_replace('#\\\url\{(.+)\}#i', '$1', $markdown); - // replace underline tags - $markdown = preg_replace('#underline(.+)underline#', '$1', $markdown); - // remove slashes - $markdown = stripslashes($markdown); - $html = $Parsedown->text($markdown); - // sanitize html - $html = $Purifier->purify($html); - return $html; -} - -function export() { - global $libreto_name, $homepage, $pads_list; - $title = $libreto_name; - $introduction = $homepage; - - $chapters = $pads_list; - $chapters = array_map(function($chapter){ - $url = get_url($chapter, 'markdown'); - $html = get_html($url); - return array("title" => $chapter, "content" => $html); - }, $chapters); - - $odt = new \CatoTH\HTML2OpenDocument\Text(); - $odt->addHtmlTextBlock('

' . $title . '

'); - $odt->addHtmlTextBlock($homepage); - foreach ($chapters as $chapter) { - $odt->addHtmlTextBlock('

' . $chapter['title'] . '

'); - $odt->addHtmlTextBlock($chapter['content']); - } - $odt->finishAndOutputOdt('Libreto-' . $title . '.odt'); -} - -function get_current_pad_name() { - global $use_subdomain, $pads_list; - if(is_array($pads_list)): - $default_pad = $pads_list[0]; - else: - $default_pad = false; - endif; - $uri = explode( '/', trim($_SERVER['REQUEST_URI'], '/') ); - if($use_subdomain) : - if (array_key_exists(0, $uri)): - $uri = urldecode($uri[0]); - $pad_name = in_array($uri, $pads_list) ? $uri : false; - else : - $pad_name = $default_pad; - endif; - else : - if (array_key_exists(1, $uri)): - $uri = urldecode($uri[1]); - if(is_array($pads_list)) : - $pad_name = in_array($uri, $pads_list) ? $uri : false; - else : - $pad_name = false; - endif; - else : - $pad_name = $default_pad; - endif; - endif; - return $pad_name; -} - -function get_libreto_name() { - global $use_subdomain; - if($use_subdomain) : - $server_name = explode(".",$_SERVER["SERVER_NAME"]); - if (array_key_exists(0, $server_name) && array_key_exists(1, $server_name)): - $name = urldecode($server_name[0]); - $name = strtok( $name ,'?'); - endif; - else: - $uri = explode( '/', trim($_SERVER['REQUEST_URI'], '/') ); - if (array_key_exists(0, $uri)): - $name = urldecode($uri[0]); - $name = strtok( $name ,'?'); - endif; - endif; - return $name; -} - -function get_user_language() { - $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); - switch ($lang){ - case "fr": - return "fr"; - break; - default: - return "en"; - break; - } -} - -function load_translation_file() { - return spyc_load_file("assets/texts/translation.yml"); -} - -function localize($key) { - global $translation, $user_language; - if (array_key_exists($key, $translation)) : - if (array_key_exists($user_language, $translation[$key])) : - return $translation[$key][$user_language]; - elseif (array_key_exists($fallback_language, $translation[$key])) : - return $translation[$key][$fallback_language]; - endif; - else: - return "$key ($user_language)"; - endif; -} diff --git a/snippets/header.php b/snippets/header.php deleted file mode 100644 index 0b99cf9..0000000 --- a/snippets/header.php +++ /dev/null @@ -1,15 +0,0 @@ - - - - - <?= $libreto_name ?> - Libreto - - - - - - ' . $custom_css . '' : '' ?> - - diff --git a/snippets/init.php b/snippets/init.php deleted file mode 100644 index 753d2a1..0000000 --- a/snippets/init.php +++ /dev/null @@ -1,30 +0,0 @@ -"> -
- -
- text(file_get_contents("./assets/texts/colophon.md")); ?> -
- -
-
-

-

- -
- diff --git a/snippets/nav.php b/snippets/nav.php deleted file mode 100644 index c78521b..0000000 --- a/snippets/nav.php +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/views/languages/home.en.yml b/views/languages/home.en.yml new file mode 100644 index 0000000..0853d14 --- /dev/null +++ b/views/languages/home.en.yml @@ -0,0 +1,22 @@ +title: Libreto +logo : http://libreto.net/assets/images/libretonet.png +introduction: > + Libreto is a collaborative notebook based on [framapad](https://framapad.org). + + + It can become a mini-website, a workshop logbook or the tool to write a collective book. + + + Libreto is free and minimal. + + No registration, no connection, anyone can write a Libreto. + +create: Create libreto + +colophon: > + + Libreto is under [GNU/GPLv3 License](https://www.gnu.org/licenses/gpl-3.0.en.html) + + Use and modify on [GitHub](https://github.com/Ventricule/libreto) + + A project initiated by [Pierre Tandille](http://lecollecteur.fr) diff --git a/views/languages/home.fr.yml b/views/languages/home.fr.yml new file mode 100644 index 0000000..0be4227 --- /dev/null +++ b/views/languages/home.fr.yml @@ -0,0 +1,26 @@ +title: Libreto + +logo : http://libreto.net/assets/images/libretonet.png + +introduction: > + Libreto est un carnet de note collaboratif fondé sur [etherpad](http://etherpad.org/). + + + Il peut devenir un mini-site, le carnet de bord d'un workshop ou le support de rédaction d'un livre collectif. + + + Libreto est libre, gratuit, et minimaliste. + + + Pas d'inscription, pas de connexion, tout le monde peut écrire un Libreto. + + +create: Créer un Libreto + +colophon: > + + Libreto est sous [licence GNU/GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html). + + N'hésitez pas à participer sur [GitHub](https://github.com/Ventricule/libreto). + + Un projet initié par [Pierre Tandille](http://lecollecteur.fr). diff --git a/views/languages/libreto.en.yml b/views/languages/libreto.en.yml new file mode 100644 index 0000000..2c889ee --- /dev/null +++ b/views/languages/libreto.en.yml @@ -0,0 +1,45 @@ +title: Libreto +read: Read +write: Write +export: Export +download: Download +update: Update +credits: | + **Crédits** + Graphisme & programmation : [Pierre Tandille](http://lecollecteur.fr) + Typographies : [HK Grotesk](https://hanken.co), [Spun Gold](http://www.co-bay.com/dasein), [Jean-Luc](http://www.carvalho-bernau.com) + Pads : [Etherpad](http://etherpad.org/), [Framapad](http://framapad.org), [Fairkom Board](https://board.net/) +about: | + **About Libreto** + Un Libreto est un carnet de note collaboratif fondé sur framapad. Libreto est libre, gratuit, et minimaliste. [Plus d'infos](http://libreto.net) +help: | + ## Bienvenue ! — [Libreto](http://libreto.net) est un outil d'écriture et de publication collaboratif basé sur [etherpad](https://etherpad.org). + + **Pour commencer :** + - Rédigez la liste de vos pads + - Rechargez la page + - Lancez-vous : écrivez sur vos pads ! + + **Pour partager / collaborer :** + - Sélectionnez et copiez l'URL + - Partagez-là ! + + **Pour diffuser :** + - exportez sous forme de livre, de PDF ou de document ODT + + **Pour personnaliser :** + - Créez une feuille de style en ajoutant un pad style.css à votre menu + + ## Plus d'options : + + **Menu** + + *Exemple :* + Mon pad (url: http://url.pad) + *Options :* + **url** : adresse d'un pad existant + **color** : [nom d'une couleur](https://htmlcolorcodes.com/color-names) / [code hexadecimal](https://htmlcolorcodes.com/color-chart) + **visibility** : visible / private / hidden + + **Exporter un livre** + Créez une feuille de style pour le livre en ajoutant un pad book.css à votre menu diff --git a/views/languages/libreto.fr.yml b/views/languages/libreto.fr.yml new file mode 100644 index 0000000..9bc0014 --- /dev/null +++ b/views/languages/libreto.fr.yml @@ -0,0 +1,46 @@ +title: Libreto +read: Lire +write: Écrire +export: Exporter +download: Télécharger +update: Mettre à jour +credits: | + **Crédits** + Graphisme & programmation : [Pierre Tandille](http://lecollecteur.fr) + Typographies : [HK Grotesk](https://hanken.co), [Spun Gold](http://www.co-bay.com/dasein), [Jean-Luc](http://www.carvalho-bernau.com) + Pads : [Etherpad](http://etherpad.org/), [Framapad](http://framapad.org), [Fairkom Board](https://board.net/) +about: | + **À propos** + Un Libreto est un carnet de note collaboratif fondé sur framapad. Libreto est libre, gratuit, et minimaliste. [Plus d'infos](http://libreto.net) +help: | + ## Bienvenue ! — [Libreto](http://libreto.net) est un outil d'écriture et de publication collaboratif basé sur [etherpad](https://etherpad.org). + + **Pour commencer :** + - Rédigez la liste de vos pads + - Rechargez la page + - Lancez-vous : écrivez sur vos pads ! + + **Pour partager / collaborer :** + - Sélectionnez et copiez l'URL + - Partagez-là ! + + **Pour diffuser :** + - exportez sous forme de livre, de PDF ou de document ODT + + **Pour personnaliser :** + - Créez une feuille de style en ajoutant un pad style.css à votre menu + + ---- + + **Menu** + Pour chaque pad, vous pouvez ajoutez des options entre parenthèses. Exemple : + `Mon pad (url: http://url.pad color: blue)` + *Options disponibles* + **url** : adresse d'un pad existant + **color** : [nom d'une couleur](https://htmlcolorcodes.com/color-names) / [code hexadecimal](https://htmlcolorcodes.com/color-chart) + **visibility** : visible / private / hidden + + ---- + + **Exporter un livre** + Créez une feuille de style pour le livre en ajoutant un pad book.css à votre menu diff --git a/snippets/footer.php b/views/snippets/footer.php similarity index 100% rename from snippets/footer.php rename to views/snippets/footer.php diff --git a/views/snippets/header.php b/views/snippets/header.php new file mode 100644 index 0000000..e793266 --- /dev/null +++ b/views/snippets/header.php @@ -0,0 +1,12 @@ + + + + + + <?= $libreto->name() ?> - Libreto + + + + + + diff --git a/views/snippets/introduction.php b/views/snippets/introduction.php new file mode 100644 index 0000000..91d4d46 --- /dev/null +++ b/views/snippets/introduction.php @@ -0,0 +1,17 @@ + +
+
+ +
+
+
+
+
+ +
+
+

options('name') ?>

+

name() ?>

+ +
+
diff --git a/views/snippets/nav.php b/views/snippets/nav.php new file mode 100644 index 0000000..d34a485 --- /dev/null +++ b/views/snippets/nav.php @@ -0,0 +1,25 @@ + + diff --git a/views/templates/bindery.php b/views/templates/bindery.php new file mode 100644 index 0000000..b61c982 --- /dev/null +++ b/views/templates/bindery.php @@ -0,0 +1,73 @@ + + + + + + <?= $libreto->name() ?> - Libreto + + + + + + + + + + diff --git a/views/templates/export.php b/views/templates/export.php new file mode 100644 index 0000000..403251c --- /dev/null +++ b/views/templates/export.php @@ -0,0 +1,3 @@ +export(); diff --git a/views/templates/home.php b/views/templates/home.php new file mode 100644 index 0000000..127178b --- /dev/null +++ b/views/templates/home.php @@ -0,0 +1,37 @@ + +options('url') . '/' . urlencode($new_name) ); + endif; +endif; +?> + + + + + + + + + Libreto + + + + + +
+ +
+
+ + +
+
+
+
+ +
+ + + diff --git a/views/templates/libreto.php b/views/templates/libreto.php new file mode 100644 index 0000000..61ebb23 --- /dev/null +++ b/views/templates/libreto.php @@ -0,0 +1,17 @@ + + +
+ + +
+ pads()->selected()) : + $iframe = $libreto->pads()->selected()->url(); + else : + header('Location: ?mode=write'); + endif; + ?> + +
+
+ diff --git a/views/templates/reader.php b/views/templates/reader.php new file mode 100644 index 0000000..53c76e4 --- /dev/null +++ b/views/templates/reader.php @@ -0,0 +1,36 @@ + + + + + + <?= $libreto->name() ?> - Libreto + + + + +
+ router()->pad()) : + ?> + pads()->selected()->html() ?> + +

name() ?>

+ pads()->children('visible'); + foreach($pads as $pad) : + ?> +

name() ?>

+
html() ?>
+ +
+ +