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 0000000..4abedfc Binary files /dev/null and b/libreto/assets/images/logo.png differ diff --git a/assets/images/logo.svg b/libreto/assets/images/logo.svg similarity index 100% rename from assets/images/logo.svg rename to libreto/assets/images/logo.svg diff --git a/libreto/assets/js/bindery-controls.min.js b/libreto/assets/js/bindery-controls.min.js new file mode 100644 index 0000000..9431a1f --- /dev/null +++ b/libreto/assets/js/bindery-controls.min.js @@ -0,0 +1,2 @@ +var BinderyControls=function(){"use strict";var e,t,n,o=(t=String.prototype.split,n=/()??/.exec("")[1]===e,function(o,r,i){if("[object RegExp]"!==Object.prototype.toString.call(r))return t.call(o,r,i);var a,s,l,p,c=[],u=(r.ignoreCase?"i":"")+(r.multiline?"m":"")+(r.extended?"x":"")+(r.sticky?"y":""),d=0;for(r=new RegExp(r.source,u+"g"),o+="",n||(a=new RegExp("^"+r.source+"$(?!\\s)",u)),i=i===e?-1>>>0: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() ?>
+ +
+ +