From b4061b968296ff5b912c49d6dd1e3153bdd3d6e7 Mon Sep 17 00:00:00 2001 From: "stephen@cubedesigners.com" Date: Mon, 10 Jul 2017 18:00:43 +0000 Subject: [PATCH] Merge changes from master branch. WIP #807 @0.5 --- .../burgermenu/class.ws.html5.compiler.php | 278 ++++++++++++------ 1 file changed, 189 insertions(+), 89 deletions(-) diff --git a/inc/ws/Util/html5/burgermenu/class.ws.html5.compiler.php b/inc/ws/Util/html5/burgermenu/class.ws.html5.compiler.php index eda11afc8..f4bedb827 100644 --- a/inc/ws/Util/html5/burgermenu/class.ws.html5.compiler.php +++ b/inc/ws/Util/html5/burgermenu/class.ws.html5.compiler.php @@ -43,6 +43,7 @@ class wsHTML5Compiler { 'js/libs/fluidbook/fluidbook.desktop.js', 'js/libs/fluidbook/fluidbook.service.js', 'js/libs/fluidbook/fluidbook.l10n.js', + 'js/libs/fluidbook/fluidbook.slider.js', 'js/libs/fluidbook/fluidbook.nav.js', 'js/libs/fluidbook/fluidbook.touch.js', 'js/libs/fluidbook/fluidbook.interact.js', @@ -105,7 +106,7 @@ class wsHTML5Compiler { // 'mmenu/jquery.mmenu.effects.css', ]; - public $specialCSS = array(); + public $specialCSS = array(); public $phonegapStandardPlugins = array('ios' => array('ExternalFileUtil'), 'android' => array('webintent')); public $pluginCSS = array(); @@ -156,7 +157,7 @@ class wsHTML5Compiler { protected $additionalConfig = array(); protected $fontScale = 1; protected $cache = array(); - protected $backgroundsPrefix = 'p'; + protected $backgroundsPrefix = array(); protected $svg = true; protected $config = array(); protected $assets = ''; @@ -170,11 +171,14 @@ class wsHTML5Compiler { protected $multiApp = false; protected $pageLabels = array(); protected $stylesheets = array(); + protected $logfp = null; + protected $logtime = null; function __construct($book_id, $version = 'stable', $phonegap = false, $phonegapVersion = 'latest', $dir = null, $standalone = false, $appcache = false, $home = false) { global $core; + $this->phonegapVersion = wsHTML5::getPhonegapVersion($phonegapVersion); $this->appcache = $appcache; $this->multiApp = $this->home = $home; @@ -200,6 +204,7 @@ class wsHTML5Compiler { return; } $this->book_id = $book_id; + $this->log('Start compilation'); if (is_null($dir)) { $this->dir = WS_BOOKS . '/html5/' . $book_id . '/'; @@ -214,14 +219,25 @@ class wsHTML5Compiler { if (!file_exists($this->dir)) { mkdir($this->dir, 0777, true); } + $this->log('Clean vdir'); $this->daoBook = new wsDAOBook($core->con); $this->book = $this->daoBook->selectById($book_id); $this->pages = $this->daoBook->getPagesOfBook($book_id); - if ($this->book->parametres->mobileVersion == 'html5-images') { - $this->backgroundsPrefix = 't'; - $this->svg = false; + switch ($this->book->parametres->mobileVersion) { + case 'html5-desktop': + $this->backgroundsPrefix = array('t', 'p'); + $svg = true; + break; + case 'html5-images': + $this->backgroundsPrefix = array('t'); + $svg = false; + break; + default: + $this->backgroundsPrefix = array('p'); + $svg = true; + break; } $daoTheme = new wsDAOTheme($core->con); @@ -260,6 +276,20 @@ class wsHTML5Compiler { $this->config = cubeObject::merge($this->book->parametres->toStandardObject(), $this->theme->parametres->toStandardObject()); } + public function log($step) { + $currenttime = microtime(true); + if (null === $this->logfp) { + $this->logfp = fopen('/var/log/extranet/htmlconversions/' . $this->book_id . '.log', 'w+'); + } + if (null === $this->logtime) { + $this->logtime = $currenttime; + } + $time = $currenttime - $this->logtime; + $log = $step . ' | ' . round($time, 3) . 's' . "\n"; + fwrite($this->logfp, $log); + $this->logtime = $currenttime; + } + public function addPageLabel($page, $label) { $this->pageLabels[$label] = $page; } @@ -289,6 +319,8 @@ class wsHTML5Compiler { public function compile() { + $this->log('Start compile process'); + $dirsToCreate = array('data/images', 'data/contents', 'data/background', 'data/thumbnails', 'data/style'); if (in_array('flv', $this->getVideosFormats())) { $dirsToCreate[] = 'swf'; @@ -323,17 +355,27 @@ class wsHTML5Compiler { if (file_exists($this->vdir . '/swf')) { $this->copy($this->assets . '/swf/video.swf', $this->vdir . '/swf/video.swf'); } - + $this->log('Copied assets'); $this->loadPlugins(); + $this->log('Plugins loaded'); $this->writeImages(); + $this->log('Images written'); $linksCSS = $this->writeLinks(); + $this->log('Links written'); $this->writeCSS($this->vdir . '/data/style/style_%d.css', $linksCSS); + $this->log('CSS written'); $this->writeLangs(); + $this->log('Langs written'); $this->writeIndex(); + $this->log('Index written'); $this->writeTexts(); + $this->log('Texts written'); $this->writeExtras(); + $this->log('Extras written'); $this->writeJs(); + $this->log('Js written'); $this->writeCache(); + $this->log('Cache written'); } protected function loadPlugins() { @@ -376,16 +418,16 @@ class wsHTML5Compiler { public function getVideosFormats($poster = true) { $res = []; -// -// if (!$this->phonegap) { -// $res = array('ogv', 'webm', 'mp4', 'flv'); -// } elseif ($this->phonegap == 'ios') { -// $res = array('mp4'); -// } else if ($this->phonegap == 'android') { -// $res = array('webm', 'mp4'); -// } + // + // if (!$this->phonegap) { + // $res = array('ogv', 'webm', 'mp4', 'flv'); + // } elseif ($this->phonegap == 'ios') { + // $res = array('mp4'); + // } else if ($this->phonegap == 'android') { + // $res = array('webm', 'mp4'); + // } - $res[] = 'mp4'; + $res[] = 'mp4'; if ($poster) { $res[] = 'jpg'; @@ -442,37 +484,37 @@ class wsHTML5Compiler { file_put_contents($cacheFile, implode("\n", $lines)); } - /** - * Helper function to add a unique script entry to the JS stack. - * Normally this is a relative path but it can be an external URL. - * External URLs are added to the pluginJs collection instead of jsFiles. - * Duplicate paths are ignored. - * @param $path - */ - public function addJs($path) { - - // If JS is external, it will be included via the pluginJs collection - // Otherwise, it will be compiled into the main JS file - $collection = (preg_match('#^https?://#i', $path) === 1) ? 'pluginJs' : 'jsFiles'; - - if (!in_array($path, $this->$collection)) { - $this->{$collection}[] = $path; - } + /** + * Helper function to add a unique script entry to the JS stack. + * Normally this is a relative path but it can be an external URL. + * External URLs are added to the pluginJs collection instead of jsFiles. + * Duplicate paths are ignored. + * @param $path + */ + public function addJs($path) { + + // If JS is external, it will be included via the pluginJs collection + // Otherwise, it will be compiled into the main JS file + $collection = (preg_match('#^https?://#i', $path) === 1) ? 'pluginJs' : 'jsFiles'; + + if (!in_array($path, $this->$collection)) { + $this->{$collection}[] = $path; + } } - /** - * Helper function to add a unique stylesheet entry to the LESS stack for compilation - * Duplicate paths are ignored. - * @param $path The path of the file relative to the /style folder, without any extension - * @param $extra_files Optional array of extra files that should be copied across for use during LESS compilation - */ - public function addLess($path, $extra_files = []) { - if (!in_array($path, $this->lessFiles)) { - $this->lessFiles[] = $path; - } - - // Make sure no duplicates are added here either - $this->lessFilesExtras = array_unique(array_merge($this->lessFilesExtras, $extra_files)); + /** + * Helper function to add a unique stylesheet entry to the LESS stack for compilation + * Duplicate paths are ignored. + * @param $path The path of the file relative to the /style folder, without any extension + * @param $extra_files Optional array of extra files that should be copied across for use during LESS compilation + */ + public function addLess($path, $extra_files = []) { + if (!in_array($path, $this->lessFiles)) { + $this->lessFiles[] = $path; + } + + // Make sure no duplicates are added here either + $this->lessFilesExtras = array_unique(array_merge($this->lessFilesExtras, $extra_files)); } protected function writeIndex() { @@ -510,6 +552,11 @@ class wsHTML5Compiler { if ($this->book->parametres->googleAnalyticsCustom != '') { $ga .= $this->book->parametres->googleAnalyticsCustom; } + + $statsfooter = ''; + if ($this->book->parametres->statsCustom != '') { + $statsfooter = $this->book->parametres->statsCustom; + } // Feuilles de style $sheets = array_merge($this->stylesheets, $this->specialCSS); @@ -577,7 +624,7 @@ class wsHTML5Compiler { } - $vars = array('titre', 'credits', 'ga', 'style', 'script', 'pagesContents', 'description', 'print', 'hiddenContents', 'splash', 'cache', 'bgcolor', 'message', 'favicon', 'svg'); + $vars = array('titre', 'credits', 'statsfooter', 'ga', 'style', 'script', 'pagesContents', 'description', 'print', 'hiddenContents', 'splash', 'cache', 'bgcolor', 'message', 'favicon', 'svg'); foreach ($vars as $v) { $html = str_replace('', $$v, $html); } @@ -606,13 +653,13 @@ class wsHTML5Compiler { $thtml = $uhtml; - $vars = array('titre', 'credits', 'ga', 'style', 'script', 'pagesContents', 'print', 'hiddenContents', 'splash', 'cache', 'bgcolor', 'message', 'favicon'); + $vars = array('titre', 'credits', 'statsfooter', 'ga', 'style', 'script', 'pagesContents', 'print', 'hiddenContents', 'splash', 'cache', 'bgcolor', 'message', 'favicon'); foreach ($vars as $v) { $uhtml = str_replace('', $$v, $uhtml); } $script .= "\n\t\t" . ''; - $vars = array('titre', 'credits', 'ga', 'style', 'script', 'print', 'hiddenContents', 'splash', 'message'); + $vars = array('titre', 'credits', 'statsfooter', 'ga', 'style', 'script', 'print', 'hiddenContents', 'splash', 'message'); foreach ($vars as $v) { $thtml = str_replace('', $$v, $thtml); } @@ -886,7 +933,7 @@ class wsHTML5Compiler { } if (file_exists($minimized)) { $mintime = filemtime($minimized); - $reminimize = false; + $reminimize = false; } else { $mintime = 0; $reminimize = true; @@ -1015,6 +1062,7 @@ class wsHTML5Compiler { } } } + $this->config->rasterizePages = cubeArray::parseRange($this->config->rasterizePages); return 'var DATAS=' . json_encode($this->config) . ';' . "\n"; } @@ -1067,14 +1115,13 @@ class wsHTML5Compiler { foreach ($this->getResolutions() as $r) { mkdir($this->vdir . '/data/background/' . $r, 0777, true); } - $srcPrefix = $this->backgroundsPrefix; - if ($this->backgroundsPrefix == 'p') { - $srcPrefix = 'h'; - } + + $thumbs = array(); foreach ($this->pages as $page => $infos) { + $docdir = wsDocument::getDir($infos['document_id']); if ($this->svg) { - $orig = wsDocument::getDir($infos['document_id']) . 'html/p' . $infos['document_page'] . '.svg'; - $opt = wsDocument::getDir($infos['document_id']) . 'html/o' . $infos['document_page'] . '.svg'; + $orig = $docdir . 'html/p' . $infos['document_page'] . '.svg'; + $opt = $docdir . 'html/o' . $infos['document_page'] . '.svg'; $svg = $orig; if (file_exists($opt) && filesize($opt) > 0) { @@ -1085,10 +1132,17 @@ class wsHTML5Compiler { } foreach ($this->getResolutions() as $r) { - $ok = $this->copy(wsDocument::getDir($infos['document_id']) . 'html/' . $srcPrefix . $r . '-' . $infos['document_page'] . '.jpg', $this->vdir . '/data/background/' . $r . '/' . $this->backgroundsPrefix . $page . '.jpg'); - if (!$ok && $r = 300) { - $this->maxRes = 150; + foreach ($this->backgroundsPrefix as $backgroundsPrefix) { + $srcPrefix = $backgroundsPrefix; + if ($backgroundsPrefix == 'p') { + $srcPrefix = 'h'; + } + $ok = $this->copy($docdir . 'html/' . $srcPrefix . $r . '-' . $infos['document_page'] . '.jpg', $this->vdir . '/data/background/' . $r . '/' . $backgroundsPrefix . $page . '.jpg'); + if (!$ok && $r = 300) { + $this->maxRes = 150; + } } + $this->copy(WS_DOCS . '/' . $infos['document_id'] . '/p' . $infos['document_page'] . '.jpg', $this->vdir . '/data/thumbnails/p' . $page . '.jpg'); } $thumb = false; @@ -1096,16 +1150,54 @@ class wsHTML5Compiler { $thumb = wsPDFConvert::getThumbFromPDF(WS_BOOKS . '/working/' . $this->book->book_id . '/' . $this->book->parametres->pdfThumbnails, $page); } if (!$thumb) { - $thumb = wsDocument::getDir($infos['document_id']) . 'p' . $infos['document_page'] . '.jpg'; + $thumb = $docdir . 'p' . $infos['document_page'] . '.jpg'; } - - $this->copy($thumb, $this->vdir . '/data/thumbnails/p' . $page . '.jpg'); + $thumbs[$page] = $thumb; if ($page == 1) { - $this->_makeCover(wsDocument::getDir($infos['document_id']) . 'html/t36-' . $infos['document_page'] . '.jpg'); + $this->_makeCover($docdir . 'html/t36-' . $infos['document_page'] . '.jpg'); + } + $this->makeThumbSprites($thumbs); + $this->log('Copied image ' . $page); + } + } + + public function makeThumbSprites(array $thumbs) { + $cols = 10; + $rows = 10; + $perSprite = $cols * $rows; + $k = 0; + $res = ''; + $pages = count($thumbs); + + $hash = ''; + for ($i = 1; $i <= $pages; $i += $perSprite) { + $num = min(1 + $pages - $i, $perSprite); + $srows = ceil($num / $cols); + $files = array(); + $mtime = 0; + for ($j = 0; $j < $perSprite; $j++) { + $p = $i + $j; + if ($p > $pages) { + break; + } + $files[] = $thumbs[$p]; + $hash .= $thumbs[$p] . '--' . filemtime($thumbs[$p]); } + + $cache = WS_CACHE . '/thumbsprites/' . hash('sha256', $hash) . '.jpg'; + $dest = $this->vdir . '/data/thumbnails/s' . $k . '.jpg'; + if (!file_exists($cache)) { + $ratio = $this->width / $this->height; + $thumbh = round(100 / $ratio); + $cmd = 'montage ' . implode(' ', $files) . ' -geometry 100x' . $thumbh . '!+0+0 -background transparent -tile ' . $cols . 'x' . $srows . ' ' . $cache; + $res .= `$cmd`; + } + copy($cache, $dest); + $k++; } + return $res; } protected function _makeCover($orig) { @@ -1149,10 +1241,16 @@ class wsHTML5Compiler { return true; } + protected function _lessBoolean($val) { + return $val ? 'true' : 'false'; + } + protected function writeCSS($file, $links) { $res = array(); $lessVariables = array(); + $lessVariables['slider-display'] = $this->_lessBoolean($this->theme->parametres->pagesBar); + $lessVariables['slider-thumb-background'] = wsHTML5::colorToCSS($this->theme->parametres->pageBarThumbBack); // General theme $cssWidth = $this->cssWidth; @@ -1170,8 +1268,11 @@ class wsHTML5Compiler { $offsetLeft2 = $offsetLeft * 2; $offsetTop = round(($this->optimalHeight - $cssHeight) / 2, 3); $navTop = ($cssHeight - 40 - 100) / 2; - $leftOfRightPage=(floor($cssWidth)-1).'px'; + $leftOfRightPage = (floor($cssWidth) - 1) . 'px'; + $lessVariables['z'] = $this->z; + $lessVariables['book-page-width'] = $w; + $lessVariables['book-page-height'] = $h; $res[] = '.portrait #pages,.portrait .doublePage.page,.page,.doublePage._3d,#shadow>div{width:' . $w . ';max-width:' . $w . ';height:' . $h . ';max-height:' . $h . '}'; $res[] = '.doublePage,#pages,#links{width:' . $w2 . ';max-width:' . $w2 . ';height:' . $h . ';max-height:' . $h . '}'; @@ -1186,12 +1287,10 @@ class wsHTML5Compiler { $res[] = '#links.right{left:-' . $w . ';}'; $res[] = '.landscape #shadow>div.right{left: ' . $w . ';}'; $res[] = '.landscape .page.right{left:' . $w . '}'; - if ($this->theme->parametres->displayPageNumber) { - $res[] = '#pagesnumbers{font-size: ' . (12 * $this->z) . 'px;margin: ' . (5 * $this->z) . 'px 0 0 0;top:' . $h . ';color:' . wsHTML5::colorToCSS($this->theme->parametres->colorPageNumber) . '}'; - $res[] = '#pagesnumbers div{width:' . $w . '}'; - } else { - $res[] = '#pagesnumbers{display:none;}'; - } + + $lessVariables['page-number-color'] = wsHTML5::colorToCSS($this->theme->parametres->colorPageNumber); + $lessVariables['display-page-number'] = $this->_lessBoolean($this->theme->parametres->displayPageNumber); + $res[] = '.doublePage._2d,.doublePage._3d{' . wsHTML5::writeCSSUA('transition', 'all ' . $this->book->parametres->mobileTransitionDuration . 's ease-in-out') . '}'; $res[] = '.background{' . wsHTML5::writeCSSUA('transform-origin', 'top left') . ';}'; @@ -1287,11 +1386,10 @@ class wsHTML5Compiler { $res[] = '#shadow>div{' . wsHTML5::writeCSSUA('box-shadow', '0 0 20px ' . $shadowColor) . '}'; } + $lessVariables['links-color'] = wsHTML5::colorToCSS($this->theme->parametres->linksColor); + // Links Styles $res = array_merge($res, $links); - $res[] = '.link a.displayArea:hover,.link a.displayArea.animating{background-color:' . wsHTML5::colorToCSS($this->theme->parametres->linksColor, 0.4) . ';}'; - $res[] = '.link a.displayArea:hover{opacity:1 !important;}'; - $res[] = '.link a.displayArea{-webkit-tap-highlight-color:' . wsHTML5::colorToCSS($this->theme->parametres->linksColor, 0.4) . ';background-color:' . wsHTML5::colorToCSS($this->theme->parametres->linksColor, 0.0001) . ';}'; // Bookmarks if (!isset($this->book->parametres->bookmarkCornerSize)) { @@ -1326,12 +1424,14 @@ class wsHTML5Compiler { # Index $ratio = $this->width / $this->height; $thumbh = round(100 / $ratio); + $this->config->thumbHeight = $thumbh; $lessVariables['thumb-height'] = $thumbh . 'px'; - # Tooltip - $res[] = '#tooltip{background-color:' . wsHTML5::colorToCSS($this->theme->parametres->tooltipBackColor) . ';color:' . wsHTML5::colorToCSS($this->theme->parametres->tooltipTextColor) . ';}'; + #tooltip + $lessVariables['tooltip-background'] = wsHTML5::colorToCSS($this->theme->parametres->tooltipBackColor); + $lessVariables['tooltip-color'] = wsHTML5::colorToCSS($this->theme->parametres->tooltipTextColor); - # ZoomPopup close button background + # ZoomPopup close button background $res[] = '.zoomPopupClose {background-color:' . wsHTML5::colorToCSS($this->theme->parametres->couleurB) . ';}'; @@ -1355,8 +1455,8 @@ class wsHTML5Compiler { $tmp = CubeIT_Files::tmpdir(); - copy($this->assets . '/style/variables.less', $tmp . '/variables.less'); - copy($this->assets . '/style/mixins.less', $tmp . '/mixins.less'); + $from = $this->assets . '/style/*'; + `cp -r $from $tmp`; $bookVariables = array(); foreach ($variables as $k => $v) { @@ -1364,38 +1464,38 @@ class wsHTML5Compiler { } file_put_contents($tmp . '/book-variables.less', implode("\n", $bookVariables)); - // Also copy any "extra" files that might be needed by LESS compilation - // (eg. video-js-core.css is needed by videojs.less) - foreach ($this->lessFilesExtras as $extra) { - $destination_extra = $tmp . '/' . $extra; + // Also copy any "extra" files that might be needed by LESS compilation + // (eg. video-js-core.css is needed by videojs.less) + foreach ($this->lessFilesExtras as $extra) { + $destination_extra = $tmp . '/' . $extra; if (!is_dir(dirname($destination_extra))) { mkdir(dirname($destination_extra), 0777, true); } - copy($this->assets . '/style/' . $extra, $destination_extra); - } + copy($this->assets . '/style/' . $extra, $destination_extra); + } foreach ($this->lessFiles as $f) { - $source_less = $this->assets . '/style/' . $f . '.less'; - $destination_less = $tmp . '/' . $f . '.less'; - $destination_css = 'style/' . $f . '.css'; + $source_less = $this->assets . '/style/' . $f . '.less'; + $destination_less = $tmp . '/' . $f . '.less'; + $destination_css = 'style/' . $f . '.css'; if (!file_exists($source_less)) { continue; } - // LESS file might be in a subfolder, so create if it doesn't exist + // LESS file might be in a subfolder, so create if it doesn't exist if (!is_dir(dirname($destination_less))) { mkdir(dirname($destination_less), 0777, true); } - // Generated CSS file might be in a subfolder, so create if it doesn't exist + // Generated CSS file might be in a subfolder, so create if it doesn't exist if (!is_dir(dirname($this->vdir . '/' . $f . '.css'))) { mkdir(dirname($this->vdir . '/' . $f . '.css'), 0777, true); } // Less files must be copied to temporary directory so they'll - // have access to the variables generated in book-variables.less - copy($source_less, $destination_less); + // have access to the variables generated in book-variables.less + copy($source_less, $destination_less); $less = new CubeIT_CommandLine('lessc'); $less->setArg('plugin', 'less-plugin-clean-css'); $less->setArg(null, $destination_less); -- 2.39.5