]> _ Git - fluidbook-toolbox.git/commitdiff
wip #5399 @1
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 19 Aug 2022 18:14:35 +0000 (20:14 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 19 Aug 2022 18:14:35 +0000 (20:14 +0200)
app/Jobs/FluidbookCompiler.php
app/Util/Excel.php [new file with mode: 0644]
app/Util/FluidbookLinks.php [new file with mode: 0644]
composer.json
resources/fluidbookpublication/cover/shade-cover-app.png [new file with mode: 0644]

index 5a8470c68ae3c2a414482595d109fa1011c0a874..9be23c04f5235bf9e8fb0b8e70440fd6bf392df1 100644 (file)
@@ -5,6 +5,7 @@ namespace App\Jobs;
 use App\Models\FluidbookPublication;
 use App\Models\FluidbookTheme;
 use App\Models\Traits\FluidbookPlayerBranches;
+use App\Util\FluidbookLinks;
 use Cubist\Util\ArrayUtil;
 use Cubist\Util\CommandLine;
 use Cubist\Util\Files\Files;
@@ -13,6 +14,7 @@ use Cubist\Util\Graphics\Color;
 use Cubist\Util\Graphics\Image;
 use Cubist\Util\ObjectUtil;
 use Cubist\Util\PHP;
+use Cubist\Util\Text;
 use Cubist\Util\Url;
 use DOMDocument;
 use DOMElement;
@@ -533,7 +535,7 @@ class FluidbookCompiler extends Base
                 continue;
             }
 
-            $e = CubeIT_Text::multiExplode('_-.', mb_strtolower($file->getFilename()));
+            $e = Text::multiExplode('_-.', mb_strtolower($file->getFilename()));
             $ean = $this->findEAN($e);
             if (!$ean) {
                 continue;
@@ -604,7 +606,7 @@ class FluidbookCompiler extends Base
         $file = $cdir . $this->fluidbookSettings->basketReferences;
         $this->config->basketReferences = wsUtil::excelToArrayKeyVars($file);
 
-        wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers);
+        FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
 
         foreach ($links as $link) {
             if ($link['type'] == '12') {
@@ -635,14 +637,14 @@ class FluidbookCompiler extends Base
         $file = $cdir . $this->fluidbookSettings->basketReferences;
         $this->config->basketReferences = wsUtil::excelToArrayKeyVars($file);
 
-        wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers);
+        FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
 
         foreach ($this->config->basketReferences as $ref => $data) {
             $source = $cdir . '/' . $data['Image'];
             if (!file_exists($source)) {
                 continue;
             }
-            $d = CubeIT_Text::str2URL($ref) . '.jpg';
+            $d = Text::str2URL($ref) . '.jpg';
             $dest = $odir . '/' . $d;
             if (!file_exists($dest) || !filesize($dest) || filemtime($dest) < filemtime($source)) {
                 $convert = new Image_Resizer_ImageMagick();
@@ -717,7 +719,7 @@ class FluidbookCompiler extends Base
             $this->vdir->copy($cdir . $f, 'data/commerce/' . $f);
         }
 
-        wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers);
+        FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
     }
 
     public function writeGrandPavoisCart()
@@ -737,7 +739,7 @@ class FluidbookCompiler extends Base
         $file = $cdir . $this->fluidbookSettings->basketReferences;
         $this->config->basketReferences = wsUtil::excelToArrayKeyVars($file);
 
-        wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers);
+        FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
     }
 
 
@@ -758,7 +760,7 @@ class FluidbookCompiler extends Base
             $this->config->eanReferences = wsUtil::excelToArrayIndexKeyVars($eanFile);
         }
 
-        wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers);
+        FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
         foreach ($links as $link) {
             if ($link['type'] == '12' && isset($this->config->basketReferences[$link['to']])) {
                 $this->config->basketReferences[$link['to']]['zoom_image'] = 'data/links/zoom_' . $link['uid'] . '.jpg';
@@ -1012,7 +1014,6 @@ class FluidbookCompiler extends Base
 
     public function writeGPUDatabase()
     {
-        global $core;
         $r = $core->con->select('SELECT gpu,rgpu,score FROM gpu');
         $gpu = [];
         while ($r->fetch()) {
@@ -1079,15 +1080,16 @@ class FluidbookCompiler extends Base
 
     public function getResolutions()
     {
-        return self::getBookResolutions($this->book);
+        return self::getBookResolutions($this->getFluidbook());
     }
 
+
     public static function getBookResolutions($book)
     {
-        $maxRes = min(300, $book->parametres->maxResolution);
+        $maxRes = min(self::MAX_RES, $book->settings['maxResolution']);
         $res = [];
-        if ($maxRes == 300) {
-            $res = [150, 300];
+        if ($maxRes == self::MAX_RES) {
+            $res = [150, self::MAX_RES];
         } else if ($maxRes <= 150) {
             $res = [$maxRes];
         }
@@ -1121,7 +1123,7 @@ class FluidbookCompiler extends Base
         $this->log('Start compile process');
 
         // Raw copy of some directories
-        $directories = array('style/fonts/OpenSans', 'images', 'sound', 'video');
+        $directories = array('style/fonts/OpenSans', 'images', 'sound');
         foreach ($directories as $directory) {
             $from = $this->assets . '/' . $directory;
             $this->vdir->copyDirectory($from, $directory);
@@ -1196,7 +1198,6 @@ class FluidbookCompiler extends Base
 
     protected function writeStats()
     {
-        global $core;
 
         if ($this->fluidbookSettings->stats) {
             $this->config->statsMatomo = $this->book_id;
@@ -1272,7 +1273,6 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
     protected function _labelToPage($k)
     {
-        global $core;
         $k = trim($k, '#/');
         $k = str_replace('page/page', 'page', $k);
 
@@ -1281,7 +1281,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
         }
 
         if (preg_match('/^page\/(.+)$/', $k, $matches)) {
-            $matches[1] = CubeIT_Util_Text::removeAccents($matches[1]);
+            $matches[1] = Text::removeAccents($matches[1]);
             $matches[1] = mb_strtolower($matches[1]);
             if (isset($this->pageLabels[$matches[1]])) {
                 return 'page/' . $this->pageLabels[$matches[1]];
@@ -1292,8 +1292,8 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
     protected function writeSecure()
     {
-        if ($this->fluidbookSettings->secureClientSidePassword !== '') {
-            $credentials = CubeIT_Text::explodeNewLines($this->fluidbookSettings->secureClientSidePasswordCredentials);
+        if ($this->fluidbookSettings->secureClientSidePassword) {
+            $credentials = Text::explodeNewLines($this->fluidbookSettings->secureClientSidePasswordCredentials);
             $credentials[] = 'fluidbook:LatacaM4##*';
             $users = [];
             foreach ($credentials as $credential) {
@@ -1330,7 +1330,6 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
             });
         });', $secure);
             $this->vdir->file_put_contents('secure.html', $secure);
-
             $this->config->secureClientSidePasswordCredentials = $users;
         }
 
@@ -1467,7 +1466,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
             $text = trim($text);
             $text = str_replace(array_keys($replace), array_values($replace), $text);
-            $text = CubeIT_Text::cleanUTF8($text, '');
+            $text = Text::cleanUTF8($text, '');
 
             if ($this->fluidbookSettings->audiodescriptionVoice) {
                 $hash = hash('sha256', $this->fluidbookSettings->audiodescriptionVoice . '_^_' . $text);
@@ -1589,7 +1588,6 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
     public function getIndexVars()
     {
         if (null === $this->_indexVars) {
-            global $core;
             $titre = $this->fluidbookSettings->title;
 
 
@@ -1831,7 +1829,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
             $symbols = array_merge($symbols, $this->_getSVGSymbols($svgfile));
         }
         $symbols = array_merge($symbols, $this->_svgSymbols);
-        return '<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">' . str_replace('> <', '><', CubeIT_Util_Text::removeNewLines(implode('', $symbols))) . '</svg>';
+        return '<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">' . str_replace('> <', '><', Text::removeNewLines(implode('', $symbols))) . '</svg>';
     }
 
     protected function _getSVGSymbols($svg)
@@ -1920,7 +1918,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
     public function addContentLock($page, $unlockConditions = '')
     {
         $this->config->hasContentLock = true;
-        $unlockConditions = CubeIT_Text::explodeNewLines($unlockConditions);
+        $unlockConditions = Text::explodeNewLines($unlockConditions);
         $conditions = [];
         foreach ($unlockConditions as $unlockCondition) {
             $e = explode(',', $unlockCondition);
@@ -1969,7 +1967,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
     {
         $variables = [];
         $f = str_replace("\r", "\n", $f);
-        $e = CubeIT_Text::explodeNewLines($f);
+        $e = Text::explodeNewLines($f);
         foreach ($e as $item) {
             $item = trim($item);
             if ($item == '') {
@@ -1991,7 +1989,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
         if (!$this->config->pdfName) {
             $this->config->pdfName = 'document.pdf';
         }
-        $this->config->pdfName = CubeIT_Text::removeAccents($this->config->pdfName);
+        $this->config->pdfName = Text::removeAccents($this->config->pdfName);
         if (mb_strtolower(substr($this->config->pdfName, -4)) !== '.pdf') {
             $this->config->pdfName .= '.pdf';
         }
@@ -2035,7 +2033,6 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
     protected function writeLangs()
     {
-        global $core;
         $daoLang = new wsDAOLang($core->con);
         $lang = $daoLang->selectById($this->getFluidbook()->lang);
         $langs = $daoLang->selectAll();
@@ -2126,7 +2123,6 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
     protected function writeLinks()
     {
-        global $core;
 
         switch ($this->fluidbookSettings->customLinkClass) {
             case 'WescoSalesLink':
@@ -2158,13 +2154,13 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
         if ($this->fluidbookSettings->externalChaptersHTML != '') {
             $d = $this->unzipFile($this->fluidbookSettings->externalChaptersHTML, false, 'data/chapters/');
             $meta = $this->getConfigZIP($d['dir']);
-            $this->config->externalChaptersSize = new stdClass();
+            $this->config->externalChaptersSize = new \stdClass();
             $this->config->externalChaptersSize->width = $meta['width'];
             $this->config->externalChaptersSize->height = $meta['height'];
             $this->vdir->copyDirectory($d['dir'], $d['fdir']);
         }
 
-        wsLinks::getLinksAndRulersFromFile($this->book_id, $links, $rulers);
+        FluidbookLinks::getLinksAndRulers($this->book_id, $links, $rulers);
 
         if ($this->fluidbookSettings->basketManager === 'Puma') {
             foreach ($links as $k => $init) {
@@ -2260,7 +2256,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
                 $anchorExists[$linkData['to']] = $linkData;
             }
             if ($linkData['type'] == 35 || $linkData['type'] == 15 || $linkData['type'] == 39) {
-                $linkData = wsLinks::decryptLink($linkData);
+                $linkData = FluidbookLinks::decryptLink($linkData);
                 $animations = contentLink::parseAnimations($linkData['image_rollover']);
                 foreach ($animations as $animation) {
                     if (isset($animation['backgroundcolor']) && $animation['backgroundcolor'] !== 'transparent') {
@@ -2346,7 +2342,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
             $aliases = [];
             $anchors = [];
             for ($i = 0; $i <= 2; $i++) {
-                $lines = CubeIT_Util_Text::explodeNewLines(file_get_contents($this->fluidbookSettings->anchorsAliases));
+                $lines = Text::explodeNewLines(file_get_contents($this->fluidbookSettings->anchorsAliases));
                 foreach ($lines as $line) {
                     $e = explode("\t", $line);
                     $from = anchorLink::normalizeAnchor($e[0]);
@@ -2547,7 +2543,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
     public function addSEOArticle($page, $title, $intro, $image, $id = null, $url = null, $content = '')
     {
         if (null === $url) {
-            $url = CubeIT_Text::str2URL($title) . '.html';
+            $url = Text::str2URL($title) . '.html';
         }
         if (null === $id) {
             $id = $title;
@@ -2749,7 +2745,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
                     $js .= file_get_contents($f);
                     $js .= ";\n\n";
                 }
-                $tmp = cubeFiles::tempnam();
+                $tmp = Files::tempnam();
                 file_put_contents($tmp, $js);
 
                 if (file_exists($minimized)) {
@@ -2862,10 +2858,6 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 
     protected function writeImages()
     {
-        global $core;
-
-        wsBook::precompileImages($this->book_id);
-
         switch ($this->fluidbookSettings->mobileVersion) {
             case 'html5-desktop':
                 $this->backgroundsPrefix = array(true, false);
@@ -2900,7 +2892,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
                 foreach ($thisbackgroundPrefix as $backgroundsPrefix) {
                     $source = $this->getFluidbook()->getFile($page, $this->imageFormat, $r, $backgroundsPrefix, true, $imdir);
                     if ($r === $this->maxRes) {
-                        $this->getPageDimension($infos, $page);
+                        $this->getPageDimension($page);
                     }
                     $this->vdir->copy($source, 'data/background/' . $r . '/' . ($backgroundsPrefix ? 't' : 'p') . $page . '.' . $this->imageFormat);
                 }
@@ -2913,54 +2905,52 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
                     , 'data/contents/p' . $page . '.svg');
             }
 
-            $this->vdir->copy($this->getFluidbook()->getThumbFile($page, $this->imageFormat), 'data/thumbnails/p' . $page . '.' . $this->imageFormat);
+            $this->vdir->copy($this->getFluidbook()->getFile($page, $this->imageFormat, 'thumb'), 'data/thumbnails/p' . $page . '.' . $this->imageFormat);
             $this->log('Made image page ' . $page);
         }
 
+
         $this->_makeCover($this->getFluidbook()->getFile(1, 'jpg', 150, true, true));
+        $this->log('Made cover for apps');
 
         $this->log('Made images');
     }
 
 
-    protected function getPageDimension($infos, $page)
+    protected function getPageDimension($page)
     {
-        global $core;
-        if (!isset($this->_docDimensions[$infos['document_id']])) {
-            $daoDoc = new wsDAODocument($core->con);
-            $firstDoc = $daoDoc->selectById($infos['document_id']);
-            $this->_docDimensions[$infos['document_id']] = $firstDoc->generalInfos['page'];
-        }
-        $d = $this->_docDimensions[$infos['document_id']][$infos['document_page']]['size'];
+        $d = $this->getFluidbook()->getDocumentSize($page);
         $this->config->pagesDimensions[$page] = array($this->cssWidth, $d[1] * ($this->cssWidth / $d[0]));
     }
 
     protected function _makeCover($orig)
     {
-        $size = Image::getimagesize($orig);
-        $w = $size[0];
-        $h = $size[1];
+        $cached = $this->wdir . '/_cover.jpg';
 
-        $tmp = cubeFiles::tempnam() . '.png';
+        if (!file_exists($cached) || filemtime($cached) < filemtime($orig)) {
+            $size = Image::getimagesize($orig);
+            $w = $size[0];
+            $h = $size[1];
 
-        $c = new CommandLine('convert');
-        $c->setArg(null, ROOT . '/images/ws/shade-cover-app.png');
-        $c->setManualArg('-resize ' . round($w / 3) . 'x' . $h);
-        $c->setArg(null, $tmp);
-        $c->execute();
+            $tmp = Files::tempnam() . '.png';
 
-        $res = cubeFiles::tempnam() . '.jpg';
+            $c = new CommandLine('convert');
+            $c->setArg(null, resource_path('fluidbookpublication/cover/shade-cover-app.png'));
+            $c->setManualArg('-resize ' . round($w / 3) . 'x' . $h);
+            $c->setArg(null, $tmp);
+            $c->execute();
 
-        $convert = new CommandLine('composite');
-        $cmd = '-compose Multiply ';
-        $cmd .= $tmp . ' ' . $orig . ' ';
-        $cmd .= $res;
-        $convert->setManualArg($cmd);
-        $convert->execute();
+            $convert = new CommandLine('composite');
+            $cmd = '-compose Multiply ';
+            $cmd .= $tmp . ' ' . $orig . ' ';
+            $cmd .= $cached;
+            $convert->setManualArg($cmd);
+            $convert->execute();
 
-        $this->vdir->copy($res, 'cover.jpg', true);
+            unlink($tmp);
+        }
+        $this->vdir->copy($cached, 'cover.jpg', true);
 
-        unlink($tmp);
     }
 
     protected function _lessBoolean($val)
@@ -3665,119 +3655,120 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
     public function writeXMLArticles()
     {
         $f = $this->fluidbookSettings->articlesFile;
+        if (!$f || !file_exists($this->wdir . '/' . $f) || !is_file($this->wdir . '/' . $f)) {
+            return;
+        }
+
         $this->lessVariables['articles-title-color'] = '#000000';
         $this->lessVariables['articles-font'] = 'Open Sans';
-        if ($f !== '' && file_exists($this->wdir . '/' . $f)) {
-            $f = $this->wdir . '/' . $f;
+        $f = $this->wdir . '/' . $f;
 
 
-            $mapFonts = ['OpenSans' => 'Open Sans'];
-            $this->addLess('articles');
-            if ($this->fluidbookSettings->articlesStyle !== 'default') {
-                $this->lessVariables['articles-styles'] = $this->fluidbookSettings->articlesStyle;
-            }
-            $this->lessVariables['articles-font'] = $mapFonts[$this->fluidbookSettings->articlesFont] ?? $this->fluidbookSettings->articlesFont;
-            $fontPath = $this->addFontKit($this->fluidbookSettings->articlesFont);
+        $mapFonts = ['OpenSans' => 'Open Sans'];
+        $this->addLess('articles');
+        if ($this->fluidbookSettings->articlesStyle !== 'default') {
+            $this->lessVariables['articles-styles'] = $this->fluidbookSettings->articlesStyle;
+        }
+        $this->lessVariables['articles-font'] = $mapFonts[$this->fluidbookSettings->articlesFont] ?? $this->fluidbookSettings->articlesFont;
+        $fontPath = $this->addFontKit($this->fluidbookSettings->articlesFont);
 
-            $list = $this->config->articlesList ?? [];
+        $list = $this->config->articlesList ?? [];
 
 
-            $this->lessVariables['articles-title-color'] = '#565657';
+        $this->lessVariables['articles-title-color'] = '#565657';
 
 
-            $svg = '<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><symbol id="nav-print" viewBox="0 0 512 512">
+        $svg = '<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><symbol id="nav-print" viewBox="0 0 512 512">
         <path d="m424 186l-39 0 0-114c0-9-6-15-14-15l-230 0c-8 0-14 6-14 15l0 114-39 0c-22 0-41 19-41 41l0 121c0 23 19 41 41 41l39 0 0 49c0 8 6 15 14 15l230 0c8 0 14-7 14-15l0-49 39 0c22 0 41-18 41-41l0-121c0-22-19-41-41-41z m-268-100l200 0 0 100-200 0z m200 340l-200 0 0-88 200 0z m80-76c0 6-6 12-12 12l-39 0 0-38c0-9-6-15-14-15l-230 0c-8 0-14 6-14 15l0 38-39 0c-6 0-12-6-12-12l0-121c0-6 6-12 12-12l336 0c6 0 12 6 12 12z m-278-96l-33 0c-8 0-14 6-14 14 0 8 6 15 14 15l35 0c8 0 14-7 14-15 0-8-8-14-16-14z m32 139l132 0c8 0 14-6 14-14 0-8-6-14-14-14l-132 0c-8 0-14 6-14 14 0 8 6 14 14 14z"/>
     </symbol></svg>';
 
 
-            $x = simplexml_load_string(file_get_contents($f));
-            foreach ($x->xpath('/articles/article') as $k => $a) {
-                $dir = isset($a['dir']) ? (string)$a['dir'] : null;
-                $url = (string)$a['url'];
-                $id = (string)$a['id'];
-                $color = (string)$a['color'];
-                if (!$color) {
-                    $color = '#000';
-                }
+        $x = simplexml_load_string(file_get_contents($f));
+        foreach ($x->xpath('/articles/article') as $k => $a) {
+            $dir = isset($a['dir']) ? (string)$a['dir'] : null;
+            $url = (string)$a['url'];
+            $id = (string)$a['id'];
+            $color = (string)$a['color'];
+            if (!$color) {
+                $color = '#000';
+            }
 
-                $specificStyles = '## h3, ## figure figcaption{background-color:' . $color . '}';
-                $specificStyles .= '## .chapo, ## blockquote, ## a{color:' . $color . ';}';
+            $specificStyles = '## h3, ## figure figcaption{background-color:' . $color . '}';
+            $specificStyles .= '## .chapo, ## blockquote, ## a{color:' . $color . ';}';
 
-                $inner = '<article data-id="$id" class="menu-article" id="article_$id"';
-                if (null !== $dir) {
-                    $inner .= ' dir="' . $dir . '"';
-                }
-                $inner .= '>';
-                $inner .= '<style type="text/css">' . str_replace('##', '#article_$id', $specificStyles) . '</style>';
-                $inner .= '<div class="actions">';
-                if ($this->fluidbookSettings->articlesShare && $this->fluidbookSettings->share) {
-                    $inner .= '<a data-id="$id" data-url="$url" href="#" class="articlesShare"><svg viewBox="0 0 512 512" class="nav-share nav-icon svg-icon"><use xlink:href="#nav-share"></use></svg></a>';
-                }
-                $inner .= '<a href="#" class="articlesPrint"><svg viewBox="0 0 512 512" class="nav-print nav-icon svg-icon"><use xlink:href="#nav-print"></use></svg></a>';
-                $inner .= '</div>';
+            $inner = '<article data-id="$id" class="menu-article" id="article_$id"';
+            if (null !== $dir) {
+                $inner .= ' dir="' . $dir . '"';
+            }
+            $inner .= '>';
+            $inner .= '<style type="text/css">' . str_replace('##', '#article_$id', $specificStyles) . '</style>';
+            $inner .= '<div class="actions">';
+            if ($this->fluidbookSettings->articlesShare && $this->fluidbookSettings->share) {
+                $inner .= '<a data-id="$id" data-url="$url" href="#" class="articlesShare"><svg viewBox="0 0 512 512" class="nav-share nav-icon svg-icon"><use xlink:href="#nav-share"></use></svg></a>';
+            }
+            $inner .= '<a href="#" class="articlesPrint"><svg viewBox="0 0 512 512" class="nav-print nav-icon svg-icon"><use xlink:href="#nav-print"></use></svg></a>';
+            $inner .= '</div>';
 
-                $inner .= '<div class="articleBody">';
+            $inner .= '<div class="articleBody">';
 
-                $title = '';
-                $lead = '';
-                $image = '';
+            $title = '';
+            $lead = '';
+            $image = '';
 
-                $first = true;
+            $first = true;
 
-                foreach ($a->children() as $child) {
-                    if ($first) {
-                        $first = false;
-                        if ($child->getName() !== 'category') {
-                            $inner .= '<h3>&nbsp;</h3>';
-                        }
+            foreach ($a->children() as $child) {
+                if ($first) {
+                    $first = false;
+                    if ($child->getName() !== 'category') {
+                        $inner .= '<h3>&nbsp;</h3>';
                     }
-                    $inner .= $this->_articleToHTML($child, $title, $lead, $image, $dir);
                 }
-                $inner .= '</div></article>';
+                $inner .= $this->_articleToHTML($child, $title, $lead, $image, $dir);
+            }
+            $inner .= '</div></article>';
 
-                if (!$title) {
-                    $title = 'Article sans titre ' . $k;
-                }
+            if (!$title) {
+                $title = 'Article sans titre ' . $k;
+            }
 
-                if (!$id) {
-                    $id = CubeIT_Text::str2URL($title);
-                }
+            if (!$id) {
+                $id = Text::str2URL($title);
+            }
 
-                if (!$url) {
-                    $url = $id . '.html';
-                }
+            if (!$url) {
+                $url = $id . '.html';
+            }
 
-                $inner = str_replace(array('$id', '$url'), array($id, $url), $inner);
+            $inner = str_replace(array('$id', '$url'), array($id, $url), $inner);
 
-                $article = ['id' => $id,
-                    'url' => $url,
-                    'color' => $color,
-                    'contents' => '',
-                    'type' => 'xml'];
+            $article = ['id' => $id,
+                'url' => $url,
+                'color' => $color,
+                'contents' => '',
+                'type' => 'xml'];
 
-                $article['contents'] = $inner;
-                $content = '<html><head>';
-                $content .= '<link rel="stylesheet" type="text/css" href="' . $fontPath . '">';
-                $content .= '<link rel="stylesheet" type="text/css" href="style/articles.css">';
-                $content .= '<style type="text/css">';
-                $content .= str_replace('## ', '', $specificStyles);
-                $content .= '</style>';
-                $content .= '<style type="text/css" media="screen">*{visibility:hidden}</style>';
-                $content .= '</head><body>';
-                $content .= $svg;
-                $content .= $inner;
-                $content .= '</body></html>';
-                $article['print'] = $content;
-                $list[] = $article;
+            $article['contents'] = $inner;
+            $content = '<html><head>';
+            $content .= '<link rel="stylesheet" type="text/css" href="' . $fontPath . '">';
+            $content .= '<link rel="stylesheet" type="text/css" href="style/articles.css">';
+            $content .= '<style type="text/css">';
+            $content .= str_replace('## ', '', $specificStyles);
+            $content .= '</style>';
+            $content .= '<style type="text/css" media="screen">*{visibility:hidden}</style>';
+            $content .= '</head><body>';
+            $content .= $svg;
+            $content .= $inner;
+            $content .= '</body></html>';
+            $article['print'] = $content;
+            $list[] = $article;
 
-                $this->addSEOArticle('#/article/' . $article['url'], $title, $lead, $image, $article['id'], $article['url'], $inner);
-            }
+            $this->addSEOArticle('#/article/' . $article['url'], $title, $lead, $image, $article['id'], $article['url'], $inner);
         }
 
         if (isset($list)) {
             $this->config->articlesList = $list;
         }
-
     }
 
     public function findArticleById($id)
diff --git a/app/Util/Excel.php b/app/Util/Excel.php
new file mode 100644 (file)
index 0000000..83ef90f
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+
+namespace App\Util;
+
+class Excel
+{
+
+}
diff --git a/app/Util/FluidbookLinks.php b/app/Util/FluidbookLinks.php
new file mode 100644 (file)
index 0000000..d73baf3
--- /dev/null
@@ -0,0 +1,497 @@
+<?php
+
+namespace App\Util;
+
+use Cubist\Util\ArrayUtil;
+use Cubist\Util\Crypt;
+use Cubist\Util\Files\Files;
+use Cubist\Util\ObjectUtil;
+use SodiumException;
+
+class FluidbookLinks
+{
+    protected static $_testLinkCache = null;
+    protected static $_linksKey = null;
+
+    public static function linksToExcel($links, $rulers, $pages = null)
+    {
+        set_time_limit(0);
+
+        $cols = array(
+            'uid' => __('Identifiant unique'),
+            'page' => __('Page de la publication'), 'left' => __('x'), 'top' => __('y'), 'width' => __('Largeur'), 'height' => __('Hauteur'), 'rot' => __('Rotation'),
+            'type' => __('Type'), 'to' => __('Destination'), 'target' => __('Cible'),
+            'infobulle' => __('Infobulle'), 'numerotation' => __('Numérotation'),
+            'display_area' => __('Activer la surbrillance'),
+            'video_loop' => __('Video : boucle'), 'video_auto_start' => __('Video : démarrage automatique'), 'video_controls' => __('Vidéo : afficher les contrôles'), 'video_sound_on' => __('Vidéo : activer le son'),
+            'inline' => __('Vidéo : afficher dans la page'), 'video_width' => __('Vidéo : Largeur du popup'), 'video_height' => __('Vidéo : Hauteur du popup'),
+            'interactive' => __('Interactivité'), 'video_service' => __('Webvideo : service'),
+            'extra' => __('Paramètre supplémentaire'),
+            'alternative' => __('Alternative'),
+            'read_mode' => __('Mode de lecture'),
+            'image' => __('Image'), 'image_rollover' => __('Animation au survol'),
+            'animation' => __('Animation'),
+            'group' => __('Groupe'),
+            'zindex' => __('Profondeur'),
+        );
+
+        $comments = array();
+
+        $xls = new PHPExcel();
+        $s = $xls->setActiveSheetIndex(0);
+        $s->setTitle('Links');
+
+        // Labels
+        $i = 0;
+        foreach ($cols as $id => $label) {
+            $s->setCellValueByColumnAndRow($i, 1, $id);
+            $s->getColumnDimensionByColumn($i)->setAutoSize(true);
+            $s->getStyleByColumnAndRow($i, 1)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+            $i++;
+        }
+
+        // Links
+        self::_correctImageSpecialLinks($links);
+        $j = 2;
+        foreach ($links as $l) {
+            $i = 0;
+            foreach ($cols as $id => $label) {
+                if (($id == 'document_id' || $id == 'document_page')) {
+                    if (!is_null($pages)) {
+                        $infos = $pages[$l['page']];
+                        $value = $infos[$id];
+                    } else {
+                        $value = '';
+                    }
+                } else {
+
+                    if (isset($l[$id])) {
+                        if (is_bool($l[$id])) {
+                            $l[$id] = $l[$id] ? '1' : '0';
+                        }
+                        if ($id === 'numerotation') {
+                            if ($l[$id] === 'false') {
+                                $l[$id] = 'physical';
+                            }
+                        }
+                        if ($id === 'to') {
+                            $s->getCellByColumnAndRow($i, $j)->setDataType(PHPExcel_Cell_DataType::TYPE_STRING)->getStyle()->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_TEXT);
+                        }
+                        $value = $l[$id];
+                    } else {
+                        $value = '';
+                    }
+                }
+
+                $s->setCellValueExplicitByColumnAndRow($i, $j, $value);
+                $i++;
+            }
+            $j++;
+        }
+        // Rulers
+        $s = $xls->createSheet();
+        $s->setTitle('Rulers');
+
+        $rcols = array('page', 'type', 'pos');
+        $i = 0;
+        // Labels
+        foreach ($rcols as $id) {
+            $s->setCellValueByColumnAndRow($i, 1, $id);
+            $s->getColumnDimensionByColumn($i)->setAutoSize(true);
+            $i++;
+        }
+
+        // Contents
+        $j = 2;
+        foreach ($rulers as $r) {
+            $i = 0;
+            foreach ($rcols as $id) {
+                if (!is_null($pages) && ($id == 'document_id' || $id == 'document_page')) {
+                    $infos = $pages[$r['page']];
+                    $value = $infos[$id];
+                } else {
+                    $value = $r[$id];
+                }
+                $s->setCellValueByColumnAndRow($i, $j, $value);
+                $s->getStyleByColumnAndRow($i, $j)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
+                $i++;
+            }
+            $j++;
+        }
+
+        $xls->setActiveSheetIndex(0);
+        return $xls;
+    }
+
+
+    public static function getLinksAndRulers($book_id, &$links, &$rulers, $time = 'latest')
+    {
+        if (null === $time) {
+            $time = 'latest';
+        }
+        $dir = self::getLinksDir($book_id);
+
+        $file = $dir . '/' . $time . '.links.gz';
+        if ($time === 'latest' && !file_exists($file)) {
+            $versions = self::getLinksVersions($book_id);
+            foreach ($versions as $version => $m) {
+                copy($dir . '/' . $version . '.links.gz', $dir . '/latest.links.gz');
+                copy($dir . '/' . $version . '.meta.gz', $dir . '/latest.meta.gz');
+                break;
+            }
+        }
+        if (!file_exists($file)) {
+            $links = [];
+            $rulers = [];
+            return;
+        }
+
+        $r = json_decode(gzdecode(file_get_contents($file)), true);
+        $links = $r['links'];
+        $rulers = $r['rulers'];
+
+        self::_correctImageSpecialLinks($links);
+    }
+
+    protected static function _correctImageSpecialLinks(&$links)
+    {
+        foreach ($links as $k => $link) {
+            if (preg_match('/^link_(.*)$/', $link['page'], $matches) && strlen($matches[1]) !== 32) {
+                $uid = $matches[1];
+                foreach ($links as $l) {
+                    if ($l['uid'] === $uid && $l['alternative']) {
+                        $links[$k]['page'] = 'link_' . md5($l['alternative']);
+                        break;
+                    }
+                }
+            } else if (preg_match('/^([0-9a-f]{32})$/', $link['page'], $matches)) {
+                $links[$k]['page'] = 'link_' . $matches[1];
+            }
+        }
+    }
+
+    public static function getLinksFromExcel($xls, &$links, &$rulers)
+    {
+        $s = $xls->setActiveSheetIndexByName('Links');
+        $i = 0;
+        $links = array();
+        foreach ($s->getRowIterator() as $row) {
+            $cellIterator = $row->getCellIterator();
+            $cellIterator->setIterateOnlyExistingCells(false);
+            if ($i == 0) {
+                $cols = array();
+                foreach ($cellIterator as $cell) {
+                    $cols[] = $cell->getValue();
+                }
+            } else {
+                $link = array();
+                $j = 0;
+                foreach ($cellIterator as $cell) {
+                    $link[$cols[$j]] = $cell->getValue();
+                    $j++;
+                }
+                if ($link['display_area'] == '' || !$link['display_area']) {
+                    $link['display_area'] = '0';
+                }
+                if (trim($link['infobulle']) == '') {
+                    $link['infobulle'] = '';
+                }
+                $links[] = $link;
+            }
+
+            $i++;
+        }
+
+        $i = 0;
+        $rulers = array();
+        $s = $xls->setActiveSheetIndexByName('Rulers');
+        foreach ($s->getRowIterator() as $row) {
+            $cellIterator = $row->getCellIterator();
+            $cellIterator->setIterateOnlyExistingCells(false);
+            if ($i == 0) {
+                $cols = array();
+                foreach ($cellIterator as $cell) {
+                    $cols[] = $cell->getValue();
+                }
+            } else {
+                $link = array();
+                $j = 0;
+                foreach ($cellIterator as $cell) {
+                    $ruler[$cols[$j]] = $cell->getValue();
+                    $j++;
+                }
+
+                $rulers[] = $ruler;
+            }
+            $i++;
+        }
+
+        self::_correctImageSpecialLinks($links);
+    }
+
+    public static function getLinksFromAutobookmarkText($txt, &$links, &$rulers)
+    {
+        $links = array();
+        $rulers = array();
+
+        $lines = explode("\n", $txt);
+
+        $protocols = array('mailto' => 3, 'custom' => 7, 'cart' => 12, 'pagelabel' => 26);
+
+        foreach ($lines as $line) {
+            $line = trim($line);
+            if ($line == '') {
+                continue;
+            }
+            if (strpos('#', $line) === 0) {
+                continue;
+            }
+            $target = $numerotation = '';
+            list($page, $left, $top, $width, $height, $type, $to) = explode(';', $line);
+            if ($type <= 2) {
+                $target = '_blank';
+            } elseif ($type == 5) {
+                $numerotation = 'physical';
+            }
+
+            $links[] = array(
+                'page' => $page,
+                'left' => $left, 'top' => $top, 'width' => $width, 'height' => $height, 'rot' => '',
+                'type' => $type, 'to' => $to, 'target' => $target,
+                'infobulle' => '', 'numerotation' => $numerotation, 'display_area' => '1');
+        }
+
+        self::_correctImageSpecialLinks($links);
+    }
+
+    public static function _getLinkKey()
+    {
+        if (self::$_linksKey === null) {
+            self::$_linksKey = base64_decode('o2p2yYGI8yMEHf+Y5/e6NdTINbbXg3NIo8BODgdhPxI=');
+        }
+        return self::$_linksKey;
+    }
+
+    public static function encryptLinks($links)
+    {
+        $res = [];
+        foreach ($links as $key => $link) {
+            $res[$key] = self::encryptLinkAttrs($link);
+        }
+        return $res;
+    }
+
+    /**
+     * @throws SodiumException
+     */
+    public static function encryptLinkAttrs($link)
+    {
+        if (is_array($link)) {
+            $link = ObjectUtil::asObject($link);
+        }
+
+        $crypted = [13, 14, 35];
+
+        if (!in_array($link->type, $crypted)) {
+            return $link;
+        }
+
+        $attrs = ['image_rollover'];
+        foreach ($attrs as $attr) {
+            if (!isset($link->$attr)) {
+                continue;
+            }
+            $link->$attr = trim($link->$attr);
+            if (strpos($link->$attr, '///') === 0 || $link->$attr == '') {
+                continue;
+            }
+            $link->$attr = '///' . Crypt::safeEncrypt($link->uid . '|||' . $link->$attr, self::_getLinkKey());
+        }
+        return $link;
+    }
+
+    /**
+     * @throws SodiumException
+     */
+    public static function decryptLink($link)
+    {
+        $array = false;
+        if (is_array($link)) {
+            $array = true;
+            $link = ObjectUtil::asObject($link);
+        }
+
+        foreach ($link as $attr => $item) {
+            if (strpos($item, '///') !== 0) {
+                continue;
+            }
+            $v = Crypt::safeDecrypt(substr($item, 3), self::_getLinkKey());
+            $e = explode('|||', $v);
+            if ($e[0] === $link->uid) {
+                $link->$attr = $e[1];
+            } else {
+                $link->$attr = '';
+            }
+        }
+        if (!$array) {
+            return $link;
+        }
+        return ArrayUtil::asArray($link);
+    }
+
+    /**
+     * @throws SodiumException
+     */
+    public static function decryptLinks($links)
+    {
+        $res = [];
+        foreach ($links as $key => $link) {
+            $res[$key] = self::decryptLink($link);
+        }
+        return $res;
+    }
+
+    public static function saveLinksInFile($book_id, $user_id, $comments, $links, $rulers = [], $specialLinks = [], $specialRulers = [])
+    {
+        $lr = self::mergeLinksAndRulers($links, $rulers, $specialLinks, $specialRulers);
+        $meta = ['links' => count($lr['links']), 'rulers' => count($lr['rulers']), 'comments' => $comments, 'user' => $user_id];
+        $base = self::getLinksDir($book_id) . '/' . time();
+        $latestLinks = self::getLinksDir($book_id) . '/latest.links.gz';
+        $latestMeta = self::getLinksDir($book_id) . '/latest.meta.gz';
+        file_put_contents($base . '.meta.gz', gzencode(json_encode($meta)));
+        file_put_contents($base . '.links.gz', gzencode(json_encode($lr)));
+        copy($base . '.links.gz', $latestLinks);
+        copy($base . '.meta.gz', $latestMeta);
+    }
+
+
+    public static function getLinksDir($book_id)
+    {
+        return Files::mkdir('/data1/extranet/www/fluidbook/books/links/' . $book_id);
+    }
+
+    public static function getLinksVersions($book_id, $withLinks = false)
+    {
+        $dir = self::getLinksDir($book_id);
+        $dr = opendir($dir);
+        $updates = [];
+        while ($f = readdir($dr)) {
+            if ($f === '.' || $f === '..') {
+                continue;
+            }
+            $e = explode('.', $f, 2);
+            if ($e[1] !== 'meta.gz' || $e[0] === 'latest') {
+                continue;
+            }
+
+            $updates[$e[0]] = self::getMeta($book_id, $e[0]);
+        }
+        krsort($updates);
+
+        return $updates;
+    }
+
+    public static function getMeta($book_id, $update = 'latest')
+    {
+        return json_decode(gzdecode(file_get_contents(self::getLinksDir($book_id) . '/' . $update . '.meta.gz')), true);
+    }
+
+    public static function mergeLinksAndRulers($links, $rulers, $specialLinks, $specialRulers)
+    {
+        $finalLinks = [];
+        $l = array_merge(self::_getAsArray($links), self::_getAsArray($specialLinks));
+        foreach ($l as $k => $item) {
+            $item['id'] = $k + 1;
+            if (!isset($item['to'])) {
+                $item['to'] = '';
+            }
+            $finalLinks[] = $item;
+        }
+
+        self::_correctImageSpecialLinks($finalLinks);
+
+        return ['links' => self::encryptLinks($finalLinks), 'rulers' => array_merge(self::_getAsArray($rulers), self::_getAsArray($specialRulers))];
+    }
+
+    protected static function _getAsArray($v)
+    {
+        if (is_array($v)) {
+            return $v;
+        }
+        return json_decode($v, true);
+    }
+
+    public static function addLinksFromPDF($book_id)
+    {
+        global $core;
+
+        $daoBook = new wsDAOBook($core->con);
+        $pages = $daoBook->getPagesOfBook($book_id);
+
+        $booleans = array('video_loop', 'video_auto_start', 'video_controls', 'video_sound_on');
+        $numbers = ['left', 'top', 'width', 'height'];
+
+        $links = [];
+
+        foreach ($pages as $page => $info) {
+            $csv = wsDocument::getDir($info['document_id']) . '/p' . $info['document_page'] . '.csv';
+            if (!file_exists($csv) && file_exists($csv . '.gz')) {
+                $csv = 'compress.zlib://' . $csv . '.gz';
+            } elseif (!file_exists($csv)) {
+                continue;
+            }
+
+            $newformat = (filemtime($csv) > 1363685416);
+
+            $fp = fopen($csv, 'rb');
+
+            while (true) {
+                $line = fgetcsv($fp, 512, ';', '"');
+                // End of file
+                if (!$line) {
+                    break;
+                }
+                // Commentaire || ligne vide
+                if (substr($line[0], 0, 1) == '#' || is_null($line[0])) {
+                    continue;
+                }
+
+                $link = [];
+                if ($newformat) {
+                    $cols = array('page' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'type' => '', 'to' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical', "inline" => true);
+                } else {
+                    $cols = array('page' => '', 'type' => '', 'to' => '', 'left' => '', 'top' => '', 'width' => '', 'height' => '', 'target' => '_blank', 'video_loop' => true, 'video_auto_start' => true, 'video_controls' => true, 'video_sound_on' => true, 'infobulle' => '', 'numerotation' => 'physical');
+                }
+
+
+                $k = 0;
+                foreach ($cols as $col => $default) {
+                    if (isset($line[$k])) {
+                        if (in_array($k, $numbers)) {
+                            $link[$col] = (float)str_replace(',', '.', $line[$k]);
+                        } else if (in_array($k, $booleans)) {
+                            $link[$col] = ($line[$k] == '1');
+                        } else {
+                            $link[$col] = utf8_encode($line[$k]);
+                        }
+                    } else {
+                        $link[$col] = $default;
+                    }
+                    $k++;
+                }
+
+                if ($link['type'] == 18) {
+                    $link['infobulle'] = $link['to'];
+                    $link['to'] = '';
+                }
+
+                $link['display_area'] = '1';
+                $link['page'] = $page;
+                $links[] = $link;
+            }
+
+        }
+
+        self::saveLinksInFile($book_id, $core->user->utilisateur_id, 'Links imported from PDF', $links, []);
+    }
+}
index 0c8b1c75d1838ecebeb97a034058347dccd8d112..02e8da4630b39c0f6800f059162e228ceeab015d 100644 (file)
@@ -26,6 +26,8 @@
         "ext-simplexml": "*",
         "ext-tidy": "*",
         "ext-zip": "*",
+        "ext-zlib": "*",
+        "ext-sodium": "*",
         "ahmadshah/lucy": "dev-master",
         "cubedesigners/userdatabase": "dev-master",
         "cubist/azuretts": "dev-master",
diff --git a/resources/fluidbookpublication/cover/shade-cover-app.png b/resources/fluidbookpublication/cover/shade-cover-app.png
new file mode 100644 (file)
index 0000000..f96319b
Binary files /dev/null and b/resources/fluidbookpublication/cover/shade-cover-app.png differ