From: Vincent Vanwaelscappel Date: Fri, 5 May 2023 08:01:37 +0000 (+0200) Subject: fix #5408 @2 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=d4e812cb3d2416b2bd4303e5d616fb8b72be1801;p=fluidbook-toolbox.git fix #5408 @2 --- diff --git a/app/Console/Commands/FluidbookCompile.php b/app/Console/Commands/FluidbookCompile.php index 6339d4914..a52dc5b7f 100644 --- a/app/Console/Commands/FluidbookCompile.php +++ b/app/Console/Commands/FluidbookCompile.php @@ -2,7 +2,7 @@ namespace App\Console\Commands; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use App\Models\FluidbookPublication; use Cubist\Backpack\Console\Commands\CubistCommand; use Cubist\Util\PHP; diff --git a/app/Console/Commands/FluidbookLinksFromPDF.php b/app/Console/Commands/FluidbookLinksFromPDF.php index 3a5eae929..61767997a 100644 --- a/app/Console/Commands/FluidbookLinksFromPDF.php +++ b/app/Console/Commands/FluidbookLinksFromPDF.php @@ -2,10 +2,8 @@ namespace App\Console\Commands; -use App\Fluidbook\Links; -use App\Models\Traits\FluidbookPlayerBranches; +use App\Fluidbook\Link\LinksData; use Cubist\Backpack\Console\Commands\CubistCommand; -use Cubist\Util\PHP; class FluidbookLinksFromPDF extends CubistCommand { @@ -14,7 +12,7 @@ class FluidbookLinksFromPDF extends CubistCommand public function handle() { - Links::addLinksFromPDF($this->argument('id')); + LinksData::addLinksFromPDF($this->argument('id')); } } diff --git a/app/Fluidbook/Compiler.php b/app/Fluidbook/Compiler.php deleted file mode 100644 index 5461ab701..000000000 --- a/app/Fluidbook/Compiler.php +++ /dev/null @@ -1,4101 +0,0 @@ - - ['js/libs/cube/util.js', - 'js/libs/cube/fb.js',], - 'modernizr' => - ['js/libs/modernizr/modernizr.min.js', - 'js/libs/modernizr/tests.js',], - 'modifier' => ['js/libs/threejs/modifier.min.js'], - 'threejs' => - ['js/libs/threejs/legacy/three.min.js', - 'js/libs/threejs/legacy/Projector.js', - 'js/libs/threejs/legacy/CanvasRenderer.js', - ], -// 'threejs-latest' => -// ['js/libs/threejs/latest/three.min.js', -// ], - 'jquery' => - [ - 'js/libs/jquery/jquery.min.js', - ], - 'jquery-extras' => ['js/libs/jquery/jquery.transform.js', - 'js/libs/jquery/jquery.form.min.js', - 'js/libs/jquery/jquery.mousewheel.min.js', - 'js/libs/jquery/jquery.hashchange.min.js', - 'js/libs/jquery/jquery.scrollto.min.js', - ], - 'aria' => ['js/libs/aria/radio.js',], - 'bluebird' => ['js/libs/bluebird.min.js'], - 'screenfull' => ['js/libs/screenfull.min.js'], - 'storage' => ['js/libs/storage.js',], - 'hotkeys' => ['js/libs/hotkeys.min.js',], - 'forge' => ['js/libs/forge/forge-sha256.min.js',], - 'perfectscrollbar' => ['js/libs/perfect-scrollbar/perfect-scrollbar.js', - 'js/libs/perfect-scrollbar/perfect-scrollbar.jquery.js'], - 'confirm' => ['js/libs/jquery/jquery.confirm.min.js'], - 'mmenu' => - ['js/libs/mmenu/jquery.mmenu.all.js'], - 'gsap' => - ['js/libs/gsap/gsap.min.js', - 'js/libs/gsap/ScrollToPlugin.min.js', - 'js/libs/gsap/InertiaPlugin.min.js', - 'js/libs/gsap/Draggable.min.js', - ], - 'hammer' => ['js/libs/hammer.min.js',], - 'interactjs' => ['js/libs/interact.min.js'], - 'gal' => - ['js/libs/gal/gal.js', - 'js/libs/gal/gal.filesystem.js',], - 'raphael' => - ['js/libs/raphael/raphael.min.js', - 'js/libs/gsap/plugins/RaphaelPlugin.min.js'], - 'countup' => - ['js/libs/countup/countup.min.js'], - 'clipboard' => ['js/libs/clipboard.min.js'], - 'fluidbook' => - ['js/libs/fluidbook/fluidbook.utils.js', - 'js/libs/fluidbook/fluidbook.networkcontrol.js', - 'js/libs/fluidbook/fluidbook.splash.js', - 'js/libs/fluidbook/fluidbook.links.js', - 'js/libs/fluidbook/fluidbook.support.js', - 'js/libs/fluidbook/fluidbook.video.js', - 'js/libs/fluidbook/fluidbook.viewport.js', - 'js/libs/fluidbook/fluidbook.desktop.js', - 'js/libs/fluidbook/fluidbook.service.js', - 'js/libs/fluidbook/fluidbook.share.js', - 'js/libs/fluidbook/fluidbook.l10n.js', - 'js/libs/fluidbook/fluidbook.slider.js', - 'js/libs/fluidbook/fluidbook.pagetransitions.js', - 'js/libs/fluidbook/fluidbook.nav.js', - 'js/libs/fluidbook/fluidbook.interface.js', - 'js/libs/fluidbook/fluidbook.input.js', - 'js/libs/fluidbook/fluidbook.touch.js', - 'js/libs/fluidbook/fluidbook.loader.js', - 'js/libs/fluidbook/fluidbook.search.js', - 'js/libs/fluidbook/fluidbook.help.js', - 'js/libs/fluidbook/fluidbook.resize.js', - 'js/libs/fluidbook/fluidbook.stats.js', - 'js/libs/fluidbook/fluidbook.cache.js', - 'js/libs/fluidbook/fluidbook.tooltip.js', - 'js/libs/fluidbook/fluidbook.bookmarks.js', - 'js/libs/fluidbook/fluidbook.background.js', - 'js/libs/fluidbook/fluidbook.pad.js', - 'js/libs/fluidbook/fluidbook.audiodescription.js', - 'js/libs/fluidbook/fluidbook.audioplayer.js', - 'js/libs/fluidbook/fluidbook.accessibility.js', - 'js/libs/fluidbook/fluidbook.privacy.js', - 'js/libs/fluidbook/fluidbook.zoom.js', - 'js/libs/fluidbook/fluidbook.menu.js', - 'js/libs/fluidbook/fluidbook.sound.js', - 'js/libs/fluidbook/fluidbook.contentlock.js', - 'js/libs/fluidbook/fluidbook.scorm.js', - 'js/libs/fluidbook/fluidbook.3dflip.js', - 'js/libs/fluidbook/menu/fluidbook.chapters.js', - 'js/libs/fluidbook/menu/fluidbook.index.js', - 'js/libs/fluidbook/fluidbook.landingpage.js', - 'js/libs/fluidbook/fluidbook.print.js', - 'js/libs/fluidbook/fluidbook.secure.js', - 'js/libs/fluidbook/fluidbook.tabs.js', - 'js/libs/fluidbook/fluidbook.articles.js', - 'js/libs/fluidbook/fluidbook.widget.js', - 'js/libs/fluidbook/fluidbook.keyboard.js', - 'js/libs/fluidbook/fluidbook.posad.js', - 'js/libs/fluidbook/fluidbook.notes.js', - 'js/libs/fluidbook/fluidbook.gamify.js', - 'js/libs/fluidbook/fluidbook.js', - 'js/main.js'], - 'mobilefirst' => [ - 'js/libs/fluidbook/fluidbook.mobilefirst.js', - 'js/libs/fluidbook/mobilefirst/fluidbook.mobilefirst.slider.js', - ], - ]; - - protected $specialJsFiles = array(); - - - public $jsFiles = []; - - // Collection of LESS files to be compiled - // Filename with no extension, relative to the /style directory in the player build folder - public $lessFiles = ['fluidbook']; - - public $specialCSS = array(); - public $phonegapStandardPlugins = array('ios' => array('ExternalFileUtil'), - 'android' => array('webintent')); - public $pluginCSS = array(); - public $pluginJs = array(); - public $htmlmultimedia = array(); - public $cssX = array(); - public $cssY = array(); - public $cssWidths = array(); - public $pdf2htmlRatio; - public $scale; - public $multiply; - public $div = array(); - public $numerotation; - public $fontDocs = array(); - public $dir; - public $z = 3; - protected $_lottieIDByHash = []; - - public $pages; - public $theme; - public $devversion; - public $book_id; - public $themeRoot; - public $needToRecompileContents = true; - public $needToRecompileSettings = true; - public $width; - public $height; - public $cssWidth; - public $cssHeight; - public $cssOneWidth; - public $cssOneHeight; - public $cssScale; - public $linkScale; - public $optimalWidth = 567; - public $optimalHeight = 709; - public $additionalConfig = array(); - public $fontScale = 1; - public $cache = array(); - public $backgroundsPrefix = array(); - public $svg = true; - public $assets = ''; - public $phonegap = false; - public $phonegapVersion; - public $standalone = false; - public $hiddenContents = array(); - public $appcache; - public $home; - public $widget = true; - public $multiApp = false; - public $pageLabels = array(); - public $stylesheets = array(); - public $logfp = null; - public $logtime = null; - public $beginBody = array(); - public $seoArticles = []; - public $securityPolicyWhitelist = ['*.google-analytics.com', '*.youtube.com', '*.ytimg.com', '*.googletagmanager.com']; - public $writeLinksData = false; - public $content_lock = []; - public $cssfont = []; - public $lessVariables = ["import-cart-styles" => 'none']; - protected $_indexVars = null; - public $accessibleTexts = []; - protected $_svgSymbols = []; - protected $_addedPDFJS = false; - protected $audioDescriptionTextsList = []; - protected $hybrid = false; - - protected $_docDimensions = []; - - public $_signature; - public $seo = null; - - /** - * @var \Cubist\Backpack\Magic\EntityData - */ - public $fluidbookSettings; - - /** - * @var \Cubist\Backpack\Magic\EntityData - */ - public $themeSettings; - - /** - * @var Command - */ - protected $_command = null; - - /** - * @param FluidbookPublication $book - * @param bool $scormVariant - * @param $phonegap - * @param $phonegapVersion - * @param $dir - * @param $standalone - * @param $appcache - * @param $home - * @param $theme FluidbookTheme|null - * @param $hybrid - * @param Command|null $command - * @throws \Exception - */ - - function __construct(FluidbookPublication $book, $scormVariant = false, $phonegap = false, $phonegapVersion = 'latest', $dir = null, $standalone = false, $appcache = false, $home = false, FluidbookTheme $theme = null, $hybrid = false, Command $command = null) - { - ExcelToArray::setCache(protected_path('fluidbookpublication/cache/exceltoarray')); - - parent::__construct(); - - $this->setFluidbook($book); - $this->setCommand($command); - - $this->phonegapVersion = self::getPhonegapVersion($phonegapVersion); - $this->appcache = $appcache; - $this->multiApp = $this->home = $home; - $this->devversion = $this->getFluidbook()->mobileLVersion; - $this->scormVariant = $scormVariant; - - $this->hybrid = $hybrid; - - $this->assets = self::getSourcesPath($this->devversion); - $this->compiledAssets = self::getCompiledSourcesPath($this->devversion); - - $this->phonegap = $phonegap; - $this->standalone = $standalone || $this->phonegap; - $this->appcache = $appcache; - $this->widget = !$this->phonegap; - - $this->fluidbookSettings = $this->getFluidbook()->getSettings(); - - PHP::memoryAllocate('12G'); - - $this->book_id = $this->getFluidbook()->id; - $this->log('Start compilation'); - - $this->dir = $this->getFluidbook()->getFinalPath($theme, $scormVariant); - $this->vdir = new VirtualDirectory($this->dir); - - $this->wdir = $this->getFluidbook()->getAssetDir(); - - $this->widget = false; - - $this->pages = $this->getFluidbook()->composition; - $this->maxRes = min(self::MAX_RES, $this->fluidbookSettings->maxResolution); - - $this->theme = $theme ?? $this->getFluidbook()->getTheme(); - - $this->themeSettings = $this->theme->getPageData(); - $this->log('Got data from database'); - - $this->width = round($this->getFluidbook()->getPageWidth(), 8); - $this->height = round($this->getFluidbook()->getPageHeight(), 8); - - $this->imageFormat = $this->fluidbookSettings->imageFormat; - - $p1 = $this->getFluidbook()->getFile(1, $this->imageFormat, 150); - $imagesize = Image::getimagesize($p1); - $this->pdf2htmlRatio = round(($imagesize[0] * 0.48) / $this->width, 12); - - $this->linkScale = $this->cssScale = $this->z * min($this->optimalWidth / $this->width, $this->optimalHeight / $this->height); - - $this->cssOneScale = $this->z * min(($this->optimalWidth * 2) / $this->width, $this->optimalHeight / $this->height); - - $this->cssWidth = $this->width * $this->cssScale; - $this->cssHeight = $this->height * $this->cssScale; - - $this->cssOneWidth = $this->width * $this->cssOneScale; - $this->cssOneHeight = $this->height * $this->cssOneScale; - - $this->scale = 1; - - if ($this->isMobileFirst()) { - $this->cssScale = $this->cssOneScale = 480 / $this->width; - $this->linkScale = $this->cssScale; - $this->cssOneWidth = $this->cssWidth = $this->width * $this->cssScale; - $this->cssOneHeight = $this->cssHeight = $this->height * $this->cssScale; - $this->initMobileFirst(); - } - - $this->svgfiles = array_unique([$this->assets . '/images/symbols/interface.svg', - storage_path('icons/15.svg')]); - if ($this->themeSettings->iconSet > 15) { - $this->svgfiles[] = storage_path('icons/' . $this->themeSettings->iconSet . '.svg'); - } - if ($symbols = $this->themeAsset('symbols')) { - $this->svgfiles[] = $symbols->getPathname(); - } - - if ($this->isMobileFirst()) { - $this->multiply = $this->pdf2htmlRatio * $this->scale * $this->cssOneScale; - } else { - $this->multiply = $this->pdf2htmlRatio * $this->scale * $this->cssScale; - } - - $this->initConfig(); - $this->log('Defined dimensions'); - } - - public function getFinalPath() - { - return $this->dir; - } - - - public function getSetting($key, $default = null) - { - if ($this->fluidbookSettings->has($key)) { - return $this->fluidbookSettings->get($key, $default); - } - if ($this->themeSettings->has($key)) { - return $this->themeSettings->get($key, $default); - } - return $default; - } - - - public function setSetting($key, $value) - { - if ($this->themeSettings->has($key)) { - $this->themeSettings->set($key, $value); - return; - } - $this->fluidbookSettings->set($key, $value); - } - - - /** - * @param $key - * @param $default - * @return null|SplFileInfo - */ - public function themeAsset($key) - { - $collection = $this->theme->{$key}; - - if ($collection) { - $path = $this->theme->getFirstMediaPath($collection); - if (!$path || !file_exists($path)) { - $res = false; - } else { - $res = new SplFileInfo($path); - } - } else { - $res = false; - } - if (null !== $this->config) { - if ($res instanceof SplFileInfo) { - $this->config->set($key, $res->getFilename()); - } else { - $this->config->set($key, ''); - } - } - return $res; - } - - /** - * @return FluidbookPublication - */ - public function getFluidbook(): FluidbookPublication - { - return $this->_fluidbook; - } - - /** - * @param FluidbookPublication $fluidbook - */ - public function setFluidbook(FluidbookPublication $fluidbook): void - { - $this->_fluidbook = $fluidbook; - } - - /** - * @return Command|null - */ - public function getCommand(): ?Command - { - return $this->_command; - } - - /** - * @param Command|null $command - */ - public function setCommand(?Command $command): void - { - $this->_command = $command; - } - - public function isMobileFirst() - { - return $this->fluidbookSettings->mobileNavigationType === 'mobilefirst'; - } - - public function initMobileFirst() - { - $this->themeSettings->usePageEdges = false; - } - - public function initConfig() - { - if (!$this->scormVariant) { - $this->fluidbookSettings->scorm_enable = false; - } - - $this->config = new Data(array_merge($this->fluidbookSettings->getRawData()['settings'], $this->themeSettings->getRawData())); - $this->config->pages = count($this->getFluidbook()->composition); - $this->config->bookmarkDisablePages = ArrayUtil::parseRange($this->config->bookmarkDisablePages); - $this->config->rasterizePages = ArrayUtil::parseRange($this->config->rasterizePages); - $this->config->vectorPages = array_diff(ArrayUtil::parseRange($this->config->vectorPages), $this->config->rasterizePages); - $this->numerotation = $this->config->numerotation = explode(',', $this->getFluidbook()->page_numbers); - - $hideOnPages = ArrayUtil::parseRange($this->config->tabsHideOnPages); - $this->config->tabsDisabledOnPages = ArrayUtil::parseRange($this->config->tabsDisabledOnPages); - - if ($this->config->tabsHideOnCover) { - $hideOnPages[] = 0; - $hideOnPages[] = 1; - } - if ($this->config->tabsHideOnLastPage) { - $hideOnPages[] = count($this->pages); - } - $this->config->tabsHideOnPages = $hideOnPages; - $this->config->triggersLinks = []; - $this->config->hasContentLock = false; - } - - public function populateConfig() - { - $this->config->id = $this->getFluidbook()->book_id; - $this->config->cid = $this->getFluidbook()->cid; - $this->config->cacheDate = time(); - $this->config->width = round($this->cssWidth, 2); - $this->config->height = round($this->cssHeight, 2); - $this->config->optimalWidth = round($this->optimalWidth, 2); - $this->config->optimalHeight = round($this->optimalHeight, 2); - $this->config->chapters = $this->getFluidbook()->chapters; - $this->config->videoFormats = $this->getVideosFormats(false); - $this->config->htmlmultimedia = $this->htmlmultimedia; - $this->config->phonegap = $this->phonegap; - $this->config->retinaResolution = min($this->fluidbookSettings->maxResolution, $this->maxRes); - $this->config->standardResolution = min($this->fluidbookSettings->maxResolution, 150); - $this->config->pageLabels = $this->pageLabels; - $this->config->pageZoomFactor = $this->z; - $this->config->multiply = round($this->multiply, 6); - $this->config->cssScale = round($this->cssScale, 6); - $this->config->pdfZoomFactor = round($this->pdf2htmlRatio, 6); - if ($this->home) { - $this->config->home = 'http://home'; - } - $this->config->multiApp = $this->multiApp; - foreach ($this->additionalConfig as $k => $v) { - $this->config->$k = $v; - } - if ($this->phonegap && ($this->fluidbookSettings->offlineLink == '' || $this->fluidbookSettings->offlineLink == 'http://')) { - $this->config->share = false; - } - if ($this->config->maxPages > 0) { - $this->addContentLock($this->config->maxPages); - } - - // We need to be able to reference both navOrder and navOrderH so convert both to arrays - // We also make sure there are no empty items in the arrays (see: http://php.net/manual/en/function.array-filter.php#111091) - $this->config->navOrder = array_filter(array_map('trim', explode(',', $this->config->navOrder)), 'strlen'); - $this->config->navOrderH = array_filter(array_map('trim', explode(',', $this->config->navOrderH)), 'strlen'); - - $this->config->standalone = $this->standalone; - if ($this->config->phonegap) { - $this->config->manifest = $this->writeManifest(); - } - - if ($this->config->form == 'bulle') { - $this->addJsLib('bulle', 'js/libs/fluidbook/forms/fluidbook.form.bulle.js'); - } else if ($this->config->form == 'bourbon') { - $this->addJsLib('parsley', 'js/libs/parsley.min.js'); - $this->addJsLib('bourbon', 'js/libs/fluidbook/forms/fluidbook.form.bourbon.js'); - } else if ($this->config->form == 'avery') { - $this->addJsLib('parsley', 'js/libs/parsley.min.js'); - $this->addJsLib('avery', 'js/libs/fluidbook/forms/fluidbook.form.avery.js'); - $this->addLess('form/avery'); - $this->writeCountries(); - } - $this->config->seoArticles = $this->seoArticles; - } - - public function writeGrandVisionCart() - { - $this->lessVariables['import-cart-styles'] = 'grandvision'; - - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('grandvision', 'js/libs/fluidbook/cart/fluidbook.cart.grandvision.js'); - $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); - $this->addJsLib('multiselect', 'js/libs/jquery/jquery.multi-select.js'); - $this->addJsLib('jqueryui', 'js/libs/jquery/jquery-ui.min.js'); - $this->addJsLib('exceljs', 'js/libs/exceljs.min.js'); - $this->svgfiles[] = $this->assets . '/images/symbols/grandvision.svg'; - - $cdir = $this->wdir . '/commerce/'; - $file = $cdir . $this->fluidbookSettings->basketReferences; - $refs = ExcelToArray::excelToArrayKeyVars($file, 'Excel2007', true); - $this->config->basketReferences = []; - foreach ($refs as $ean => $ref) { - $this->config->basketReferences[$ean] = $ref; - $this->config->basketReferences[$ean]['angle_url'] = base64_encode(file_get_contents($this->wdir . '/commerce/opt/' . $ean . '-angle.jpg')); - } - - $odir = $cdir . '/opt/'; - if (!file_exists($odir)) { - mkdir($odir, 0777, true); - } - - $it = Files::getDirectoryIterator($cdir); - $exts = ['png', 'jpg', 'tif', 'mp4']; - foreach ($it as $file) { - - /** @var $file SplFileInfo */ - if ($file->isDir()) { - continue; - } - $ext = $file->getExtension(); - if (!in_array($ext, $exts)) { - continue; - } - - $e = Text::multiExplode('_-.', mb_strtolower($file->getFilename())); - $ean = $this->findEAN($e); - if (!$ean) { - continue; - } - if (!isset($this->config->basketReferences[$ean])) { - continue; - } - $f = $file->getPathname(); - - if ($ext === 'mp4') { - $n = $ean . '-360.mp4'; - $this->config->basketReferences[$ean]['360'] = true; - $opt = $odir . '/' . $n; - if (!file_exists($opt) || !filesize($opt) || filemtime($opt) < filemtime($f)) { - // Optimize original video - `ffmpeg -i $f -filter:v scale=360:-2 -vcodec libx264 -an $opt`; - touch($opt, filemtime($f)); - } - } else { - if (in_array('front', $e)) { - $type = 'front'; - } else if (in_array('angle', $e)) { - $type = 'angle'; - } else { - continue; - } - - $n = $ean . '-' . $type . '.jpg'; - $this->config->basketReferences[$ean][$type] = true; - $opt = $odir . '/' . $n; - if (!file_exists($opt) || !filesize($opt) || filemtime($opt) < filemtime($f)) { - // Optimize original image - $convert = new Resizer(); - $convert->loadImage($f); - $convert->resize(1080, null, 'ratio', false, 'C', 'M', 'white'); - $convert->output('jpg', $opt, 75); - touch($opt, filemtime($f)); - } - } - $this->vdir->copy($opt, 'data/commerce/' . $n); - } - } - - public function findEAN($array) - { - foreach ($array as $item) { - if (strlen($item) === 13 && preg_match('/^\d{13}$/', $item)) { - return $item; - } - } - return false; - } - - public function writeFlexipanCart() - { - $this->lessVariables['import-cart-styles'] = 'flexipan'; - - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('flexipan', 'js/libs/fluidbook/cart/fluidbook.cart.flexipan.js'); - $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); - - $cdir = $this->wdir . '/commerce/'; - - - $file = $cdir . $this->fluidbookSettings->basketReferences; - $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); - - $this->getLinksAndRulers($links, $rulers); - - foreach ($links as $link) { - if ($link['type'] == '12') { - - } - } - - $this->config->product_zoom_references = []; - foreach ($this->config->basketReferences as $ref => $data) { - $this->config->product_zoom_references[$ref] = [$ref]; - } - } - - public function getLinksAndRulers(&$links, &$rulers) - { - Links::getLinksAndRulers($this->book_id, $links, $rulers, 'latest', true); - } - - public function writeMIFCart() - { - $this->lessVariables['import-cart-styles'] = 'mif'; - - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('mif', 'js/libs/fluidbook/cart/fluidbook.cart.mif.js'); - $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); - - $cdir = $this->wdir . '/commerce/'; - $odir = $cdir . '/opt/'; - if (!file_exists($odir)) { - mkdir($odir, 0777, true); - } - - $file = $cdir . $this->fluidbookSettings->basketReferences; - $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); - - $this->getLinksAndRulers($links, $rulers); - - foreach ($this->config->basketReferences as $ref => $data) { - $source = $cdir . '/' . $data['Image']; - if (!file_exists($source)) { - continue; - } - $d = Text::str2URL($ref) . '.jpg'; - $dest = $odir . '/' . $d; - if (!file_exists($dest) || !filesize($dest) || filemtime($dest) < filemtime($source)) { - $convert = new Resizer(); - $convert->loadImage($source); - $convert->resize(500, 500, 'ratio', false, 'C', 'M', 'ffffff'); - $convert->output('jpg', $dest, 80); - } - $vdest = 'data/commerce/opt/' . $d; - $this->vdir->copy($dest, $vdest); - $this->config->basketReferences[$ref]['Image'] = $vdest; - } - - foreach ($links as $link) { - if ($link['type'] == '12') { - - } - } - -// $this->config->product_zoom_references = []; -// foreach ($this->config->basketReferences as $ref => $data) { -// $r = [$data['Lien']]; -// $this->config->product_zoom_references[$ref] = $r; -// } - } - - public function writeJoueClub2021Cart() - { - $this->lessVariables['import-cart-styles'] = 'joueclub2021'; - $extra = Link::parseExtras($this->fluidbookSettings->cartExtraSettings, true); - - /** - * buttonColor=#d7b646 - * buttonTextColor=#ffffff - * headerBackgroundColor=#0e1a3c - * headerTextColor=#ffffff - */ - $this->lessVariables['cart-button-color'] = $extra['buttoncolor'] ?? '#e30613'; - $this->lessVariables['cart-button-text-color'] = $extra['buttontextcolor'] ?? '#ffffff'; - $this->lessVariables['cart-button-radius'] = $extra['buttonradius'] ?? '50%'; - $this->lessVariables['cart-header-background-color'] = $extra['headerbackgroundcolor'] ?? '#26348b'; - $this->lessVariables['cart-header-text-color'] = $extra['headertextcolor'] ?? '#ffffff'; - $this->lessVariables['cart-close-color'] = $extra['closecolor'] ?? '#ffffff'; - $this->lessVariables['cart-close-background-color'] = $extra['closebackgroundcolor'] ?? '#e30613'; - $this->lessVariables['cart-close-radius'] = $extra['closeradius'] ?? '50%'; - $this->lessVariables['cart-actions-radius'] = $extra['actionsradius'] ?? '8px'; - $this->lessVariables['cart-actions-background-color'] = $extra['actionsbackgroundcolor'] ?? '#26348b'; - $this->lessVariables['cart-actions-text-color'] = $extra['actionstextcolor'] ?? '#ffffff'; - $this->lessVariables['cart-scrollbar-color'] = $extra['scrollbarcolor'] ?? '#26348b'; - - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('joueclub2021', 'js/libs/fluidbook/cart/fluidbook.cart.joueclub2021.js'); - $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); - - $cdir = $this->wdir . '/commerce/'; - - $file = $cdir . $this->fluidbookSettings->basketReferences; - $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); - - foreach ($this->config->basketReferences as $ref => $data) { - $dest = $cdir . $ref . '.jpg'; - if (!file_exists($dest)) { - copy($data['img'], $dest); - } - $this->vdir->copy($dest, 'data/commerce/' . $ref . '.jpg'); - } - $addFiles = [$this->config->cartHeaderImage, $this->config->cartHeaderMobileImage]; - foreach ($addFiles as $f) { - if (!$f) { - return; - } - - $this->vdir->copy($cdir . $f, 'data/commerce/' . $f); - } - - $this->getLinksAndRulers($links, $rulers); - } - - public function writeGrandPavoisCart() - { - $this->lessVariables['import-cart-styles'] = 'grandpavois'; - - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('grandpavois', 'js/libs/fluidbook/cart/fluidbook.cart.grandpavois.js'); - $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); - - $cdir = $this->wdir . '/commerce/'; - $odir = $cdir . '/opt/'; - if (!file_exists($odir)) { - mkdir($odir, 0777, true); - } - - $file = $cdir . $this->fluidbookSettings->basketReferences; - $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); - - $this->getLinksAndRulers($links, $rulers); - } - - - public function writePumaCart() - { - $this->lessVariables['import-cart-styles'] = 'puma'; - - $this->addJsLib('parsley', 'js/libs/parsley.min.js'); - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('puma', 'js/libs/fluidbook/cart/fluidbook.cart.puma.js'); - $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); - $this->addJsLib('exceljs', 'js/libs/exceljs.min.js'); - $this->addVideoJs(); - - $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($this->wdir . 'commerce/' . $this->fluidbookSettings->basketReferences); - $eanFile = $this->wdir . 'commerce/ean.xlsx'; - if (file_exists($eanFile)) { - $this->config->eanReferences = ExcelToArray::excelToArrayIndexKeyVars($eanFile); - } - - $this->getLinksAndRulers($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'; - $this->config->basketReferences[$link['to']]['zoom_url'] = base64_encode(file_get_contents($this->dir . '/data/links/zoom_' . $link['uid'] . '.jpg')); - $this->config->basketReferences[$link['to']]['zoom_image_ratio'] = $link['width'] / $link['height']; - } - } - - $this->config->product_zoom_references = []; - $files = ['360°', 'Image supplémentaire', 'Fiche technique']; - foreach ($this->config->basketReferences as $ref => $data) { - $r = []; - foreach ($files as $file) { - if (!isset($data[$file])) { - $data[$file] = ''; - } - $fname = trim($data[$file]); - if ($fname !== '') { - $fname = str_replace(' ', '-', $fname); - $wfile = $this->wdir . 'commerce/' . $fname; - if (file_exists($wfile)) { - $fname = 'data/commerce/' . $fname; - $this->vdir->copy($wfile, $fname); - } else { - $fname = ''; - } - } - $r[] = $fname; - } - $this->config->product_zoom_references[$ref] = $r; - } - } - - - public function writeThirietCart() - { - $this->config->cartLinkAppearance = 'overlay'; - $this->svgfiles[] = $this->assets . '/images/symbols/cart-overlay.svg'; - $this->addJsLib('thiriet', 'js/libs/fluidbook/cart/fluidbook.cart.thiriet.js'); - } - - public function writeCFOCCart() - { - - $this->lessVariables['import-cart-styles'] = 'cfoc'; - - $this->addJsLib('cfoc', 'js/libs/fluidbook/cart/fluidbook.cart.cfoc.js'); - - if (!empty($this->config->basketReferences) && is_string($this->config->basketReferences)) { - if (file_exists($this->config->basketReferences) || Url::isDistant($this->config->basketReferences)) { - $referencesFile = $this->config->basketReferences; - } else { - $referencesFile = $this->wdir . 'commerce/' . $this->config->basketReferences; - } - } - - $references = []; - - if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { - $rows = ExcelToArray::excelToArrayFirstSheet($referencesFile); - - - // Expected headings are: EXCLU, LIGNE, EAN, REF, DESIGNATION, COULEUR, QTE MINI, PRIX TTC - $column_headings = array_shift($rows); // We assume the first row will be the headings, so we slice it off - $column_headings = array_map(function ($heading) { // Clean the headings a bit - return trim(strtoupper($heading)); - }, $column_headings); - - foreach ($rows as $row) { - - // First, trim values in case there are any stray spaces - $row = array_map('trim', $row); - - // Next, set the headings as keys to make it easier to refer to the row values by name - $row = array_combine($column_headings, $row); - - // For the 'EXCLU' field, this should be converted to a boolean - $row['EXCLU'] = ('exclu boutique' === $row['EXCLU']); - - // Make sure the PRIX TTC field doesn't have any stray commas or spaces in the numbers - // because this will cause unexpected problems for the calculations - $row['PRIX TTC'] = str_replace([',', ' '], '', $row['PRIX TTC']); - - // The EAN and REF are required, so if they don't exist, we can assume it's not a valid row - if (empty($row['EAN']) || empty($row['REF'])) { - continue; - } - - $references[$row['REF']][$row['EAN']] = $row; - } - - } - - $this->config->basketReferences = $references; - - // It's possible to use the cartExtraSettings field in the parameters to define publication specific settings, - // such as the subject line used in the e-mail that is sent from the cart validation - $extra = Link::parseExtras($this->fluidbookSettings->cartExtraSettings, true); - - $this->config->cartEmailSubject = $extra['email_subject'] ?? 'Récapitulatif de votre commande CFOC'; - } - - /** - * @throws \Exception - */ - public function writeBastideCart() - { - - $this->lessVariables['import-cart-styles'] = 'bastide'; - - $this->addJsLib('bastide', 'js/libs/fluidbook/cart/fluidbook.cart.bastide.js'); - - - if (!empty($this->config->basketReferences)) { - if (file_exists($this->config->basketReferences) || Url::isDistant($this->config->basketReferences)) { - $referencesFile = $this->config->basketReferences; - } else { - $referencesFile = $this->wdir . 'commerce/' . $this->config->basketReferences; - } - } - - $references = []; - - if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { - $rows = ExcelToArray::excelToArrayFirstSheet($referencesFile); - - // Expected headings are: n° page, Chapitre, Article Code, Article, Conditionnement - $column_headings = array_shift($rows); // We assume the first row will be the headings, so we slice it off - $column_headings = array_map(function ($heading) { // Normalise the headings, removing extra spaces and line breaks - return trim(strtoupper(preg_replace('/\s+/', ' ', $heading))); - }, $column_headings); - - foreach ($rows as $row) { - - // First, trim values in case there are any stray spaces - $row = array_map('trim', $row); - - // Next, set the headings as keys to make it easier to refer to the row values by name - $row = array_combine($column_headings, $row); - - // The ARTICLE CODE is required, so if it doesn't exist, we can assume it's not a valid row - if (empty($row['ARTICLE CODE'])) { - continue; - } - - $references[$row['ARTICLE CODE']] = $row; - } - - } - - $this->config->basketReferences = $references; - - // Allow individual Fluidbooks to override the columns shown in the cart - $extra = Link::parseExtras($this->config->cartExtraSettings, true); - - if (!empty($extra['cart_columns'])) { - // In the "Paramètres panier" field (cartExtraSettings), the cart columns can be defined in this format: - // cart_columns=XLS COL NAME|Display name,XLS COL 2|Display name 2 - // This setting needs to be trimmed and converted into an associative array with column_name => display_name - // Split by commas, then by pipes | - $columns = array_map(function ($heading) { - return explode('|', $heading); - }, explode(',', $extra['cart_columns'])); - $processed_columns = []; - foreach ($columns as $column) { - $processed_columns[strtoupper(trim($column[0]))] = trim($column[1] ?? ''); - } - - // Ensure that special QUANTITY and DELETE columns are present (see getColumns() in fluidbook.cart.bastide.js) - $processed_columns['QUANTITY'] = $processed_columns['QUANTITY'] ?? 'Quantité'; - $processed_columns['DELETE'] = ''; - - $this->config->cartColumns = $processed_columns; - } - } - - public function writeCartConfig() - { - if ($this->fluidbookSettings->cartLinkAppearance == 'overlay') { - $this->svgfiles[] = $this->assets . '/images/symbols/cart-overlay.svg'; - } - - if ($this->config->basket) { - $this->addJsLib('cart', 'js/libs/fluidbook/fluidbook.cart.js'); - switch ($this->config->basketManager) { - case 'Thiriet': - $this->writeThirietCart(); - return; - case 'Flexipan': - $this->writeFlexipanCart(); - return; - case 'Puma': - $this->writePumaCart(); - return; - case 'MIF': - $this->writeMIFCart(); - return; - case 'GrandVision': - $this->writeGrandVisionCart(); - return; - case 'GrandPavois': - $this->writeGrandPavoisCart(); - return; - case 'JoueclubWishlist2021': - $this->writeJoueClub2021Cart(); - return; - case 'Remarkable': - $this->addJsLib('parsley', 'js/libs/parsley.min.js'); - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('remarkable', 'js/libs/fluidbook/cart/fluidbook.cart.remarkable.js'); - break; - case 'Mopec': - $this->addJsLib('parsley', 'js/libs/parsley.min.js'); - $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); - $this->addJsLib('mopec', 'js/libs/fluidbook/cart/fluidbook.cart.mopec.js'); - break; - case 'CFOC': - $this->writeCFOCCart(); - break; - case 'Bastide': - $this->writeBastideCart(); - break; - default: - break; - } - } - if (!$this->config->product_zoom_references && $this->config->basketReferences && $this->config->basketManager == "ZoomProductLink") { - $this->config->product_zoom_references = $this->config->basketReferences; - $this->config->basketReferences = ''; - } - - if ($this->config->product_zoom_references) { - if (file_exists($this->config->product_zoom_references) || Url::isDistant($this->config->product_zoom_references)) { - $referencesFile = $this->config->product_zoom_references; - } else { - $referencesFile = $this->wdir . '/commerce/' . $this->config->product_zoom_references; - } - if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { - $this->config->product_zoom_references = ExcelToArray::excelToArrayKeyValMulti($referencesFile, 'Excel2007', true); - } - } - - if ($this->config->basketReferences && is_string($this->config->basketReferences)) { - if (file_exists($this->config->basketReferences) || Url::isDistant($this->config->basketReferences)) { - $referencesFile = $this->config->basketReferences; - } else { - $referencesFile = $this->wdir . '/commerce/' . $this->config->basketReferences; - } - - if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { - $ext = Files::getExtension($referencesFile); - if ($ext == 'xlsx') { - if ($this->config->basketManager == "ZoomProductLink") { - $function = 'excelToArrayKeyVal'; - } else { - $function = 'excelToArray'; - } - $this->config->basketReferences = ExcelToArray::$function($referencesFile); - if ($this->fluidbookSettings->customLinkClass == 'AtlanticDownloadLink') { - $this->config->basketReferences = self::atlanticReferences($this->config->basketReferences, 'local/', array($this, 'log'), array($this->vdir, "copy")); - } - } - $this->log("Done cart references"); - } - } - } - - public static function atlanticReferences($references, $dir, $log = null, $copy = 'copy') - { - foreach ($references as $i => $sheet) { - foreach ($sheet as $j => $line) { - foreach ($line as $k => $v) { - if (preg_match('|^http:\/\/atlantic-international-book-com\.com\/files\/(.*)$|', $v, $matches)) { - $local = $dir . '/' . $matches[1]; - $url = str_replace(' ', '%20', $v); - $cache = protected_path('fluidbookpublication/atlantic') . md5($url); - if (!file_exists($cache) || filemtime($url) > filemtime($cache)) { - copy($url, $cache); - $copylog = ' (copy) '; - } else { - $copylog = ' '; - } - call_user_func($copy, $cache, $dir . '/' . $matches[1]); - $references[$i][$j][$k] = 'local/' . $matches[1]; - if (null !== $log) { - call_user_func($log, 'Done' . $copylog . $matches[1]); - } - } - } - } - } - - return $references; - } - - public function log($step) - { - $currenttime = microtime(true); - if (null === $this->logfp) { - $this->logfp = fopen(Files::mkdir(storage_path('logs/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); - fflush($this->logfp); - $this->logtime = $currenttime; - - if (null !== $this->getCommand()) { - $this->getCommand()->info(trim($log)); - } - } - - public function addFacebookSDK() - { - $lang = str_replace('-', '_', $this->getFluidbook()->lang); - $e = explode('_', $lang); - if (count($e) > 1) { - $e[1] = mb_strtoupper($lang); - } - $lang = implode('_', $e); - - $langsMap = ['fr' => 'fr_FR', 'en' => 'en_US']; - - if (isset($langsMap[$lang])) { - $lang = $langsMap[$lang]; - } - - $this->beginBody[] = "
-"; - $this->securityPolicyWhitelist[] = '*.facebook.net'; - $this->securityPolicyWhitelist[] = 'data:'; - } - - public function addPageLabel($page, $label) - { - $this->pageLabels[$label] = $page; - } - - public function getResolutions() - { - return self::getBookResolutions($this->getFluidbook()); - } - - - public static function getBookResolutions($book) - { - $maxRes = min(self::MAX_RES, $book->settings['maxResolution']); - $res = []; - if ($maxRes == self::MAX_RES) { - $res = [150, self::MAX_RES]; - } else if ($maxRes <= 150) { - $res = [$maxRes]; - } - return $res; - } - - public function getCssScale() - { - return $this->cssScale; - } - - public function getLinkScale() - { - return $this->linkScale; - } - - public function virtualToPhysical($virtual): string|int - { - if (isset($this->pageLabels[$virtual])) { - return $virtual; - } - if (!in_array($virtual, $this->numerotation)) { - return $virtual; - } - $p = array_search($virtual, $this->numerotation); - return $p + 1; - } - - public function handle() - { - $this->log('Preprocess images'); - FluidbookImagesPreprocess::dispatchSync($this->book_id); - $this->log('Start compile process'); - - // Raw copy of some directories - $directories = array('style/fonts/OpenSans', 'images', 'sound'); - foreach ($directories as $directory) { - $from = $this->assets . '/' . $directory; - $this->vdir->copyDirectory($from, $directory); - } - - if ($this->fluidbookSettings->scorm_enable || $this->fluidbookSettings->secureClientSidePassword) { - $this->fluidbookSettings->seoVersion = false; - } - if ($this->fluidbookSettings->embedAllLibraries) { - $this->addVideoJs(); - $this->addSlideshowLibrary(false); - $this->addSlideshowLibrary(true); - } - - $this->log('Copied assets'); - $this->writeSecure(); - $this->loadPlugins(); - $this->log('Plugins loaded'); - $this->writeImages(); - $this->log('Images written'); - $this->writeCartConfig(); - $this->writeXMLArticles(); - $this->log('XML Articles written'); - $this->writeSlider(); - $this->log('Slider written'); - $linksCSS = $this->writeLinks(); - $this->log('Links written'); - $this->writeArticles(); - $this->log('Articles written'); - $this->writeStats(); - $this->log('Stats written'); - $this->writeLangs(); - $this->log('Langs written'); - $this->writeSEO(); - $this->log('SEO written'); - $this->writeWidget(); - $this->log('Widget written'); - $this->writeSounds(); - $this->log('Sound written'); - $this->writeTexts(); - $this->log('Texts written'); - $this->writeAccessibility(); - $this->log('Accessibility written'); - $this->writeExtras(); - $this->log('Extras written'); - $this->populateConfig(); - $this->log('Config populated'); - $this->writeCSS($linksCSS); - $this->log('CSS written'); - $this->writeIndex(); - $this->log('Index written'); - if ($this->fluidbookSettings->scorm_enable) { - $this->writeScorm(); - $this->log('SCORM written'); - } - $this->writeJs(); - $this->log('Js written'); - $this->vdir->sync(true, $this); - $this->log('Files Synced'); -// $f=rtrim(str_replace('/html5/', '/compiletime/', $this->dir)); -// touch($f); - } - - protected function writeSlider() - { - if ($this->fluidbookSettings->sliderImage) { - $dim = Image::getimagesize($this->wdir . '/' . $this->fluidbookSettings->sliderImage); - $this->config->sliderImageDimensions = $dim; - $this->copyLinkFile($this->fluidbookSettings->sliderImage, 'data/interface'); - } - } - - protected function writeStats() - { - if ($this->fluidbookSettings->stats) { - $this->config->statsMatomo = $this->book_id; - $this->config->statsMatomoServer = 3; - if ($this->book_id >= 21210) { - $this->config->statsMatomoServer = 4 + ($this->book_id % 2); - } - } else { - $this->config->statsMatomo = false; - } - - if ($this->fluidbookSettings->tagcommander_id) { - $id = $this->fluidbookSettings->tagcommander_id; - if (!$this->fluidbookSettings->tagcommander_prod) { - $id .= '/uat'; - } - - $default = ['page_name' => '']; - $this->config->tagcommander_default_vars = array_merge($default, $this->parseVariables($this->fluidbookSettings->tagcommander_default_vars)); - $this->config->tagcommander_default_vars['env_work'] = $this->fluidbookSettings->tagcommander_prod ? 'prod' : 'pre-prod'; - - $scriptNames = explode(',', $this->config->tagcommander_scriptname); - $this->fluidbookSettings->googleAnalyticsCustom .= ''; - for ($i = 1; $i < count($scriptNames); $i++) { - $this->fluidbookSettings->statsCustom .= ''; - } - - if ($this->fluidbookSettings->tagcommander_plan) { - $planPath = $this->_wdirOrAbsolute($this->fluidbookSettings->tagcommander_plan); - - $plan = ExcelToArray::excelToArrayKeyVars($planPath); - $fixedplan = []; - foreach ($plan as $k => $v) { - $e = explode('#', $k); - if (count($e) === 2) { - $k = $e[1]; - } - - $fixedplan[$this->_labelToPage($k)] = $v; - } - $this->config->tagcommander_plan = $fixedplan; - } - } - if (isset($this->fluidbookSettings->googleTagManager) && $this->fluidbookSettings->googleTagManager) { - $this->fluidbookSettings->googleAnalyticsCustom .= " - - -"; - $this->fluidbookSettings->statsCustom = ' - -'; - - - } - } - - - protected function _wdirOrAbsolute($path) - { - $e = explode('#', $path); - if (file_exists($e[0])) { - return $path; - } - return $this->wdir . $path; - - } - - protected function _labelToPage($k) - { - $k = trim($k, '#/'); - $k = str_replace('page/page', 'page', $k); - - if (preg_match('/^page\/(\d+)$/', $k, $matches)) { - return $k; - } - - if (preg_match('/^page\/(.+)$/', $k, $matches)) { - $matches[1] = Text::removeAccents($matches[1]); - $matches[1] = mb_strtolower($matches[1]); - if (isset($this->pageLabels[$matches[1]])) { - return 'page/' . $this->pageLabels[$matches[1]]; - } - } - return $k; - } - - protected function writeSecure() - { - if ($this->fluidbookSettings->secureClientSidePassword) { - $credentials = Text::explodeNewLines($this->fluidbookSettings->secureClientSidePasswordCredentials); - $credentials[] = 'fluidbook:LatacaM4##*'; - $users = []; - foreach ($credentials as $credential) { - $salt = bin2hex(random_bytes(5)); - $e = explode(':', $credential); - if (count($e) <= 1) { - continue; - } - $usersalt = bin2hex(random_bytes(5)); - $user = hash("sha256", $usersalt . '+' . $e[0]); - $users[$user] = ['salt' => $salt, 'usersalt' => $usersalt, 'hash' => hash("sha256", $salt . '-' . $e[1])]; - } - - $secure = file_get_contents($this->wdir . '/' . $this->fluidbookSettings->secureClientSidePassword); - $secure = str_replace('$CREDENTIALS', 'var CREDENTIALS=' . json_encode($users) . ';', $secure); - $secure = str_replace('$TITLE', $this->fluidbookSettings->title, $secure); - $secure = str_replace('$CODE', '$(function () { - $(\'form\').on(\'submit\', function () { - var u = $("#username").val(); - var p = $("#password").val(); - var error = true; - $.each(CREDENTIALS, function (user, data) { - if (forge_sha256(data.usersalt + \'+\' + u) === user && forge_sha256(data.salt + \'-\' + p) === data.hash) { - error = false; - window.sessionStorage.setItem(\'secureUsername\', u); - window.sessionStorage.setItem(\'securePassword\', p); - window.location = \'index.html\'; - } - }); - if (error) { - $("#message").text(\'Wrong username or password\'); - } - return false; - }); - });', $secure); - $this->vdir->file_put_contents('secure.html', $secure); - $this->config->secureClientSidePasswordCredentials = $users; - } - - if ($this->fluidbookSettings->recaptcha) { - $this->beginBody[] = ''; - } - } - - protected function loadPlugins() - { - $e = explode("\n", $this->fluidbookSettings->mobilePlugins); - $main = array_pop($this->jsFiles); - - $plugins = array(); - - foreach ($e as $plugin) { - $plugin = trim($plugin); - if ($plugin == '') { - continue; - } - - $d = 'plugins/' . str_replace('.', '/', $plugin); - $dir = $this->assets . '/' . $d; - if (!file_exists($dir)) { - continue; - } - - $plugins[] = $plugin; - - if (file_exists($dir . '/plugin.js')) { - $f = $d . '/plugin.js'; - $this->pluginJs[] = $f; - $this->vdir->copy($dir . '/plugin.js', $f); - } - if (file_exists($dir . '/plugin.css')) { - $f = $d . '/plugin.css'; - $this->pluginCSS[] = $f; - $this->vdir->copy($dir . '/plugin.css', $f); - } - } - - $this->config->plugins = $plugins; - - array_push($this->jsFiles, $main); - } - - public function getVideosFormats($poster = true) - { - $res = []; - $res[] = 'mp4'; - - if ($poster) { - $res[] = 'jpg'; - } - return $res; - } - - /** - * 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, $collection = null) - { - - if (null === $collection) { - // 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 string The path of the file relative to the /style folder, without any extension - */ - public function addLess($path) - { - if (!in_array($path, $this->lessFiles)) { - $this->lessFiles[] = $path; - } - } - - /** - * @throws \Exception - */ - protected function writeSounds() - { - if ($this->fluidbookSettings->soundTheme == '') { - return; - } - $dir = resource_path('fluidbookpublication/sounds/' . $this->fluidbookSettings->soundTheme); - $this->setSetting('simpleSoundTheme', file_exists($dir . '/flip.mp3')); - $this->vdir->copyDirectory($dir, 'data/sounds'); - } - - protected function writeAccessibility() - { - if ($this->fluidbookSettings->audiodescriptionTexts) { - - $file = $this->wdir . '/' . $this->fluidbookSettings->audiodescriptionTexts; - if (file_exists($file)) { - new PHPExcel(); - $reader = new PHPExcel_Reader_Excel2007(); - $phpexcel = $reader->load($file); - - $sheet = $phpexcel->getActiveSheet(); - $maxRow = $sheet->getHighestRow(0); - - for ($i = 0; $i <= $maxRow; $i++) { - $page = trim($sheet->getCellByColumnAndRow(0, $i)->getValue()); - $text = trim($sheet->getCellByColumnAndRow(1, $i)->getValue()); - $voice = trim($sheet->getCellByColumnAndRow(2, $i)->getValue()); - if ($page == '' || $text == '') { - continue; - } - $data = ['text' => $text]; - if ($voice) { - $data['voice'] = $voice; - } - $this->audioDescriptionTextsList[$page] = $data; - } - } - } - - foreach ($this->audioDescriptionTextsList as $page => $data) { - $replace = [ - '`' => "'", - '“' => '"', - '”' => '"', - '’' => "'", - '—' => " - ", - '‘' => "'", - "…" => "...", - ]; - - $text = trim($data['text']); - $text = str_replace(array_keys($replace), array_values($replace), $text); - $text = Text::cleanUTF8($text, ''); - - $voiceInfos = $data['voice'] ?? $this->fluidbookSettings->audiodescriptionVoice; - - if ($voiceInfos) { - $e = explode(':', $voiceInfos); - - if (count($e) === 1) { - $engine = 'azuretts'; - $voice = $voiceInfos; - } else { - $engine = $e[0]; - $voice = $e[1]; - } - - $hash = hash('sha256', $engine . ':' . $voice . '_^_' . $text); - $fname = $hash . '.mp3'; - $dir = Files::mkdir(protected_path('audiodescription')); - - $file = $dir . $fname; - - if (!file_exists($file) || filesize($file) === 0) { - if ($engine == 'azuretts') { - $e = explode('/', $voice); - $this->_azureTTS($text, $e[0], $e[1], $e[2], $file); - } - } - - $this->config->audiodescription[$page] = $fname; - $this->vdir->copy($file, 'data/audiodescription/' . $fname); - } - $this->accessibleTexts[$page] = $text; - } - - if (count($this->accessibleTexts) > 0) { - $this->config->accessibleTexts = $this->accessibleTexts; - } - } - - - protected function _azureTTS($text, $locale, $gender, $voiceName, $output) - { - try { - $api = new \Cubist\Azure\TTS\Api('28fdfcdcc7f141b29cd9db4afc5779c5'); - $api->textToSpeech($text, $locale, $gender, $voiceName, $output); - } catch (Exception $e) { - dd($e); - } - } - - protected function _writeIndex($page) - { - if (!isset($this->seo->pages[$page])) { - return; - } - /** @var Page $seo */ - $seo = $this->seo->pages[$page]; - if (!$this->fluidbookSettings->seoVersion) { - $seo->robots = false; - } - $html = $seo->getHTML(); - - if ($this->fluidbookSettings->seoVersion) { - $seo->writePage($html, $this->vdir); - } - if ($page == 1) { - $seo->writePage($html, $this->vdir, 'index.html'); - } - } - - /** - * @throws \Exception - */ - public function getIndexVars() - { - if (null === $this->_indexVars) { - $titre = $this->fluidbookSettings->title; - - if (null === $this->_signature) { - $this->_signature = Signature::find($this->fluidbookSettings->signature); - $credits = $this->_signature->credits; - } else { - $credits = ''; - } - $hiddenContents = implode("\n", $this->hiddenContents); - $bgcolor = $this->themeSettings->loadingBackColor; - - // Feuilles de style - $sheets = array_merge($this->stylesheets, $this->specialCSS); - - $style = array(); - foreach ($sheets as $sheet) { - $style[] = ''; - } - $style = implode("\n\t\t", $style); - - $this->log('Got index vars 1'); - - $pagesContents = ''; - - $cache = ''; - - $beginbody = implode("\n", array_unique($this->beginBody)); - - $jstime = "?j=" . time(); - - $iscript = ''; - if (count($this->htmlmultimedia)) { - $iscript .= '' . "\n"; - } - - $script = '' . "\n"; - foreach ($this->jsLibs as $jsLib => $files) { - $script .= "\t" . '' . "\n"; - } - if ($this->fluidbookSettings->scorm_enable) { - $script .= "\t" . '' . "\n"; - } - if (count($this->specialJsFiles)) { - $script .= "\t" . '' . "\n"; - } - foreach ($this->pluginJs as $p) { - $script .= "\t" . '' . "\n"; - } - $script .= $iscript; - - $this->log('Got index vars 2'); - - $socialTitle = htmlspecialchars($this->fluidbookSettings->facebook_title ?: $titre, ENT_COMPAT); - $socialDescription = htmlspecialchars($this->fluidbookSettings->facebook_description ?: $this->fluidbookSettings->seoDescription, ENT_COMPAT); - - $socialImage = 'https://toolbox.fluidbook.com/services/socialimage/' . $this->getFluidbook()->cid; - $dim = self::getSocialImageSize($this->getFluidbook()); - - $socialImageWidth = $dim[0]; - $socialImageHeight = $dim[1]; - - $this->log('Got index vars 2.5'); - - - $titre = $this->fluidbookSettings->title; - - $description = ''; - - $twittercard = ' - - - - '; - $opengraph = ' - - - - '; - - $this->log('Got index vars 3'); - - $favicon = ''; - if ($this->theme->hasFaviconFile()) { - $pngFile = $this->theme->getFaviconPath('png'); - $this->vdir->copy($this->theme->getFaviconPath('ico'), 'data/favicon.ico'); - $this->vdir->copy($pngFile, 'data/favicon.png'); - $this->vdir->copy($pngFile, 'data/apple-touch-icon.png'); - - $datapng = 'data:image/png;base64,' . base64_encode(file_get_contents($pngFile)); - - $favicon .= '' . "\n\t"; - $favicon .= ''; - } - - $print = $this->writePDF(); - $message = ''; - - $this->log('Got index vars 4'); - - $splash = ''; - $splashstyles = ''; - $splashImage = $this->themeAsset('splashImage'); - if ($splashImage) { - $this->vdir->copy($splashImage->getPathname(), 'data/images/' . $splashImage->getFilename()); - $splashstyles = 'background-image:url(' . 'data/images/' . $splashImage->getFilename() . ');background-size:contain;background-position:50% 50%;'; - if ($this->fluidbookSettings->splashURL !== '') { - $splash = ''; - } - } else if ($logoLoader = $this->themeAsset('logoLoader')) { - $dim = Image::getimagesize($logoLoader->getPathname()); - if ($dim !== false) { - $this->vdir->copy($logoLoader->getPathname(), 'data/images/' . $logoLoader->getFilename()); - $splash .= ''; - } - } - $svg = $this->_mergeSVG(); - - if ($this->phonegap) { - $csp = "securityPolicyWhitelist)) . "; img-src * data:\">"; - } - $lang = $this->getFluidbook()->lang; - - $console = ''; - if ($this->fluidbookSettings->debugConsole) { - $console = '
-
- -'; - } - - $this->log('Got index vars 5'); - $vars = array('lang', 'titre', 'credits', 'style', 'script', 'pagesContents', 'print', 'hiddenContents', 'splash', 'splashstyles', 'cache', 'bgcolor', 'message', 'favicon', 'svg', 'beginbody', 'csp', 'opengraph', 'twittercard', 'description', 'console'); - - $res = []; - foreach ($vars as $v) { - if (isset($$v)) { - $res[''] = $$v; - } else { - $res[''] = ''; - } - } - $this->_indexVars = $res; - $this->log('Got index vars 6'); - } - return $this->_indexVars; - } - - protected function _mergeSVG() - { - $symbols = []; - foreach ($this->svgfiles as $svgfile) { - $symbols = array_merge($symbols, $this->_getSVGSymbols($svgfile)); - } - $symbols = array_merge($symbols, $this->_svgSymbols); - return '' . str_replace('> <', '><', Text::removeNewLines(implode('', $symbols))) . ''; - } - - protected function _getSVGSymbols($svg) - { - if (file_exists($svg)) { - $svg = file_get_contents($svg); - } - $svg = str_replace('$bookmark-color', Color::colorToCSS($this->themeSettings->bookmarkBackgroundColor), $svg); - $res = []; - $xml = simplexml_load_string($svg); - if (!$xml) { - return $res; - } - $xml->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg'); - foreach ($xml->xpath('//svg:symbol') as $item) { - $res[(string)$item['id']] = $item->asXML(); - } - - return $res; - } - - protected function writeIndex() - { - $iv = $this->getIndexVars(); - $this->log('Got index vars'); - foreach ($iv as $k => $v) { - $this->seo->html = str_replace($k, $v, $this->seo->html); - } - if ($this->fluidbookSettings->seoVersion) { - foreach ($this->pages as $page => $infos) { - $this->_writeIndex($page); - } - } else { - $this->_writeIndex(1); - } - } - - protected function writeWidget() - { - // Write widget html -// if ($this->widget) { -// $whtml = file_get_contents($this->assets . '/widget.html'); -// $script = ''; -// $script .= ''; -// -// $style = ''; -// $vars = array('titre', 'style', 'script'); -// foreach ($vars as $v) { -// if (isset($$v)) { -// $whtml = str_replace('', $$v, $whtml); -// } else { -// $whtml = str_replace('', '', $whtml); -// } -// } -// $this->vdir->file_put_contents('widget.html', $whtml); -// } - } - - function writeSEO() - { - foreach ($this->seoArticles as $seoArticle) { - if ($this->hybrid) { - $html = file_get_contents($this->assets . '/_seohybrid.html'); - } else { - $html = file_get_contents($this->assets . '/_seo.html'); - } - $a = $seoArticle; - unset($a['image']); - $a['imageurl'] = 'https://workshop.fluidbook.com/services/facebook_thumbnail?cid=' . $this->getFluidbook()->cid . '&j=' . time(); - if ($seoArticle['image']) { - $a['imageurl'] .= '&image=' . $seoArticle['image']; - } - $dim = Image::getimagesize($a['imageurl']); - $a['imagewidth'] = $dim[0]; - $a['imageheight'] = $dim[1]; - foreach ($a as $k => $v) { - $html = str_replace('$' . $k, $v, $html); - } - $this->vdir->file_put_contents('p/' . $seoArticle['url'], $html); - } - $this->seo = new Document($this); - } - - public function addContentLock($page, $unlockConditions = '') - { - $this->config->hasContentLock = true; - $unlockConditions = Text::explodeNewLines($unlockConditions); - $conditions = []; - foreach ($unlockConditions as $unlockCondition) { - $e = explode(',', $unlockCondition); - if (!isset($e[1])) { - $e[1] = 'click'; - } - $conditions[] = $e; - } - $page = max(1, $page); - if (!isset($this->content_lock[$page])) { - $this->content_lock[$page] = ['unlocked' => 0, 'conditions' => []]; - } - $this->content_lock[$page]['conditions'] = array_merge($this->content_lock[$page]['conditions'], $conditions); - } - - protected function writeScorm() - { - $manifestfiles = ['1.2' => '_imsmanifest.12.xml', '2004' => '_imsmanifest.2004.xml', '2004.3' => '_imsmanifest.2004-3.xml']; - $manifestfile = $manifestfiles[(string)$this->fluidbookSettings->scorm_version]; - - $manifest = file_get_contents($this->assets . '/' . $manifestfile); - if (!$this->fluidbookSettings->scorm_title) { - $this->fluidbookSettings->scorm_title = $this->fluidbookSettings->title; - } - if (!$this->fluidbookSettings->scorm_id || ($this->getFluidbook()->book_id > 16614 && $this->fluidbookSettings->scorm_id === 'MFMCTE091mobile')) { - $this->fluidbookSettings->scorm_id = 'fb_' . $this->getFluidbook()->book_id; - } - if (!$this->fluidbookSettings->scorm_org) { - $this->fluidbookSettings->scorm_org = 'Fluidbook'; - } - - $vars = array('scorm_id', 'scorm_org', 'scorm_title'); - foreach ($vars as $v) { - $manifest = str_replace('$' . $v, htmlspecialchars($this->fluidbookSettings->$v, ENT_QUOTES), $manifest); - } - $this->vdir->file_put_contents('imsmanifest.xml', $manifest); - - - $this->config->scorm_variables = $this->fluidbookSettings->scorm_variables = $this->parseVariables($this->fluidbookSettings->scorm_variables); - if ($this->fluidbookSettings->scorm_quizdata) { - $this->config->scorm_quizdata = ExcelToArray::excelToArray($this->wdir . '/' . $this->fluidbookSettings->scorm_quizdata); - } - } - - protected function parseVariables($f) - { - $variables = []; - $f = str_replace("\r", "\n", $f); - $e = Text::explodeNewLines($f); - foreach ($e as $item) { - $item = trim($item); - if ($item == '') { - continue; - } - $f = explode('=', $item, 2); - $variables[trim($f[0])] = trim($f[1]); - } - return $variables; - } - - protected function writePDF() - { - if (!$this->fluidbookSettings->print && !$this->fluidbookSettings->pdf) { - return; - } - - $res = PDF::compilePDF($this->getFluidbook()); - if (!$this->config->pdfName) { - $this->config->pdfName = 'document.pdf'; - } - $this->config->pdfName = Text::removeAccents($this->config->pdfName); - if (mb_strtolower(substr($this->config->pdfName, -4)) !== '.pdf') { - $this->config->pdfName .= '.pdf'; - } - - if ($res !== false) { - $this->vdir->copy($res, 'data/' . $this->config->pdfName); - } - $this->log('PDF written'); - return ''; - } - - protected function addFilesInfos($key, $file) - { - if (!file_exists($file)) { - return; - } - if (!isset($this->config->filesInfos)) { - $this->config->filesInfos = array(); - } - $infos = array('filesize' => filesize($file)); - $dim = Image::getimagesize($file); - if ($dim !== false) { - $infos['width'] = $dim[0]; - $infos['height'] = $dim[1]; - } - $this->config->filesInfos[$key] = $infos; - } - - protected function __($str) - { - if (!isset($this->config->l10n)) { - $this->writeLangs(); - } - return $this->config->get('l10n.default.' . $str, $str); - } - - protected function writeLangs() - { - $this->config->defaultLang = $this->getFluidbook()->locale; - $l10n = FluidbookTranslate::getCompiledTranslations(); - $l10n['default'] = $this->getFluidbook()->getDefaultTranslations($l10n); - $this->config->setRaw('l10n', $l10n); - - - $multilang = Text::explodeNewLines($this->config->get('multilang', '')); - if (count($multilang)) { - $m = array(); - foreach ($multilang as $line) { - $line = trim($line); - if ($line == '') { - continue; - } - $l = explode(',', $line); - $locale = $l[0]; - $flag = $l[1]; - $this->getVirtualDirectory()->copy(resource_path('fluidbookpublication/flags/' . $flag . '.png'), 'images/flags/' . $flag . '.png'); - $l[3] = Text::ucfirst(Locale::translate($locale, $locale)); - $l[4] = Country::translate($flag, $locale); - $m[] = implode(',', $l); - } - - $this->config->setRaw('multilang', implode("\n", $m)); - } - } - - protected function writeExtras() - { - //dd($this->themeAsset('afterSearch')); - if ($afterSearch = $this->themeAsset('afterSearch')) { - $this->vdir->copy($afterSearch->getPathname(), 'data/images/' . $afterSearch->getFilename()); - } - if ($this->fluidbookSettings->externalArchives != '') { - $this->addFilesInfos('archives', $this->wdir . '/' . $this->fluidbookSettings->externalArchives); - $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->externalArchives, 'data/images/' . $this->fluidbookSettings->externalArchives); - } - - if (stristr($this->fluidbookSettings->navExtraImage, '.')) { - $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->navExtraImage, 'data/images/' . $this->fluidbookSettings->navExtraImage); - } - - if (stristr($this->fluidbookSettings->navExtraImageMobile, '.')) { - $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->navExtraImageMobile, 'data/images/' . $this->fluidbookSettings->navExtraImageMobile); - } - - for ($i = 1; $i <= 5; $i++) { - $ic = $this->fluidbookSettings->{'navExtraIcon' . $i}; - if ($ic != '') { - if (stristr($ic, '.svg')) { - $e = explode('.', $ic); - $sname = 'external-' . $e[0]; - $this->addSVGSymbolFromFile($this->wdir . '/' . $ic, $sname); - $this->config->{'navExtraIcon' . $i} = $sname; - } else if (stristr($ic, '.')) { - $this->vdir->copy($this->wdir . '/' . $ic, 'data/images/' . $ic); - } - } - } - } - - protected function addSVGSymbolFromFile($svg, $symbolName) - { - $svg = SVGTools::optimizeSVG($svg); - - $xml = simplexml_load_string(file_get_contents($svg)); - $viewBox = (string)$xml['viewBox']; - - $this->_svgSymbols[$symbolName] = '' . $this->SimpleXMLElement_innerXML($xml) . ''; - } - - protected function writeLinks() - { - - switch ($this->fluidbookSettings->customLinkClass) { - case 'WescoSalesLink': - $this->specialJsFiles[] = 'js/libs/interact.min.js'; - $this->specialJsFiles[] = 'js/libs/fluidbook/special/wescosales.js'; - $this->specialCSS[] = 'wescosales'; - break; - case 'AtlanticDownloadLink': - $this->specialJsFiles[] = 'js/libs/fluidbook/special/atlanticdownload.js'; - $this->specialCSS[] = 'atlanticdownload'; - break; - case 'MiraklEaster2021': - $this->specialJsFiles[] = 'js/libs/fluidbook/special/mirakleaster2021.js'; - $this->specialCSS[] = 'mirakleaster2021'; - break; - } - - $this->config->links = array(); - $this->config->clinks = array(); - $this->config->bookmarkGroups = array(); - - $ignore = $this->fluidbookSettings->ignoreLinksTypes; - if (!$ignore) { - $ignore = array(); - } else { - $ignore = explode(',', $ignore); - } - - 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->width = $meta['width']; - $this->config->externalChaptersSize->height = $meta['height']; - $this->vdir->copyDirectory($d['dir'], $d['fdir']); - } - - $this->getLinksAndRulers($links, $rulers); - $this->_fluidbook->normalizeLinks($links); - - if ($this->fluidbookSettings->basketManager === 'Puma') { - foreach ($links as $k => $init) { - if ($init['type'] == 12 && isset($this->config->product_zoom_references[$init['to']]) && count($this->config->product_zoom_references[$init['to']]) > 0 && implode('', $this->config->product_zoom_references[$init['to']]) != '') { - $init['infobulle'] = 'Digital information'; - $init['animation'] = 'reflet-anim.html'; - $links[$k] = $init; - } - if ($init['type'] == 7) { - $init['image'] = ''; - $init['display_area'] = false; - $links[$k] = $init; - } - } - - } - - // Custom landing page content - if ($this->fluidbookSettings->landingPage != '') { - $d = $this->unzipFile($this->fluidbookSettings->landingPage, false, 'data/landing-page/'); - $this->vdir->copyDirectory($d['dir'], $d['fdir']); - } - - if ($this->fluidbookSettings->tabsHTML5 != '' && file_exists($this->wdir . '/' . $this->fluidbookSettings->tabsHTML5)) { - $ext = Files::getExtension($this->fluidbookSettings->tabsHTML5); - if ($ext === 'zip') { - $links['tabs'] = [ - 'page' => 'background', - 'top' => 0, - 'left' => 0, - 'width' => 100, - 'height' => 100, - 'type' => 6, - 'to' => $this->fluidbookSettings->tabsHTML5, - 'image' => '', - 'inline' => 1, - 'interactive' => 1, - 'class' => 'tabslink', - 'uid' => 'tabs', - ]; - } else if ($ext === 'svg') { - $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->tabsHTML5, 'data/tabs.svg'); - $this->config->svgTabs = true; - $pagesLists = ['tabsPages', 'tabsSections']; - - foreach ($pagesLists as $pagesList) { - $e = explode(',', $this->fluidbookSettings->$pagesList); - $list = []; - foreach ($e as $k => $v) { - $v = trim($v); - if ($v === '') { - continue; - } - if ($v !== '-') { - if ($this->fluidbookSettings->tabsPagesNumbers === 'virtual') { - $v = $this->virtualToPhysical($v); - } - } - $list[] = $v; - } - $this->config->$pagesList = $list; - } - } - } - - $pagesOfCustomLinks = []; - $hiddenLinks = []; - $anchorExists = []; - $closedLinks = []; - - $linksCopy = $links; - - - foreach ($linksCopy as $k => $linkData) { - if ($this->fluidbookSettings->PDFRendererIframe === 'svg' && (($linkData['type'] == 31 && stristr($linkData['to'], '.pdf')) || ($linkData['type'] == 6 && stristr($linkData['alternative'], '.pdf')))) { - $ofile = $this->wdir . '/' . $linkData['to']; - $dfile = $this->wdir . '/' . $linkData['to'] . '.svg'; - if (!file_exists($dfile) || filemtime($dfile) < filemtime($ofile)) { - $cmd = "pdftocairo -svg -f 1 -l 1 $ofile $dfile"; - `$cmd`; - } - $linkData['type'] = 6; - $linkData['to'] = $linkData['to'] . '.svg'; - $linkData['backgroundColor'] = '#fff'; - $links[$k] = $linkData; - } - if ($linkData['type'] == 26 || $linkData == 40) { - $linkData['to'] = AnchorLink::normalizeAnchor($linkData['to']); - $anchorExists[$linkData['to']] = $linkData; - } - if ($linkData['type'] == 35 || $linkData['type'] == 15 || $linkData['type'] == 39) { - $linkData = Link::decryptLink($linkData); - $animations = ContentLink::parseAnimations($linkData['image_rollover']); - foreach ($animations as $animation) { - if (isset($animation['backgroundcolor']) && $animation['backgroundcolor'] !== 'transparent') { - $dupData = $linkData; - $dupData['type'] = 14; - $dupData['to'] = $animation['backgroundcolor']; - - $dupData['uid'] = 'b_' . $linkData['uid']; - $dupData['addzindex'] = -1; - $dupData['image_rollover'] = ''; - array_push($links, $dupData); - array_push($links, $linkData); - unset($links[$k]); - } - } - } - if (isset($linkData['image']) && $linkData['image'] && $linkData['type'] != 28 && $linkData['type'] != 35) { - $dupData = $linkData; - $dupData['image'] = ''; - $dupData['animation'] = ''; - $dupData['to'] = self::_SVGCleanAsset($linkData['image']); - if ($dupData['image_rollover'] != 'none' && !stristr($dupData['image_rollover'], '=')) { - $dupData['rollover'] = $dupData['image_rollover']; - } - $dupData['image_rollover'] = ''; - $dupData['type'] = 15; - $dupData['uid'] = 'i_' . $linkData['uid']; - if (Link::isScorm($linkData)) { - $dupData['scorm'] = true; - } - array_push($links, $dupData); - } - if (isset($linkData['animation']) && $linkData['animation']) { - $dupData = $linkData; - $dupData['image'] = ''; - $dupData['animation'] = ''; - $dupData['inline'] = true; - $dupData['interactive'] = false; - $dupData['to'] = $linkData['animation']; - $dupData['type'] = 6; - $linkData['relatedAnimation'] = $dupData['uid'] = 'a_' . $linkData['uid']; - $dupData['video_width'] = $dupData['video_height'] = 0; - if (Link::isScorm($linkData)) { - $dupData['scorm'] = true; - } - $links[$k] = $linkData; - array_push($links, $dupData); - } - if ($linkData['type'] == 7) { - $k = $linkData['to']; - $e = explode(':', $k); - if (count($e) > 1) { - $k = $e[1]; - } - if (!isset($pagesOfCustomLinks[$k])) { - $pagesOfCustomLinks[$k] = []; - } - if (!in_array($linkData['page'], $pagesOfCustomLinks[$k])) { - $pagesOfCustomLinks[$k][] = $linkData['page']; - } - } - - if ($linkData['type'] == 32 && $linkData['target'] !== 'hide') { - $ids = explode(',', $linkData['to']); - $close = ($linkData['video_service'] && $linkData['video_service'] !== 'none'); - foreach ($ids as $id) { - $id = trim($id); - if ($id === 'tabs') { - $this->config->tabsHiddenAtStartup = true; - } else { - if ($close) { - $closedLinks[] = $id; - $closedLinks[] = 'i_' . $id; - } - $hiddenLinks[] = $id; - $hiddenLinks[] = 'i_' . $id; - } - } - } - } - - if ($this->fluidbookSettings->anchorsAliases && file_exists($this->fluidbookSettings->anchorsAliases)) { - $aliases = []; - $anchors = []; - for ($i = 0; $i <= 2; $i++) { - $lines = Text::explodeNewLines(file_get_contents($this->fluidbookSettings->anchorsAliases)); - foreach ($lines as $line) { - $e = explode("\t", $line); - $from = AnchorLink::normalizeAnchor($e[0]); - $to = AnchorLink::normalizeAnchor($e[1]); - $aliases[$from] = $to; - if (is_numeric($to) && !isset($anchorExists[$from])) { - $anchor = [ - 'page' => $to, - 'top' => 0, - 'left' => 0, - 'width' => 100, - 'height' => 100, - 'type' => 26, - 'to' => $from, - 'uid' => Links::generateUID() - ]; - $anchorExists[$from] = $anchor; - $links[] = $anchor; - } else { - if (!isset($anchorExists[$from]) && isset($anchorExists[$to])) { - $anchor = $anchorExists[$to]; - $anchor['to'] = $from; - $anchor['uid'] = Links::generateUID(); - $anchorExists[$from] = $anchor; - $links[] = $anchor; - } - } - } - } - } - - - $this->config->pagesOfCustomLinks = $pagesOfCustomLinks; - - $i = 1; - $pages = array(); - $cpages = array(); - $ctpages = array(); - $css = array(); - $linkPages = []; - $allLinksData = []; - $gamifyCoins = []; - - usort($links, array($this, '_sortLinks')); - - foreach ($links as $linkData) { - if (in_array($linkData['type'], $ignore)) { - continue; - } - if ($linkData['uid'] === 'slider') { - $linkData['page'] = 'background'; - } - - $linkData['hidden'] = in_array($linkData['uid'], $hiddenLinks); - if (isset($linkData['zindex']) && $linkData['zindex'] < 50 && in_array($linkData['uid'], $closedLinks)) { - $linkData['zindex'] = 50; - } - if ($linkData['type'] == 28) { - $this->addSEOArticle('#/page/' . $linkData['page'], $linkData['to'], $linkData['extra'], $linkData['image']); - continue; - } - - $link = Link::getInstance($this->base62($i), $linkData, $this); - if (is_null($link) || $link->ignore()) { - continue; - } - - - $linksToAdd = [$link]; - if ($link->overlapDoublePage() && !$this->isOnePage()) { - $linksToAdd[] = $link->getRightClone(); - } - - - foreach ($linksToAdd as $lta) { - try { - /** @var $lta Link */ - // Keep this line because some properties of the link (like blend mode) are parsed with this function - $c = $lta->getHTMLContainer(); - - - $css[] = $lta->getCSSContainer(); - if (!isset($pages[$lta->page])) { - $pages[$lta->page] = ['normal' => []]; - $cpages[$lta->page] = ['normal' => []]; - $ctpages[$lta->page] = ['normal' => []]; - } - - - $d = $lta->getDepth(); - if ($d < 30) { - $v = 'ctpages'; - } else if ($d < 50) { - $v = 'cpages'; - } else { - $v = 'pages'; - } - - $lta->setInitialOrder($i); - if (!isset($$v[$lta->page][$lta->blendmode])) { - $$v[$lta->page][$lta->blendmode] = []; - } - - array_push($$v[$lta->page][$lta->blendmode], $lta); - $i++; - } catch (\Exception $e) { - $this->triggerLinkError($e, $lta); - } - } - - - // Make old "aftersearch" link compatible with new "extra" menu option by extracting link URL - if ($link->page == 'aftersearch') { - $this->config->afterSearchLink = $link->to; - $this->config->afterSearchTooltip = $link->infobulle; - } - - if (strpos($link->page, 'link_') === 0) { - $linkPages[$link->page] = true; - } - - if ($link->gamifyCoins) { - $gamifyCoins[$linkData['uid']] = $link->gamifyCoins; - } - - $allLinksData[$linkData['uid']] = $linkData; - - if ($link->keep()) { - $this->hiddenContents[] = $link->getHTMLContainer(); - } - } - - $allpages = range(0, $this->getFluidbook()->getPagesNumber() + 1); - if ($this->fluidbookSettings->themeEnableAfterSearch) { - $allpages[] = 'aftersearch'; - } - $allpages[] = 'background'; - $allpages[] = 'archives'; - $allpages[] = 'slider'; - foreach ($linkPages as $linkPage => $true) { - $allpages[] = $linkPage; - } - - foreach ($allpages as $i) { - $this->config->set('links.' . $i, $this->_htmlLinkList($pages[$i] ?? [])); - $this->config->set('clinks.' . $i, $this->_htmlLinkList($cpages[$i] ?? [])); - $this->config->set('ctlinks.' . $i, $this->_htmlLinkList($ctpages[$i] ?? [])); - } - - if ($this->writeLinksData) { - $this->config->linksData = $allLinksData; - } - $this->config->gamifyCoins = $gamifyCoins; - - return $css; - } - - /** - * @return bool - */ - public function isOnePage(): bool - { - return $this->_fluidbook->isOnePage(); - } - - /** - * @param $e \Exception - * @param $link Link - * @return void - * @throws \Exception - */ - protected function triggerLinkError($e, $link) - { - Log::error($e); - - /*$c = explode('\\', get_class($link)); - $type = array_pop($c); - $type = str_replace('Link', '', $type); - - throw new \Exception('Error on the ' . $type . ' link to ' . $link->to . ' on page ' . $link->page . ' with message : ' . $e->getMessage());*/ - } - - protected function _htmlLinkList($list) - { - if (!count($list)) { - return []; - } - $res = []; - foreach ($list as $blendmode => $l) { - usort($l, [$this, '_sortLinksByDepth']); - $res[$blendmode] = []; - foreach ($l as $item) { - $res[$blendmode][] = $item->getHTMLContainer(); - } - - } - return $res; - - } - - public function getBookSurface() - { - return $this->width * $this->height; - } - - protected function _sortLinksByDepth($a, $b) - { - $c = $a->getDepth() - $b->getDepth(); - if ($c === 0) { - $c = $b->getSurface() - $a->getSurface(); - } - if ($c === 0) { - $c = $b->getInitialOrder() - $a->getInitialOrder(); - } - - return $c; - } - - public function addSlideshowLibrary($inline = true) - { - $l = ($inline ? $this->config->inlineSlideshowLibrary : $this->config->popupSlideshowLibrary); - if ($l === 'splide') { - $this->addJsLib('splide', 'js/libs/splide/splide.js'); - } - - $this->addJsLib('slideshow', ['js/libs/fluidbook/slideshow/fluidbook.slideshow.js', - 'js/libs/fluidbook/slideshow/fluidbook.slideshow.' . $l . '.js']); - $this->addLess('slideshow/' . $l); - } - - public function addSEOArticle($page, $title, $intro, $image, $id = null, $url = null, $content = '') - { - if (null === $url) { - $url = Text::str2URL($title) . '.html'; - } - if (null === $id) { - $id = $title; - } - - $this->seoArticles[$id] = ['title' => $title, 'description' => $intro, 'image' => $image, 'content' => $content, 'page' => $page, 'url' => $url, 'id' => $id]; - } - - public function _sortLinks($a, $b) - { - - $priorities = array(26 => -1, 35 => 1); - - $pa = isset($priorities[$a['type']]) ? -$priorities[$a['type']] : 0; - $pb = isset($priorities[$b['type']]) ? -$priorities[$b['type']] : 0; - return $pb - $pa; - } - - public function addBookmarkGroup($link) - { - if ($link['left'] > $this->fluidbookSettings->width) { - //$link['page']++; - } - if ($link['page'] <= 0 || $link['page'] > $this->fluidbookSettings->pages) { - return; - } - - $this->config->bookmarkGroups[] = array('page' => ($link['page']), 'nb' => $link['to'], 'name' => $link['extra']); - } - - public function addTriggersLink($page, $link, $delay = 0) - { - $this->config->push('triggersLinks', ['page' => $page, 'link' => $link, 'delay' => $delay]); - } - - public function addAudiodescription($link) - { - - $e = explode('.', $link['to']); - $ext = mb_strtolower(array_pop($e)); - if ($ext === 'txt') { - $file = $this->wdir . '/' . $link['to']; - if (file_exists($file)) { - $this->audioDescriptionTextsList[$link['page']] = ['text' => file_get_contents($file)]; - } - } else { - $this->config->set('audiodescription.' . $link['page'], $link['to']); - $this->copyLinkFile($link['to'], 'data/audiodescription/'); - } - } - - protected function beforeWriteConfig() - { - // Dynamic background - $dbc = []; - $p = $this->parseVariables($this->fluidbookSettings->dynamicBackgroundColor); - foreach ($p as $range => $color) { - $e = explode(',', $color); - $pages = ArrayUtil::parseRange($range); - foreach ($pages as $page) { - $dbc[$page] = $e; - } - } - $this->config->dynamicBackgroundColor = $dbc; - if ($this->fluidbookSettings->textsThickness > 1) { - if ($this->fluidbookSettings->textsThicknessPages == '') { - $this->config->textsThicknessPages = range(1, $this->fluidbookSettings->pages); - } else { - $this->config->textsThicknessPages = ArrayUtil::parseRange($this->fluidbookSettings->textsThicknessPages); - } - } else { - $this->config->textsThickness = 1; - $this->config->textsThicknessPages = []; - } - - // Content locks - uasort($this->content_lock, function ($a, $b) { - return $a['page'] - $b['page']; - }); - - // Gamify - $p = $this->parseVariables($this->fluidbookSettings->gamify_coins_pages); - foreach ($p as $range => $coins) { - $pages = ArrayUtil::parseRange($range); - foreach ($pages as $page) { - $this->config->gamifyCoins['visit_page_' . $page] = (int)$coins; - } - } - - $this->config->content_lock = $this->content_lock; - } - - public function addPDFJS($force = false) - { - if ($this->_addedPDFJS) { - return; - } - - if (stripos($this->fluidbookSettings->PDFRenderer, 'pdfjs') !== false) { - $renderer = $this->fluidbookSettings->PDFRenderer; - } else if ($force) { - $renderer = 'pdfjs-legacy'; - } else { - return; - } - - $this->_addedPDFJS = true; - - - if ($renderer === 'pdfjs') { - $resource = resource_path('pdfjs/dist-min'); - } else if ($renderer === 'pdfjs-legacy') { - $resource = resource_path('pdfjs/legacy-min'); - } - $this->vdir->copyDirectory($resource, 'pdfjs'); - $this->vdir->copy($this->assets . '/js/libs/pdfjs/custom.js', 'pdfjs/web/custom.js'); - - - $css = '.seamless #sidebarContainer, .seamless .toolbar {display:none !important;}'; - $css .= '.seamless .pdfViewer{padding:0 !important;}'; - $css .= '.seamless #viewerContainer{top:0 !important;overflow:visible !important;}'; - $css .= '.seamless{--page-border:0;--page-margin:0;--body-bg-color:transparent;}'; - $css .= '.openFile,.rotateCw,.rotateCcw,.rotateCcw + .horizontalToolbarSeparator{display:none !important;}' . $this->fluidbookSettings->PDFJSCSS; - $this->vdir->file_put_contents('pdfjs/web/viewer.css', file_get_contents($resource . '/web/viewer.css') . $css); - } - - protected function writeJs() - { - $this->beforeWriteConfig(); - - $config = $this->writeConfig(); - $this->vdir->file_put_contents('data/datas.js', $config); - - $finals = $this->jsLibs; - $this->addPDFJS(); - - if ($this->fluidbookSettings->scorm_enable) { - $finals['scorm'] = array(); - $finals['scorm'][] = 'js/libs/scorm/apiwrapper.js'; - $finals['scorm'][] = 'js/libs/scorm/scorm.js'; - } - if (count($this->specialJsFiles)) { - $finals['special'] = $this->specialJsFiles; - } - if ($this->widget) { - $finals['widget'] = $this->widgetJsFiles; - } - - $dirminimized = Files::mkdir($this->compiledAssets . '/js/min'); - - foreach ($finals as $jsfinal => $files) { - $mintime = 0; - $hash = hash('sha256', json_encode($files)); - $minimized = $dirminimized . $jsfinal . '-' . $hash . '-min.js'; - if (file_exists($minimized) && filesize($minimized) > 0) { - $mintime = filemtime($minimized); - $reminimize = false; - } else { - $mintime = 0; - $reminimize = true; - } - - if (!$reminimize) { - foreach ($files as $file) { - $f = $this->assets . '/' . $file; - if (file_exists($f) && filemtime($f) > $mintime) { - $reminimize = true; - break; - } - } - } - - if (!$reminimize) { - if (filemtime(__FILE__) > $mintime || (file_exists(__DIR__ . '/class.ws.html5.links.php') && filemtime(__DIR__ . '/class.ws.html5.links.php') > $mintime)) { - $reminimize = true; - } - } - - if ($reminimize) { - $js = ''; - $hasNonMin = false; - foreach ($files as $file) { - $f = $this->assets . '/' . $file; - if (!file_exists($f)) { - continue; - } - if (strpos($f, '.min.') === false) { - $hasNonMin = true; - } - $js .= file_get_contents($f); - $js .= ";\n\n"; - } - $tmp = Files::tempnam(); - file_put_contents($tmp, $js); - - if (file_exists($minimized)) { - unlink($minimized); - } - - if (file_exists($tmp) && filesize($tmp) > 0) { - if ($hasNonMin) { - $uglify = new CommandLine('uglifyjs'); - $uglify->setArg('o', $minimized); - $uglify->setArg(null, $tmp); - $uglify->execute(); - } else { - $uglify = null; - copy($tmp, $minimized); - } - - if (!file_exists($minimized) || filesize($minimized) == 0) { - die('An error occured while uglifying ' . $hasNonMin . '? ' . $minimized . ': ' . ($uglify ? $uglify->commande : '') . ' :: ' . ($uglify ? $uglify->output : '') . '(' . implode(',', $files) . ')'); - } - } - } - $dest = 'data/' . $jsfinal . '.js'; - $this->vdir->copy($minimized, $dest); - } - - - if ($this->phonegap) { - // $this->vdir->copy(WS_COMPILE_ASSETS . '/_html5/js/libs/phonegap/' . $this->phonegapVersion . '/cordova-' . $this->phonegap . '.js', 'data/cordova.js'); - } - $this->vdir->copyDirectory($this->assets . '/js/libs/fluidbook/workers', 'js/libs/fluidbook/workers'); - $this->vdir->copyDirectory($this->assets . '/js/libs/stand', 'js/libs/stand'); - $this->vdir->copyDirectory($this->assets . '/js/libs/polyfills', 'js/libs/polyfills'); - } - - public function getCacheDir($path): string - { - return Files::mkdir(protected_path('fluidbookpublication/cache/' . $path)); - } - - public function writeTexts() - { - $cache = sha1($this->fluidbookSettings->highlightResults . '/--/' . $this->fluidbookSettings->searchWordSelectionAlgorithm . '///' . $this->fluidbookSettings->textExtraction . '|--|' . $this->fluidbookSettings->ignoreSearchSeparators . '|||' . $this->getFluidbook()->getCompositionUpdate() . '()()()' . FWSTK::lastUpdate()); - $cacheDir = Files::mkdir(protected_path('fluidbookpublication/index/' . $this->book_id . '/' . $cache . '/')); - $indexFile = $cacheDir . '/search.index.js'; - $textFile = $cacheDir . '/search.texts.js'; - $hightlightsFile = $cacheDir . '/search.highlight.js'; - - if (!file_exists($indexFile) || !file_exists($textFile)) { - SearchIndex::makeTextsIndexes($this, $cacheDir, $index, $texts, true); - file_put_contents($indexFile, 'var INDEX=' . $index . ';' . "\r"); - file_put_contents($textFile, 'var TEXTS=' . $texts . ";\r"); - } - if ($this->fluidbookSettings->highlightResults && !file_exists($hightlightsFile)) { - file_put_contents($hightlightsFile, 'var HIGHLIGHTS=' . json_encode(SearchIndex::makeHighlightIndex($this)) . ";\r"); - } - $this->vdir->copy($cacheDir . '/search.index.js', 'data/search.index.js'); - if ($this->fluidbookSettings->highlightResults) { - $this->vdir->copy($cacheDir . '/search.highlight.js', 'data/search.highlight.js'); - } - if ($this->fluidbookSettings->searchWordSelectionAlgorithm == 'expression') { - $this->vdir->copy($cacheDir . '/search.texts.js', 'data/search.texts.js'); - } - } - - protected function _SVGCleanAsset($a) - { - if (!stristr($a, '.svg')) { - return $a; - } - $clean = str_replace('.svg', '.o.svg', $a); - $path = $this->wdir . '/' . $a; - $opt = $this->wdir . '/' . $clean; - - if (!file_exists($opt) || !filesize($opt) || filemtime($path) > filemtime($opt)) { - if (file_exists($opt) && is_link($opt)) { - unlink($opt); - } - SVGTools::_optimizeSVG($path, $opt); - } - return $clean; - - } - - public function supportSVG() - { - if (!$this->phonegap) { - return false; - } else if ($this->phonegap == 'ios') { - return true; - } else { - return false; - } - } - - protected function writeConfig() - { - $data = $this->config->getRawData(); - foreach ($data as $k => $v) { - if (null === $v) { - $v = $data[$k] = ''; - } - if ($this->getFluidbook()->getField($k) instanceof Checkbox) { - $v = $data[$k] = !!$v; - } - } - $data['id'] = $this->book_id; - $data['compiler'] = 3; - return 'var SETTINGS=' . json_encode($data) . ';' . "\n"; - } - - protected function writeCountries() - { - $c = Country::getList($this->getFluidbook()->locale); - asort($c); - $this->config->countries = $c; - } - - protected function writeManifest() - { - $res = array(); - // TODO: Why was this function missing a return statement? It's called from populateConfig() is expected to return a value. - return $res; - } - - protected function writeImages() - { - switch ($this->fluidbookSettings->mobileVersion) { - case 'html5-desktop': - $this->backgroundsPrefix = array(true, false); - $this->svg = true; - break; - case 'html5-images': - $this->backgroundsPrefix = array(true); - $this->svg = false; - break; - default: - $this->backgroundsPrefix = array(false); - $this->svg = true; - break; - } - - $rasterizePages = $this->config->rasterizePages; - $this->config->pagesDimensions = []; - - if ($this->fluidbookSettings->mobileNavigationType === 'mobilefirst') { - $imdir = 'mf'; - } else { - $imdir = 'html'; - } - - $thumbs = array(); - foreach ($this->pages as $page => $infos) { - $thisrasterize = in_array($page, $rasterizePages); - $thisimagesvg = !$thisrasterize && $this->svg; - $thisbackgroundPrefix = $thisrasterize ? [true] : $this->backgroundsPrefix; - - foreach ($this->getResolutions() as $r) { - foreach ($thisbackgroundPrefix as $backgroundsPrefix) { - $source = $this->getFluidbook()->getFile($page, $this->imageFormat, $r, $backgroundsPrefix, true, $imdir); - if ($r === $this->maxRes) { - $this->getPageDimension($page); - } - $this->vdir->copy($source, 'data/background/' . $r . '/' . ($backgroundsPrefix ? 't' : 'p') . $page . '.' . $this->imageFormat); - } - } - - if ($thisimagesvg) { - $this->vdir->copy( - $this->getFluidbook()->getFile($page, 'svg', 150, true, - in_array($page, $this->config->vectorPages), 'html') - , 'data/contents/p' . $page . '.svg'); - } - - $t = $this->getFluidbook()->getThumbFile($page, $this->imageFormat); - $this->vdir->copy($t, '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'); - } - - - /** - * @param $page - * @return array - */ - protected function getPageDimension($page) - { - $k = 'pagesDimensions.' . $page; - if (!$this->config->has($k)) { - $d = $this->getFluidbook()->getDocumentSize($page); - $res = [round($this->cssWidth, 2), round($d[1] * ($this->cssWidth / $d[0]), 2)]; - $this->config->set($k, $res); - return $res; - } - return $this->config->get($k); - } - - public function getWidth() - { - return $this->getPageDimension(1)[0]; - } - - public function getHeight() - { - return $this->getPageDimension(1)[1]; - } - - - protected function _makeCover($orig) - { - $cached = $this->wdir . '/_cover.jpg'; - - if (!file_exists($cached) || filemtime($cached) < filemtime($orig)) { - $size = Image::getimagesize($orig); - $w = $size[0]; - $h = $size[1]; - - $tmp = Files::tempnam() . '.png'; - - $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 .= $cached; - $convert->setManualArg($cmd); - $convert->execute(); - - unlink($tmp); - } - $this->vdir->copy($cached, 'cover.jpg', true); - - } - - protected function _lessBoolean($val) - { - return $this->_themeBoolean($val) ? 'true' : 'false'; - } - - protected function _font($f) - { - $default = 'Arial, Helvetica, sans-serif'; - if ($f === 'OpenSans') { - $f = 'Open Sans'; - } - switch ($f) { - case 'Montserrat': - case 'Open Sans': - $this->addFontKit($f); - return "'" . $f . "', " . $default; - case 'sans-serif': - return $f; - case 'Arial': - return $default; - default: - return "'Open Sans', Arial, Helverica, sans-serif"; - } - } - - protected function _themeBoolean($v) - { - return !(null === $v || $v === '0' || $v === 0 || $v === false || !$v); - } - - protected function writeCSS($links) - { - $res = array(); - - $this->addFontKit('OpenSans'); - - $lessContents = ''; - - $this->lessVariables['font'] = $this->_font($this->themeSettings->interfaceFont); - $this->lessVariables['text-transform'] = $this->_themeBoolean($this->themeSettings->interfaceFontUppercase) ? 'uppercase' : 'inherit'; - - $this->lessVariables['css-scale'] = $this->cssScale; - - $this->lessVariables['slider-background'] = Color::colorToCSS(!$this->themeSettings->sliderBackground ? 'rgba(0,0,0,0.1)' : $this->themeSettings->sliderBackground); - $this->lessVariables['slider-handle'] = Color::colorToCSS(!$this->themeSettings->sliderHandle ? '#ffffff' : $this->themeSettings->sliderHandle); - $this->lessVariables['slider-display'] = $this->_lessBoolean($this->themeSettings->pagesBar); - $this->lessVariables['slider-thumb-background'] = Color::colorToCSS($this->themeSettings->pageBarThumbBack); - $this->lessVariables['pages-background'] = $this->fluidbookSettings->forceWhiteBackground ? '#ffffff' : 'transparent'; - - $this->log('CSS 1'); - - // General theme - $cssWidth = $this->cssWidth; - $cssHeight = $this->cssHeight; - $cssScale = $this->cssScale; - $w2 = ($cssWidth * 2) . 'px'; - $h = $cssHeight . 'px'; - - $wm = ($this->width * $this->multiply) . 'px'; - $hm = ($this->height * $this->multiply) . 'px'; - $w = $cssWidth . 'px'; - $offsetLeft = round(($this->optimalWidth - $cssWidth) / 2, 3); - $offsetLeft2 = $offsetLeft * 2; - $offsetTop = round(($this->optimalHeight - $cssHeight) / 2, 3); - $navTop = ($cssHeight - 40 - 100) / 2; - $leftOfRightPage = (floor($cssWidth) - 1) . 'px'; - - $this->lessVariables['z'] = $this->z; - $this->lessVariables['book-page-width'] = $w; - - - $this->lessVariables['book-page-correct-width'] = $w; - $this->lessVariables['book-page-correct-height'] = $h; - - - $this->log('CSS 2'); - $this->lessVariables['book-page-height'] = $h; - $this->lessVariables['book-page-ratio'] = floatval($w) / floatval($h); - - $this->lessVariables['page-shade-opacity'] = min(1, $this->themeSettings->shadeAlpha / 50); - $c = new Color($this->themeSettings->bookShadeColor); - $this->lessVariables['shadow-opacity'] = $c->getAlpha() * 1.2; - $this->lessVariables['edges-display'] = $this->_lessBoolean($this->themeSettings->usePageEdges); - $this->lessVariables['edge-left-offset'] = 0; - $this->lessVariables['edge-right-offset'] = 0; - $this->lessVariables['edges-opacity'] = 1; - - - $this->lessVariables['audioplayer-background-color'] = Color::colorToCSS($this->themeSettings->audioplayerBackgroundColor ?: $this->themeSettings->couleurL); - $this->lessVariables['audioplayer-icon-color'] = Color::colorToCSS($this->themeSettings->audioplayerIconColor); - $this->config->audioplayerStrokeColor = $this->lessVariables['audioplayer-stroke-color'] = Color::colorToCSS($this->themeSettings->audioplayerStrokeColor ?: $this->themeSettings->couleurL); - - $this->lessVariables['page-number-color'] = Color::colorToCSS($this->themeSettings->colorPageNumber); - $this->lessVariables['display-page-number'] = $this->_lessBoolean($this->themeSettings->displayPageNumber); - $this->lessVariables['page-transition-duration'] = $this->fluidbookSettings->mobileTransitionDuration . 's'; - - $this->config->mobileTransitionDurationSlide = ($this->fluidbookSettings->mobileTransitionDurationSlide ?: $this->fluidbookSettings->mobileTransitionDuration); - $this->lessVariables['page-transition-slide-duration'] = $this->config->mobileTransitionDurationSlide . 's'; - - $corrText = $this->isMobileFirst() ? 0 : 4; - $this->log('CSS 3'); - - // Theme - $shade = '.page .shade{'; - $shade .= 'opacity:' . min(($this->themeSettings->shadeAlpha * 2) / 100, 1) . ';'; - $shade .= '}'; - $res[] = $shade; - - // SVG - $res[] = 'svg .fill-c-menu-back{fill:' . Color::colorToCSS($this->themeSettings->couleurB) . ';}'; - $res[] = 'svg .fill-c-menu-text{fill:' . Color::colorToCSS($this->themeSettings->subTextColor) . ';}'; - - // Background - $res[] = $this->_cssBackground(); - $this->log('CSS 4'); - // Archives - // Header - $header = 'header{'; - $header .= 'height:' . $this->themeSettings->menuHeight . 'px;'; - if ($mi = $this->themeAsset('menuImage')) { - $this->vdir->copy($mi->getPathname(), 'data/images/' . $mi->getFilename()); - $header .= 'background-image:url(../images/' . $mi->getFilename() . ');'; - $header .= 'background-repeat:no-repeat;'; - $header .= 'background-size:100% ' . $this->themeSettings->menuHeight . 'px;'; - } else { - // Force redo - $header .= 'background-color:' . Color::colorToCSS($this->themeSettings->menuColor) . ';'; - } - $header .= '}'; - $res[] = $header; - $this->log('CSS 5'); - // Logo - $logo = '#logo{'; - if ($l = $this->themeAsset('logo')) { - $this->vdir->copy($l->getPathname(), 'data/images/' . $l->getFilename()); - $dim = Image::getimagesize($l->getPathname()); - $logo .= 'background-image:url(../images/' . $l->getFilename() . ');width:' . $dim[0] . 'px;height:' . $dim[1] . 'px;'; - } - $logo .= '}'; - $res[] = $logo; - - // Credits - $res[] = 'footer,footer a{color:' . Color::colorToCSS($this->themeSettings->creditsColor) . ';}'; - $this->log('CSS 6'); - // Arrows - $this->lessVariables['arrows-background'] = Color::colorToCSS($this->themeSettings->couleurA); - $this->lessVariables['arrows-color'] = Color::colorToCSS($this->themeSettings->arrowsColor); - - // Loader - $this->lessVariables['loader-background-color'] = Color::colorToCSS($this->themeSettings->couleurL); - $this->lessVariables['loader-foreground-color'] = Color::colorToCSS($this->themeSettings->loadingSecColor); - - // Audio description buttons - $this->lessVariables['audiodescription-background'] = Color::colorToCSS($this->themeSettings->couleurA); - $this->lessVariables['audiodescription-color'] = Color::colorToCSS($this->themeSettings->couleurA); - $this->log('CSS 7'); - // Links Styles - $this->lessVariables['links-color'] = Color::colorToCSS($this->themeSettings->linksColor); - $this->lessVariables['slideshow-color'] = Color::colorToCSS($this->themeSettings->slideshowColor ?: $this->themeSettings->couleurB); - $this->lessVariables['inlineslideshow-transition-time'] = (floatval($this->fluidbookSettings->inlineSlideshowTransitionDuration) * 1000) . 'ms'; - $this->lessVariables['slideshow-caption-size'] = $this->fluidbookSettings->slideshowCaptionSize ?: '16px'; - - $res = array_merge($res, $links); - - // Bookmarks - if (!isset($this->fluidbookSettings->bookmarkCornerSize)) { - $this->fluidbookSettings->bookmarkCornerSize = 10; - } - $this->log('CSS 8'); - $this->lessVariables['bookmark-star-disabled-color'] = Color::colorToCSS($this->themeSettings->bookmarkStarDisabledColor); - $this->lessVariables['bookmark-star-enabled-color'] = Color::colorToCSS($this->themeSettings->bookmarkStarEnabledColor); - $this->lessVariables['bookmark-color'] = Color::colorToCSS($this->themeSettings->bookmarkBackgroundColor); - $this->lessVariables['bookmark-corner-size'] = round($this->width * $this->fluidbookSettings->bookmarkCornerSize * 0.0075 * $this->z) . 'px'; - $this->lessVariables['bookmark-corner-offset'] = $this->fluidbookSettings->bookmarkOffset . 'px'; - - // Menus - $menuColor = new Color($this->themeSettings->couleurB); - $menuColor->setAlpha(1); - $menuTextColor = Color::colorToCSS($this->themeSettings->subTextColor); - $menuBreakpoint = empty($this->fluidbookSettings->menuBreakpoint) ? '1023px' : $this->fluidbookSettings->menuBreakpoint; - - $this->lessVariables['menu-breakpoint'] = $menuBreakpoint; - $this->lessVariables['menu-background'] = $menuColor->toCSS(); - if ($this->themeSettings->subSecondaryColor) { - $this->lessVariables['menu-button-background'] = Color::colorToCSS($this->themeSettings->subSecondaryColor); - } else { - $this->lessVariables['menu-background-green'] = 'max(45, min(255-45, green(@menu-background)))'; - $this->lessVariables['menu-background-red'] = 'max(45, min(255-45, red(@menu-background)))'; - $this->lessVariables['menu-background-blue'] = 'max(45, min(255-45, blue(@menu-background)))'; - $this->lessVariables['menu-button-background'] = 'overlay(rgb(@menu-background-red, @menu-background-green, @menu-background-blue), #c0c0c0)'; - } - $this->log('CSS 9'); - $this->lessVariables['menu-text'] = $menuTextColor; - $this->lessVariables['menu-field-background'] = Color::colorToCSS($this->themeSettings->subFieldColor); - $this->lessVariables['menu-field-text'] = Color::colorToCSS($this->themeSettings->subTextFieldColor); - $this->lessVariables['menu-select-background'] = Color::colorToCSS($this->themeSettings->subSelectColor); - $this->lessVariables['menu-select-text'] = Color::colorToCSS($this->themeSettings->subTextSelectColor); - $this->lessVariables['icon-color'] = Color::colorToCSS($this->themeSettings->couleurI); - $this->lessVariables['menu-overlay'] = Color::colorToCSS($this->themeSettings->popupVideoOverlay); - - $this->log('CSS 10'); - // Chapters - $this->lessVariables['menu-chapters-columns-count'] = max(1, min(6, $this->fluidbookSettings->chaptersColumns)); - $this->lessVariables['menu-chapters-columns-width'] = $this->fluidbookSettings->chaptersColMaxWidth; - $this->lessVariables['menu-chapters-font-size'] = $this->fluidbookSettings->chaptersFontSize; - - foreach ($this->getFluidbook()->getChapters() as $chapter) { - if ($chapter['color'] == '') { - continue; - } - $color = trim($chapter['color'], '#'); - $lessContents .= '.mview.c_' . $color . '{.menu-color(' . Color::colorToCSS($color) . ');}'; - } - - // Archives -// if ($this->>getFluidbook()->parametres->externalArchivesBack) { -// $this->vdir->copy($this->wdir . '/' . $this->>getFluidbook()->parametres->externalArchivesBack, 'data/images/' . $this->>getFluidbook()->parametres->externalArchivesBack); -// $res[] = '.mview.archives{background-image:url("../images/' . $this->>getFluidbook()->parametres->externalArchivesBack . '");}'; -// } - $this->log('CSS 11'); - # Index - $thumbw = $this->fluidbookSettings->mobileNavigationType === 'portrait' ? 200 : 100; - $this->lessVariables['thumb-width'] = $thumbw . 'px'; - $ratio = $this->width / $this->height; - $thumbh = round($thumbw / $ratio); - $this->config->thumbWidth = $thumbw; - $this->config->thumbHeight = $thumbh; - - $this->lessVariables['thumb-height'] = $thumbh . 'px'; - - #tooltip - $this->lessVariables['tooltip-background'] = Color::colorToCSS($this->themeSettings->tooltipBackColor); - $this->lessVariables['tooltip-color'] = Color::colorToCSS($this->themeSettings->tooltipTextColor); - $this->lessVariables['tooltip-font-size'] = $this->themeSettings->tooltipTextSize == 100 ? 14 : $this->themeSettings->tooltipTextSize; - $this->lessVariables['tooltip-padding'] = $this->themeSettings->tooltipPadding ?: 20; - $this->log('CSS 12'); - #Videos - if ($this->fluidbookSettings->bigPlayImage) { - $this->lessVariables['video-bigplay-image'] = '~"../data/links/' . $this->fluidbookSettings->bigPlayImage . '"'; - $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->bigPlayImage, 'data/links/' . $this->fluidbookSettings->bigPlayImage); - } else { - $this->lessVariables['video-bigplay-image'] = '~"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMTMuNCAxMTMuNCI+PHN0eWxlPi5zdDB7b3BhY2l0eTowLjg7fSAuc3Qxe2ZpbGw6I0ZGRkZGRjt9PC9zdHlsZT48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTEwLjUgMTEzLjRIMi45Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlWMi45QzAgMS4zIDEuMyAwIDIuOSAwaDEwNy42YzEuNiAwIDIuOSAxLjMgMi45IDIuOXYxMDcuNmMwIDEuNi0xLjMgMi45LTIuOSAyLjl6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTQ1LjggMzcuOGwzMS41IDE3LjljLjguNS44IDEuNiAwIDIuMUw0NS44IDc1LjZjLS44LjUtMS44LS4xLTEuOC0xVjM4LjhjMC0uOSAxLTEuNSAxLjgtMXoiLz48L3N2Zz4="'; - } - - #fonts - foreach ($this->cssfont as $hash => $item) { - $res[] = '@font-face{font-family: "' . $hash . '";src:url("../../data/fonts/' . $hash . '.woff") format("woff");}'; - } - - if ($this->fluidbookSettings->textPopupStylesheet) { - $res[] = file_get_contents($this->wdir . '/' . $this->fluidbookSettings->textPopupStylesheet); - } - $this->log('CSS 13'); - $this->_writeLess($this->lessVariables, $lessContents); - $this->stylesheets[] = 'data/style/style.css'; - $this->vdir->file_put_contents('data/style/style.css', implode("\n", $res)); - $this->log('Write CSS'); - } - - protected function _writeLess($variables, $lessContents = '') - { - if ($this->widget) { - $this->lessFiles[] = 'widget'; - } - foreach ($this->specialCSS as $s) { - $this->lessFiles[] = 'special/' . $s; - } - - $tmp = Files::tmpdir(); - - $from = $this->assets . '/style/*'; - `cp -r $from $tmp`; - - $bookVariables = array(); - foreach ($variables as $k => $v) { - $bookVariables[] = '@' . trim($k) . ':' . $v . ';'; - } - file_put_contents($tmp . '/book-variables.less', implode("\n", $bookVariables)); - file_put_contents($tmp . '/additional.less', $lessContents); - - foreach ($this->lessFiles as $f) { - $source_less = $this->assets . '/style/' . $f . '.less'; - $destination_less = $tmp . '/' . $f . '.less'; - $destination_css = $tmp . '/' . $f . '.css'; - - if (!file_exists($source_less)) { - die($source_less); - continue; - } - - $dir = dirname($destination_css); - - if (file_exists($dir) && !is_dir($dir)) { - unlink($dir); - } - // LESS file might be in a subfolder, so create if it doesn't exist - if (!file_exists($dir)) { - mkdir($dir, 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); - $less = new CommandLine('lessc'); - $less->setArg(null, $destination_less); - $less->setArg(null, $destination_css); - $less->execute(); - if (!file_exists($destination_css)) { - die($less->output); - continue; - } - $this->vdir->copy($destination_css, 'style/' . $f . '.css'); - if ($f != 'widget') { - $this->stylesheets[] = 'style/' . $f . '.css'; - } - } - } - - protected function _cssBackground() - { - $body = '#background, #splash {'; - - switch ($this->themeSettings->repeat) { - case FluidbookTheme::REPEAT: - $body .= 'background-repeat:repeat;'; - break; - case FluidbookTheme::NONE: - $body .= 'background-repeat:no-repeat;'; - break; - case FluidbookTheme::RATIO: - $body .= 'background-repeat:no-repeat;'; - $body .= 'background-size:cover;'; - break; - case FluidbookTheme::STRETCH: - $body .= 'background-repeat:no-repeat;'; - $body .= 'background-size:100% 100%;'; - break; - } - - if ($backgroundImage = $this->themeAsset('backgroundImage')) { - - $dbi = Image::getimagesize($backgroundImage->getPathname()); - $this->config->backgroundImageDimensions = array('width' => $dbi[0], 'height' => $dbi[1]); - - - $this->vdir->copy($backgroundImage->getPathname(), 'data/images/' . $backgroundImage->getFilename()); - $body .= 'background-image:url(../images/' . $backgroundImage->getFilename() . ');'; - $body .= 'background-position:'; - - switch ($this->themeSettings->backgroundVAlign) { - case FluidbookTheme::TOP: - $body .= 'top'; - break; - case FluidbookTheme::MIDDLE: - $body .= 'center'; - break; - case FluidbookTheme::BOTTOM: - $body .= 'bottom'; - break; - } - - $body .= ' '; - - switch ($this->themeSettings->backgroundHAlign) { - case FluidbookTheme::LEFT: - $body .= 'left'; - break; - case FluidbookTheme::CENTER: - $body .= 'center'; - break; - case FluidbookTheme::RIGHT: - $body .= 'right'; - break; - } - $body .= ';'; - } - - $body .= '}'; - - - if ($this->_themeBoolean($this->themeSettings->displayBackgroundDuringLoading)) { - $body .= '#background, #splash { - background-color:' . Color::colorToCSS($this->themeSettings->backgroundColor) . ' !important; - }'; - } else { - $body .= '#background { - visibility: hidden; - opacity: 0; - background-color:' . Color::colorToCSS($this->themeSettings->backgroundColor) . ' !important; - }'; - - $body .= '#splash { - background-color:' . Color::colorToCSS($this->themeSettings->loadingBackColor) . ' !important; - background-image: none; - }'; - } - - return $body; - } - - public static function writeCSSUA($property, $value) - { - $res = array(); - foreach (self::$uaPrefixes as $prefix) { - $res[] = $prefix . $property . ':' . $value; - } - return implode(';', $res); - } - - protected function base62($val) - { - $chars = '0123456789abcdefghijklmnopqrstuvwxyz'; - $base = strlen($chars); - $str = ''; - do { - $i = $val % $base; - $str = $chars[$i] . $str; - $val = ($val - $i) / $base; - } while ($val > 0); - return $str; - } - - public function copyLinkDir($source, $dest) - { - $this->vdir->copyDirectory($source, $dest); - } - - public function simpleCopyLinkFile($source, $dest) - { - if (stripos($source, '.svg') !== false) { - $source = $this->_fixSVG($source); - } - - $this->vdir->copy($source, $dest); - } - - protected function _fixSVG($source) - { - $fixed = str_replace('.svg', '.f.svg', $source); - if (file_exists($fixed) && filemtime($fixed) >= filemtime($source)) { - return $fixed; - } - if (file_exists($fixed) && is_link($fixed)) { - unlink($fixed); - } - $svg = simplexml_load_string(file_get_contents($source)); - $attr = $svg->attributes(); - if (isset($attr['width'], $attr['height'])) { - copy($source, $fixed); - return $fixed; - } - - $dim = Image::getimagesize($source); - $svg->addAttribute('preserveAspectRatio', 'none'); - $svg->addAttribute('width', $dim[0]); - $svg->addAttribute('height', $dim[1]); - file_put_contents($fixed, $svg->asXML()); - - return $fixed; - } - - public function addVideoJs() - { - $locale = $this->getFluidbook()->lang; - $map = ['pt' => 'pt-PT', 'pt-br' => 'pt-BR', 'zh' => 'zh-CN', 'es-pr' => 'es']; - if (isset($map[$locale])) { - $locale = $map[$locale]; - } - - $this->addJsLib('videojs', ['js/libs/videojs/video.min.js', 'js/libs/videojs/lang/' . $locale . '.js']); - $this->addLess('videojs/videojs'); - } - - public function addParallax() - { - $this->addJsLib('parallax', ['js/libs/fluidbook/fluidbook.parallax.js']); - } - - public function addLottie($animationData, $params, $hash) - { - if (isset($this->_lottieIDByHash[$hash])) { - return $this->_lottieIDByHash[$hash]; - } - - $this->addJsLib('lottie', 'js/libs/lottie.min.js'); - - if (!isset($this->config->lottieAnimations)) { - $this->config->lottieAnimations = []; - } - - $id = count($this->config->lottieAnimations); - $this->config->lottieAnimations[] = [$params, $animationData]; - $this->_lottieIDByHash[$hash] = $id; - return $id; - } - - public function addFont($fontFile) - { - $f = $this->wdir . '/' . $fontFile; - $e = explode('.', $f); - $ext = array_pop($e); - $hash = 'fb_' . substr(md5($fontFile), 0, 10); - if (!isset($this->cssfont[$hash])) { - $final = $hash . '.woff'; - $dest = $this->wdir . '/' . $final; - if (!file_exists($dest) || filemtime($dest) < filemtime($f)) { - $script = resource_path('tools/fonts/convertrn.pe'); - if (!is_executable($script)) { - chmod($script, 755); - } - $fontforge = new CommandLine('fontforge'); - $fontforge->setArg('-script', $script); - $fontforge->setArg(null, $f); - $fontforge->setArg(null, $dest); - $fontforge->execute(); - //$fontforge->debug(); - } - $this->vdir->copy($dest, 'data/fonts/' . $hash . '.woff'); - $fontline = new CommandLine('font-line'); - $fontline->setArg(null, 'report'); - $fontline->setArg(null, $f); - $fontline->execute(); - //$fontline->debug(); - $report = explode("\n", $fontline->getOutput()); - - foreach ($report as $item) { - $item = trim($item); - if (!stristr($item, ':')) { - continue; - } - list($k, $v) = explode(':', $item, 2); - $v = trim($v); - if ($k == '[head] Units per Em') { - $fontHeight = $v; - } - if ($k == '[OS/2] CapHeight') { - $fontCapHeight = $v; - } - if ($k == '[OS/2] TypoAscender') { - $ascender = abs($v); - } - if ($k == '[OS/2] TypoDescender') { - $descender = abs($v); - } - } - $capHeight = 1; - if (isset($fontCapHeight) && isset($fontHeight)) { - $capHeight = $fontCapHeight / $fontHeight; - } - $font = ['family' => $hash, 'capHeight' => $capHeight, 'ascender' => $ascender / $fontHeight, 'descender' => $descender / $fontHeight]; - $this->cssfont[$hash] = $font; - } - return $this->cssfont[$hash]; - } - - public function addJsLib($name, $files) - { - if (!isset($this->jsLibs[$name])) { - $this->jsLibs[$name] = []; - } - if (!is_array($files)) { - $files = [$files]; - } - $diff = array_diff($files, $this->jsLibs[$name]); - if (count($diff)) { - $this->jsLibs[$name] = array_merge($this->jsLibs[$name], $diff); - } - } - - public static function encodeWebVideos($file, $dir = null, $async = true, $force = false, $format = 'all') - { - $file = new SplFileInfo($file); - if (is_null($dir)) { - $dir = $file->getPath(); - } - - $videos = array('mp4', 'jpg'); - - if (is_string($format)) { - if ($format == 'none') { - $format = array(); - } elseif ($format == 'all') { - $format = $videos; - } else { - $format = array($format); - } - } - - if (!$force) { - $format = array(); - } - - - $base = $dir . '/' . $file->getBasename('.' . $file->getExtension()); - $log = $base . '.log'; - - foreach ($videos as $v) { - $vfile = $base . '.' . $v; - if (!file_exists($vfile)) { - $force = true; - } else if (filemtime($file) > filemtime($vfile) || in_array($v, $format)) { - $force = true; - unlink($vfile); - } - } - - if (!$force && file_exists($log) && filemtime($log) > filemtime($file)) { - return; - } - - $webvideo = new CommandLine('/application/scripts/webvideo', $log); - $webvideo->setArg(null, $file); - $webvideo->setArg(null, $dir); - $webvideo->execute(); - } - - - public function copyLinkFile($source, $dest, $video = false) - { - if ($video && $this->fluidbookSettings->mobileVideosPath != '') { - - } - $origDir = $this->wdir; - $types = $this->getVideosFormats(); - if ($video) { - self::encodeWebVideos($origDir . $source, null, true); - $e = explode('.', $source); - array_pop($e); - $base = implode('.', $e); - $source = array(); - foreach ($types as $type) { - $source[] = $base . '.' . $type; - } - } - - if (!is_array($source)) { - $source = array($source); - } - - foreach ($source as $so) { - $s = $origDir . $so; - if (file_exists($s)) { - $d = $dest . '/' . $so; - $this->simpleCopyLinkFile($s, $d, false); - } - } - } - - public function __destruct() - { - - } - - public function unzipFile($file, $moveAssets = false, $baseDir = null, $junkPaths = false) - { - $fdir = is_null($baseDir) ? 'data/links/' . str_replace('.', '_', $file) : $baseDir; - - $zipPath = $this->wdir . '/' . $file; - $dir = protected_path('fluidbookpublication/cache/unzip') . '/' . Files::hashFileAttributes($zipPath) . '_' . ($moveAssets ? '1' : '0') . '_' . ($junkPaths ? '1' : '0'); - - if (!file_exists($dir)) { - mkdir($dir, 0777, true); - Zip::extract($zipPath, $dir, $junkPaths); - if ($moveAssets) { - `mv $dir/Assets/* $dir`; - rmdir($dir . '/Assets'); - } - } - - return array('dir' => $dir, 'fdir' => $fdir); - } - - public function getConfigZIP($d) - { - $res = array('type' => 'zip', 'width' => 0, 'height' => 0); - if (file_exists($d . '/index.html')) { - $doc = new DOMDocument(); - @$doc->loadHTMLFile($d . '/index.html'); - $xpath = new DOMXPath($doc); - $c = $xpath->query("//canvas"); - foreach ($c as $canvas) { - /* @var $canvas DOMElement */ - $res['width'] = intval((string)$canvas->getAttribute('width')); - $res['height'] = intval((string)$canvas->getAttribute('height')); - } - - $m = $xpath->query('//meta[@name="width"]'); - foreach ($m as $meta) { - $res['width'] = intval((string)$meta->getAttribute('content')); - } - - $m = $xpath->query('//meta[@name="height"]'); - foreach ($m as $meta) { - $res['height'] = intval((string)$meta->getAttribute('content')); - } - - $r = array('html' => 'index.html', 'inject' => array(), 'injectcss' => array(), 'injectjs' => array()); - } else { - $r = array('html' => false, 'inject' => array(file_get_contents($d . '/init.js')), 'injectcss' => array('multimedia.css'), 'injectjs' => array('multimedia.js')); - } - return array_merge($res, $r); - } - - public function addFontKit($font) - { - if ($font === 'sans-serif') { - return; - } - if ($font === 'Open Sans') { - $font = 'OpenSans'; - } - - $path = 'style/fonts/' . $font; - $css = $path . '/font.css'; - if (in_array($css, $this->stylesheets)) { - return; - } - $this->stylesheets[] = $css; - $this->vdir->copyDirectory($this->assets . '/' . $path, $path); - return $path . '/font.css'; - } - - - public function SimpleXMLElement_innerXML($xml) - { - $innerXML = ''; - foreach (dom_import_simplexml($xml)->childNodes as $child) { - $innerXML .= $child->ownerDocument->saveXML($child); - } - return $innerXML; - } - - public function writeXMLArticles() - { - $f = $this->fluidbookSettings->articlesFile; - - $this->lessVariables['articles-title-color'] = '#000000'; - $this->lessVariables['articles-font'] = 'Open Sans'; - - if (!$f || !file_exists($this->wdir . '/' . $f) || !is_file($this->wdir . '/' . $f)) { - return; - } - $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); - - $list = $this->config->articlesList ?? []; - - - $this->lessVariables['articles-title-color'] = '#565657'; - - - $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'; - } - - $specificStyles = '## h3, ## figure figcaption{background-color:' . $color . '}'; - $specificStyles .= '## .chapo, ## blockquote, ## a{color:' . $color . ';}'; - - $inner = '
'; - $inner .= '
'; - if ($this->fluidbookSettings->articlesShare && $this->fluidbookSettings->share) { - $inner .= ''; - } - $inner .= ''; - $inner .= '
'; - - $inner .= '
'; - - $title = ''; - $lead = ''; - $image = ''; - - $first = true; - - foreach ($a->children() as $child) { - if ($first) { - $first = false; - if ($child->getName() !== 'category') { - $inner .= '

 

'; - } - } - $inner .= $this->_articleToHTML($child, $title, $lead, $image, $dir); - } - $inner .= '
'; - - if (!$title) { - $title = 'Article sans titre ' . $k; - } - - if (!$id) { - $id = Text::str2URL($title); - } - - if (!$url) { - $url = $id . '.html'; - } - - $inner = str_replace(array('$id', '$url'), array($id, $url), $inner); - - $article = ['id' => $id, - 'url' => $url, - 'color' => $color, - 'contents' => '', - 'type' => 'xml']; - - $article['contents'] = $inner; - $content = ''; - $content .= ''; - $content .= ''; - $content .= ''; - $content .= ''; - $content .= ''; - $content .= $svg; - $content .= $inner; - $content .= ''; - $article['print'] = $content; - $list[] = $article; - - $this->addSEOArticle('#/article/' . $article['url'], $title, $lead, $image, $article['id'], $article['url'], $inner); - } - - if (isset($list)) { - $this->config->articlesList = $list; - } - } - - public function findArticleById($id) - { - foreach ($this->config->articlesList as $item) { - if ($item['id'] === $id) { - return $item; - } - } - return null; - } - - public function updateArticleById($id, $article) - { - foreach ($this->config->articlesList as $k => $item) { - if ($item['id'] === $id) { - $this->config->articlesList[$k] = $article; - break; - } - } - } - - public function writeArticles() - { - $list = $this->config->articlesList ?? []; - - $nb = count($list); - - usort($list, function ($a, $b) { - if ($a['page'] == $b['page']) { - $ea = explode('-', $a['id']); - $eb = explode('-', $b['id']); - if (is_numeric($ea[0]) && is_numeric($eb[0])) { - return $ea[0] - $eb[0]; - } - return strcmp($a['id'], $b['id']); - } - return $a['page'] - $b['page']; - }); - - foreach ($list as $k => $item) { - $nextIndex = ($k + 1) % $nb; - $prevIndex = ($k - 1 + $nb) % $nb; - $list[$k]['prev'] = $list[$prevIndex]['url']; - $list[$k]['next'] = $list[$nextIndex]['url']; - } - - - $idlist = []; - foreach ($list as $item) { - $idlist[$item['id']] = $item; - } - - $this->config->articlesList = $idlist; - } - - /** - * @param $child SimpleXMLElement - * @param $title - * @param $lead - * @param $image - * @return string|void - */ - protected function _articleToHTML($child, &$title, &$lead, &$image, $dir = null) - { - $markupMap = ['category' => 'h3', - 'subtitle' => 'h2', - 'legend' => 'figcaption', - 'title' => 'h1', - 'lead' => 'div.chapo', - 'paragraph' => 'p', - 'note' => 'div.note', - 'quote' => 'blockquote', - 'signature' => 'div.author', - 'intertitle' => 'h2.inter', - 'bigfont' => 'h2.bigfont', - 'separator' => 'hr', - 'link' => 'a']; - - $attrsmap = ['a' => ['link' => 'href']]; - - $dirattr = ''; - if (isset($child['dir'])) { - $d = (string)$child['dir']; - if ($d !== $dir) { - $dirattr = ' dir="' . $d . '"'; - $dir = $d; - } - } - - $res = ''; - $tag = $child->getName(); - if ($tag === 'encadre') { - $res .= ''; - foreach ($child->children() as $sub) { - $res .= $this->_articleToHTML($sub, $a1, $a2, $a3, $dir); - } - $res .= ''; - } else if ($tag === 'youtube') { - $res .= '
'; - } else if ($tag === 'image') { - $srcattrs = ['href', 'src', 'file']; - $file = ''; - foreach ($srcattrs as $srcattr) { - if (isset($child[$srcattr])) { - $file = (string)$child[$srcattr]; - break; - } - } - if ($image === '') { - $image = 'articles/' . $file; - } - $filepath = $this->wdir . '/articles/' . $file; - $this->vdir->copy($filepath, 'data/articles/' . $file); - $legend = (string)$child; - $caption = $legend ? '
' . $legend . '
' : ''; - if (file_exists($filepath)) { - $dim = getimagesize($filepath); - } else { - $dim = [0 => 1024, 1 => 10]; - } - $res .= '' . $legend . '' . $caption . ''; - } else { - $c = trim($this->SimpleXMLElement_innerXML($child)); - if (!$c) { - return; - } - if ($title === '' && $tag === 'title') { - $title = $c; - } - if ($lead === '' && $tag === 'lead') { - $lead = $c; - } - $m = $markupMap[$tag] ?? $tag; - $e = explode('.', $m); - $markup = $e[0]; - $attrs = $dirattr; - if (count($e) === 2) { - $attrs .= ' class="' . $e[1] . '"'; - } - if ($m === 'a') { - $attrs .= ' target="_blank"'; - } - foreach ($child->attributes() as $name => $v) { - $n = $attrsmap[$m][$name] ?? $name; - $attrs .= ' ' . $n . '="' . htmlspecialchars($v) . '"'; - } - $res .= '<' . $markup . $attrs . '>' . $c . ''; - } - return $res; - } - - public static function getPhonegapVersion($v = 'latest') - { - if ($v != 'latest') { - return $v; - } - - $versions = self::getPhonegapVersions(); - return array_pop($versions); - } - - public static function getPhonegapVersions() - { - $versions = array(); - $phonegap_dir = resource_path('fluidbookpublication/phonegap'); - - if (is_dir($phonegap_dir)) { - $dr = opendir($phonegap_dir); - while ($file = readdir($dr)) { - if ($file == '.' || $file == '..' || $file == 'plugins') { - continue; - } - $versions[] = $file; - } - usort($versions, 'version_compare'); - } - - return $versions; - } - - public static function getSourcesPath($version, $dir = null) - { - $res = self::getFluidbookPlayerBaseDirectory(); - if (null !== $dir) { - $res .= $dir . '/'; - } - if ($version === 'stable') { - $res .= 'branches/master'; - } else if ($version === 'dev') { - $res .= 'local/master'; - } else { - list($branch, $location) = explode('|', $version); - $res .= ($location === 'git' ? 'branches' : $location) . '/' . $branch; - } - return $res; - } - - public static function getCompiledSourcesPath($version) - { - return self::getSourcesPath($version, 'compiled'); - } - - public function source_path($path = ''): string - { - $res = $this->assets; - if ($path) { - $res .= '/' . $path; - } - return $res; - } - - public function page_path($page, $path = ''): string - { - return ''; - } - - public function getPagePDFSource($page): string - { - return $this->getFluidbook()->getPDFSplitSource($page); - } - - public function getWidthForLinks() - { - return $this->getWidth() / $this->getLinkScale(); - } - - public function getHeightForLinks() - { - return $this->getHeight() / $this->getLinkScale(); - } -} diff --git a/app/Fluidbook/Compiler/Cart.php b/app/Fluidbook/Compiler/Cart.php new file mode 100644 index 000000000..17cbef8e5 --- /dev/null +++ b/app/Fluidbook/Compiler/Cart.php @@ -0,0 +1,574 @@ +lessVariables['import-cart-styles'] = 'grandvision'; + + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('grandvision', 'js/libs/fluidbook/cart/fluidbook.cart.grandvision.js'); + $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); + $this->addJsLib('multiselect', 'js/libs/jquery/jquery.multi-select.js'); + $this->addJsLib('jqueryui', 'js/libs/jquery/jquery-ui.min.js'); + $this->addJsLib('exceljs', 'js/libs/exceljs.min.js'); + $this->svgfiles[] = $this->assets . '/images/symbols/grandvision.svg'; + + $cdir = $this->wdir . '/commerce/'; + $file = $cdir . $this->fluidbookSettings->basketReferences; + $refs = ExcelToArray::excelToArrayKeyVars($file, 'Excel2007', true); + $this->config->basketReferences = []; + foreach ($refs as $ean => $ref) { + $this->config->basketReferences[$ean] = $ref; + $this->config->basketReferences[$ean]['angle_url'] = base64_encode(file_get_contents($this->wdir . '/commerce/opt/' . $ean . '-angle.jpg')); + } + + $odir = $cdir . '/opt/'; + if (!file_exists($odir)) { + mkdir($odir, 0777, true); + } + + $it = Files::getDirectoryIterator($cdir); + $exts = ['png', 'jpg', 'tif', 'mp4']; + foreach ($it as $file) { + + /** @var $file SplFileInfo */ + if ($file->isDir()) { + continue; + } + $ext = $file->getExtension(); + if (!in_array($ext, $exts)) { + continue; + } + + $e = Text::multiExplode('_-.', mb_strtolower($file->getFilename())); + $ean = $this->findEAN($e); + if (!$ean) { + continue; + } + if (!isset($this->config->basketReferences[$ean])) { + continue; + } + $f = $file->getPathname(); + + if ($ext === 'mp4') { + $n = $ean . '-360.mp4'; + $this->config->basketReferences[$ean]['360'] = true; + $opt = $odir . '/' . $n; + if (!file_exists($opt) || !filesize($opt) || filemtime($opt) < filemtime($f)) { + // Optimize original video + `ffmpeg -i $f -filter:v scale=360:-2 -vcodec libx264 -an $opt`; + touch($opt, filemtime($f)); + } + } else { + if (in_array('front', $e)) { + $type = 'front'; + } else if (in_array('angle', $e)) { + $type = 'angle'; + } else { + continue; + } + + $n = $ean . '-' . $type . '.jpg'; + $this->config->basketReferences[$ean][$type] = true; + $opt = $odir . '/' . $n; + if (!file_exists($opt) || !filesize($opt) || filemtime($opt) < filemtime($f)) { + // Optimize original image + $convert = new Resizer(); + $convert->loadImage($f); + $convert->resize(1080, null, 'ratio', false, 'C', 'M', 'white'); + $convert->output('jpg', $opt, 75); + touch($opt, filemtime($f)); + } + } + $this->vdir->copy($opt, 'data/commerce/' . $n); + } + } + + public function findEAN($array) + { + foreach ($array as $item) { + if (strlen($item) === 13 && preg_match('/^\d{13}$/', $item)) { + return $item; + } + } + return false; + } + + public function writeFlexipanCart() + { + $this->lessVariables['import-cart-styles'] = 'flexipan'; + + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('flexipan', 'js/libs/fluidbook/cart/fluidbook.cart.flexipan.js'); + $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); + + $cdir = $this->wdir . '/commerce/'; + + + $file = $cdir . $this->fluidbookSettings->basketReferences; + $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); + + $this->getLinksAndRulers($links, $rulers); + + foreach ($links as $link) { + if ($link['type'] == '12') { + + } + } + + $this->config->product_zoom_references = []; + foreach ($this->config->basketReferences as $ref => $data) { + $this->config->product_zoom_references[$ref] = [$ref]; + } + } + + + + public function writeMIFCart() + { + $this->lessVariables['import-cart-styles'] = 'mif'; + + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('mif', 'js/libs/fluidbook/cart/fluidbook.cart.mif.js'); + $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); + + $cdir = $this->wdir . '/commerce/'; + $odir = $cdir . '/opt/'; + if (!file_exists($odir)) { + mkdir($odir, 0777, true); + } + + $file = $cdir . $this->fluidbookSettings->basketReferences; + $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); + + $this->getLinksAndRulers($links, $rulers); + + foreach ($this->config->basketReferences as $ref => $data) { + $source = $cdir . '/' . $data['Image']; + if (!file_exists($source)) { + continue; + } + $d = Text::str2URL($ref) . '.jpg'; + $dest = $odir . '/' . $d; + if (!file_exists($dest) || !filesize($dest) || filemtime($dest) < filemtime($source)) { + $convert = new Resizer(); + $convert->loadImage($source); + $convert->resize(500, 500, 'ratio', false, 'C', 'M', 'ffffff'); + $convert->output('jpg', $dest, 80); + } + $vdest = 'data/commerce/opt/' . $d; + $this->vdir->copy($dest, $vdest); + $this->config->basketReferences[$ref]['Image'] = $vdest; + } + + foreach ($links as $link) { + if ($link['type'] == '12') { + + } + } + +// $this->config->product_zoom_references = []; +// foreach ($this->config->basketReferences as $ref => $data) { +// $r = [$data['Lien']]; +// $this->config->product_zoom_references[$ref] = $r; +// } + } + + public function writeJoueClub2021Cart() + { + $this->lessVariables['import-cart-styles'] = 'joueclub2021'; + $extra = Link::parseExtras($this->fluidbookSettings->cartExtraSettings, true); + + /** + * buttonColor=#d7b646 + * buttonTextColor=#ffffff + * headerBackgroundColor=#0e1a3c + * headerTextColor=#ffffff + */ + $this->lessVariables['cart-button-color'] = $extra['buttoncolor'] ?? '#e30613'; + $this->lessVariables['cart-button-text-color'] = $extra['buttontextcolor'] ?? '#ffffff'; + $this->lessVariables['cart-button-radius'] = $extra['buttonradius'] ?? '50%'; + $this->lessVariables['cart-header-background-color'] = $extra['headerbackgroundcolor'] ?? '#26348b'; + $this->lessVariables['cart-header-text-color'] = $extra['headertextcolor'] ?? '#ffffff'; + $this->lessVariables['cart-close-color'] = $extra['closecolor'] ?? '#ffffff'; + $this->lessVariables['cart-close-background-color'] = $extra['closebackgroundcolor'] ?? '#e30613'; + $this->lessVariables['cart-close-radius'] = $extra['closeradius'] ?? '50%'; + $this->lessVariables['cart-actions-radius'] = $extra['actionsradius'] ?? '8px'; + $this->lessVariables['cart-actions-background-color'] = $extra['actionsbackgroundcolor'] ?? '#26348b'; + $this->lessVariables['cart-actions-text-color'] = $extra['actionstextcolor'] ?? '#ffffff'; + $this->lessVariables['cart-scrollbar-color'] = $extra['scrollbarcolor'] ?? '#26348b'; + + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('joueclub2021', 'js/libs/fluidbook/cart/fluidbook.cart.joueclub2021.js'); + $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); + + $cdir = $this->wdir . '/commerce/'; + + $file = $cdir . $this->fluidbookSettings->basketReferences; + $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); + + foreach ($this->config->basketReferences as $ref => $data) { + $dest = $cdir . $ref . '.jpg'; + if (!file_exists($dest)) { + copy($data['img'], $dest); + } + $this->vdir->copy($dest, 'data/commerce/' . $ref . '.jpg'); + } + $addFiles = [$this->config->cartHeaderImage, $this->config->cartHeaderMobileImage]; + foreach ($addFiles as $f) { + if (!$f) { + return; + } + + $this->vdir->copy($cdir . $f, 'data/commerce/' . $f); + } + + $this->getLinksAndRulers($links, $rulers); + } + + public function writeGrandPavoisCart() + { + $this->lessVariables['import-cart-styles'] = 'grandpavois'; + + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('grandpavois', 'js/libs/fluidbook/cart/fluidbook.cart.grandpavois.js'); + $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); + + $cdir = $this->wdir . '/commerce/'; + $odir = $cdir . '/opt/'; + if (!file_exists($odir)) { + mkdir($odir, 0777, true); + } + + $file = $cdir . $this->fluidbookSettings->basketReferences; + $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($file); + + $this->getLinksAndRulers($links, $rulers); + } + + + public function writePumaCart() + { + $this->lessVariables['import-cart-styles'] = 'puma'; + + $this->addJsLib('parsley', 'js/libs/parsley.min.js'); + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('puma', 'js/libs/fluidbook/cart/fluidbook.cart.puma.js'); + $this->addJsLib('html2pdf', 'js/libs/html2pdf/html2pdf.min.js'); + $this->addJsLib('exceljs', 'js/libs/exceljs.min.js'); + $this->addVideoJs(); + + $this->config->basketReferences = ExcelToArray::excelToArrayKeyVars($this->wdir . 'commerce/' . $this->fluidbookSettings->basketReferences); + $eanFile = $this->wdir . 'commerce/ean.xlsx'; + if (file_exists($eanFile)) { + $this->config->eanReferences = ExcelToArray::excelToArrayIndexKeyVars($eanFile); + } + + $this->getLinksAndRulers($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'; + $this->config->basketReferences[$link['to']]['zoom_url'] = base64_encode(file_get_contents($this->dir . '/data/links/zoom_' . $link['uid'] . '.jpg')); + $this->config->basketReferences[$link['to']]['zoom_image_ratio'] = $link['width'] / $link['height']; + } + } + + $this->config->product_zoom_references = []; + $files = ['360°', 'Image supplémentaire', 'Fiche technique']; + foreach ($this->config->basketReferences as $ref => $data) { + $r = []; + foreach ($files as $file) { + if (!isset($data[$file])) { + $data[$file] = ''; + } + $fname = trim($data[$file]); + if ($fname !== '') { + $fname = str_replace(' ', '-', $fname); + $wfile = $this->wdir . 'commerce/' . $fname; + if (file_exists($wfile)) { + $fname = 'data/commerce/' . $fname; + $this->vdir->copy($wfile, $fname); + } else { + $fname = ''; + } + } + $r[] = $fname; + } + $this->config->product_zoom_references[$ref] = $r; + } + } + + + public function writeThirietCart() + { + $this->config->cartLinkAppearance = 'overlay'; + $this->svgfiles[] = $this->assets . '/images/symbols/cart-overlay.svg'; + $this->addJsLib('thiriet', 'js/libs/fluidbook/cart/fluidbook.cart.thiriet.js'); + } + + public function writeCFOCCart() + { + + $this->lessVariables['import-cart-styles'] = 'cfoc'; + + $this->addJsLib('cfoc', 'js/libs/fluidbook/cart/fluidbook.cart.cfoc.js'); + + if (!empty($this->config->basketReferences) && is_string($this->config->basketReferences)) { + if (file_exists($this->config->basketReferences) || Url::isDistant($this->config->basketReferences)) { + $referencesFile = $this->config->basketReferences; + } else { + $referencesFile = $this->wdir . 'commerce/' . $this->config->basketReferences; + } + } + + $references = []; + + if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { + $rows = ExcelToArray::excelToArrayFirstSheet($referencesFile); + + + // Expected headings are: EXCLU, LIGNE, EAN, REF, DESIGNATION, COULEUR, QTE MINI, PRIX TTC + $column_headings = array_shift($rows); // We assume the first row will be the headings, so we slice it off + $column_headings = array_map(function ($heading) { // Clean the headings a bit + return trim(strtoupper($heading)); + }, $column_headings); + + foreach ($rows as $row) { + + // First, trim values in case there are any stray spaces + $row = array_map('trim', $row); + + // Next, set the headings as keys to make it easier to refer to the row values by name + $row = array_combine($column_headings, $row); + + // For the 'EXCLU' field, this should be converted to a boolean + $row['EXCLU'] = ('exclu boutique' === $row['EXCLU']); + + // Make sure the PRIX TTC field doesn't have any stray commas or spaces in the numbers + // because this will cause unexpected problems for the calculations + $row['PRIX TTC'] = str_replace([',', ' '], '', $row['PRIX TTC']); + + // The EAN and REF are required, so if they don't exist, we can assume it's not a valid row + if (empty($row['EAN']) || empty($row['REF'])) { + continue; + } + + $references[$row['REF']][$row['EAN']] = $row; + } + + } + + $this->config->basketReferences = $references; + + // It's possible to use the cartExtraSettings field in the parameters to define publication specific settings, + // such as the subject line used in the e-mail that is sent from the cart validation + $extra = Link::parseExtras($this->fluidbookSettings->cartExtraSettings, true); + + $this->config->cartEmailSubject = $extra['email_subject'] ?? 'Récapitulatif de votre commande CFOC'; + } + + /** + * @throws \Exception + */ + public function writeBastideCart() + { + + $this->lessVariables['import-cart-styles'] = 'bastide'; + + $this->addJsLib('bastide', 'js/libs/fluidbook/cart/fluidbook.cart.bastide.js'); + + + if (!empty($this->config->basketReferences)) { + if (file_exists($this->config->basketReferences) || Url::isDistant($this->config->basketReferences)) { + $referencesFile = $this->config->basketReferences; + } else { + $referencesFile = $this->wdir . 'commerce/' . $this->config->basketReferences; + } + } + + $references = []; + + if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { + $rows = ExcelToArray::excelToArrayFirstSheet($referencesFile); + + // Expected headings are: n° page, Chapitre, Article Code, Article, Conditionnement + $column_headings = array_shift($rows); // We assume the first row will be the headings, so we slice it off + $column_headings = array_map(function ($heading) { // Normalise the headings, removing extra spaces and line breaks + return trim(strtoupper(preg_replace('/\s+/', ' ', $heading))); + }, $column_headings); + + foreach ($rows as $row) { + + // First, trim values in case there are any stray spaces + $row = array_map('trim', $row); + + // Next, set the headings as keys to make it easier to refer to the row values by name + $row = array_combine($column_headings, $row); + + // The ARTICLE CODE is required, so if it doesn't exist, we can assume it's not a valid row + if (empty($row['ARTICLE CODE'])) { + continue; + } + + $references[$row['ARTICLE CODE']] = $row; + } + + } + + $this->config->basketReferences = $references; + + // Allow individual Fluidbooks to override the columns shown in the cart + $extra = Link::parseExtras($this->config->cartExtraSettings, true); + + if (!empty($extra['cart_columns'])) { + // In the "Paramètres panier" field (cartExtraSettings), the cart columns can be defined in this format: + // cart_columns=XLS COL NAME|Display name,XLS COL 2|Display name 2 + // This setting needs to be trimmed and converted into an associative array with column_name => display_name + // Split by commas, then by pipes | + $columns = array_map(function ($heading) { + return explode('|', $heading); + }, explode(',', $extra['cart_columns'])); + $processed_columns = []; + foreach ($columns as $column) { + $processed_columns[strtoupper(trim($column[0]))] = trim($column[1] ?? ''); + } + + // Ensure that special QUANTITY and DELETE columns are present (see getColumns() in fluidbook.cart.bastide.js) + $processed_columns['QUANTITY'] = $processed_columns['QUANTITY'] ?? 'Quantité'; + $processed_columns['DELETE'] = ''; + + $this->config->cartColumns = $processed_columns; + } + } + + public function writeCartConfig() + { + if ($this->fluidbookSettings->cartLinkAppearance == 'overlay') { + $this->svgfiles[] = $this->assets . '/images/symbols/cart-overlay.svg'; + } + + if ($this->config->basket) { + $this->addJsLib('cart', 'js/libs/fluidbook/fluidbook.cart.js'); + switch ($this->config->basketManager) { + case 'Thiriet': + $this->writeThirietCart(); + return; + case 'Flexipan': + $this->writeFlexipanCart(); + return; + case 'Puma': + $this->writePumaCart(); + return; + case 'MIF': + $this->writeMIFCart(); + return; + case 'GrandVision': + $this->writeGrandVisionCart(); + return; + case 'GrandPavois': + $this->writeGrandPavoisCart(); + return; + case 'JoueclubWishlist2021': + $this->writeJoueClub2021Cart(); + return; + case 'Remarkable': + $this->addJsLib('parsley', 'js/libs/parsley.min.js'); + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('remarkable', 'js/libs/fluidbook/cart/fluidbook.cart.remarkable.js'); + break; + case 'Mopec': + $this->addJsLib('parsley', 'js/libs/parsley.min.js'); + $this->addJsLib('cookie', 'js/libs/jquery/jquery.cookie.js'); + $this->addJsLib('mopec', 'js/libs/fluidbook/cart/fluidbook.cart.mopec.js'); + break; + case 'CFOC': + $this->writeCFOCCart(); + break; + case 'Bastide': + $this->writeBastideCart(); + break; + default: + break; + } + } + if (!$this->config->product_zoom_references && $this->config->basketReferences && $this->config->basketManager == "ZoomProductLink") { + $this->config->product_zoom_references = $this->config->basketReferences; + $this->config->basketReferences = ''; + } + + if ($this->config->product_zoom_references) { + if (file_exists($this->config->product_zoom_references) || Url::isDistant($this->config->product_zoom_references)) { + $referencesFile = $this->config->product_zoom_references; + } else { + $referencesFile = $this->wdir . '/commerce/' . $this->config->product_zoom_references; + } + if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { + $this->config->product_zoom_references = ExcelToArray::excelToArrayKeyValMulti($referencesFile, 'Excel2007', true); + } + } + + if ($this->config->basketReferences && is_string($this->config->basketReferences)) { + if (file_exists($this->config->basketReferences) || Url::isDistant($this->config->basketReferences)) { + $referencesFile = $this->config->basketReferences; + } else { + $referencesFile = $this->wdir . '/commerce/' . $this->config->basketReferences; + } + + if (file_exists($referencesFile) || Url::isDistant($referencesFile)) { + $ext = Files::getExtension($referencesFile); + if ($ext == 'xlsx') { + if ($this->config->basketManager == "ZoomProductLink") { + $function = 'excelToArrayKeyVal'; + } else { + $function = 'excelToArray'; + } + $this->config->basketReferences = ExcelToArray::$function($referencesFile); + if ($this->fluidbookSettings->customLinkClass == 'AtlanticDownloadLink') { + $this->config->basketReferences = self::atlanticReferences($this->config->basketReferences, 'local/', array($this, 'log'), array($this->vdir, "copy")); + } + } + $this->log("Done cart references"); + } + } + } + + public static function atlanticReferences($references, $dir, $log = null, $copy = 'copy') + { + foreach ($references as $i => $sheet) { + foreach ($sheet as $j => $line) { + foreach ($line as $k => $v) { + if (preg_match('|^http:\/\/atlantic-international-book-com\.com\/files\/(.*)$|', $v, $matches)) { + $local = $dir . '/' . $matches[1]; + $url = str_replace(' ', '%20', $v); + $cache = protected_path('fluidbookpublication/atlantic') . md5($url); + if (!file_exists($cache) || filemtime($url) > filemtime($cache)) { + copy($url, $cache); + $copylog = ' (copy) '; + } else { + $copylog = ' '; + } + call_user_func($copy, $cache, $dir . '/' . $matches[1]); + $references[$i][$j][$k] = 'local/' . $matches[1]; + if (null !== $log) { + call_user_func($log, 'Done' . $copylog . $matches[1]); + } + } + } + } + } + + return $references; + } + +} diff --git a/app/Fluidbook/Compiler/Compiler.php b/app/Fluidbook/Compiler/Compiler.php new file mode 100644 index 000000000..b0af8244b --- /dev/null +++ b/app/Fluidbook/Compiler/Compiler.php @@ -0,0 +1,3165 @@ + + ['js/libs/cube/util.js', + 'js/libs/cube/fb.js',], + 'modernizr' => + ['js/libs/modernizr/modernizr.min.js', + 'js/libs/modernizr/tests.js',], + 'modifier' => ['js/libs/threejs/modifier.min.js'], + 'threejs' => + ['js/libs/threejs/legacy/three.min.js', + 'js/libs/threejs/legacy/Projector.js', + 'js/libs/threejs/legacy/CanvasRenderer.js', + ], +// 'threejs-latest' => +// ['js/libs/threejs/latest/three.min.js', +// ], + 'jquery' => + [ + 'js/libs/jquery/jquery.min.js', + ], + 'jquery-extras' => ['js/libs/jquery/jquery.transform.js', + 'js/libs/jquery/jquery.form.min.js', + 'js/libs/jquery/jquery.mousewheel.min.js', + 'js/libs/jquery/jquery.hashchange.min.js', + 'js/libs/jquery/jquery.scrollto.min.js', + ], + 'aria' => ['js/libs/aria/radio.js',], + 'bluebird' => ['js/libs/bluebird.min.js'], + 'screenfull' => ['js/libs/screenfull.min.js'], + 'storage' => ['js/libs/storage.js',], + 'hotkeys' => ['js/libs/hotkeys.min.js',], + 'forge' => ['js/libs/forge/forge-sha256.min.js',], + 'perfectscrollbar' => ['js/libs/perfect-scrollbar/perfect-scrollbar.js', + 'js/libs/perfect-scrollbar/perfect-scrollbar.jquery.js'], + 'confirm' => ['js/libs/jquery/jquery.confirm.min.js'], + 'mmenu' => + ['js/libs/mmenu/jquery.mmenu.all.js'], + 'gsap' => + ['js/libs/gsap/gsap.min.js', + 'js/libs/gsap/ScrollToPlugin.min.js', + 'js/libs/gsap/InertiaPlugin.min.js', + 'js/libs/gsap/Draggable.min.js', + ], + 'hammer' => ['js/libs/hammer.min.js',], + 'interactjs' => ['js/libs/interact.min.js'], + 'gal' => + ['js/libs/gal/gal.js', + 'js/libs/gal/gal.filesystem.js',], + 'raphael' => + ['js/libs/raphael/raphael.min.js', + 'js/libs/gsap/plugins/RaphaelPlugin.min.js'], + 'countup' => + ['js/libs/countup/countup.min.js'], + 'clipboard' => ['js/libs/clipboard.min.js'], + 'fluidbook' => + ['js/libs/fluidbook/fluidbook.utils.js', + 'js/libs/fluidbook/fluidbook.networkcontrol.js', + 'js/libs/fluidbook/fluidbook.splash.js', + 'js/libs/fluidbook/fluidbook.links.js', + 'js/libs/fluidbook/fluidbook.support.js', + 'js/libs/fluidbook/fluidbook.video.js', + 'js/libs/fluidbook/fluidbook.viewport.js', + 'js/libs/fluidbook/fluidbook.desktop.js', + 'js/libs/fluidbook/fluidbook.service.js', + 'js/libs/fluidbook/fluidbook.share.js', + 'js/libs/fluidbook/fluidbook.l10n.js', + 'js/libs/fluidbook/fluidbook.slider.js', + 'js/libs/fluidbook/fluidbook.pagetransitions.js', + 'js/libs/fluidbook/fluidbook.nav.js', + 'js/libs/fluidbook/fluidbook.interface.js', + 'js/libs/fluidbook/fluidbook.input.js', + 'js/libs/fluidbook/fluidbook.touch.js', + 'js/libs/fluidbook/fluidbook.loader.js', + 'js/libs/fluidbook/fluidbook.search.js', + 'js/libs/fluidbook/fluidbook.help.js', + 'js/libs/fluidbook/fluidbook.resize.js', + 'js/libs/fluidbook/fluidbook.stats.js', + 'js/libs/fluidbook/fluidbook.cache.js', + 'js/libs/fluidbook/fluidbook.tooltip.js', + 'js/libs/fluidbook/fluidbook.bookmarks.js', + 'js/libs/fluidbook/fluidbook.background.js', + 'js/libs/fluidbook/fluidbook.pad.js', + 'js/libs/fluidbook/fluidbook.audiodescription.js', + 'js/libs/fluidbook/fluidbook.audioplayer.js', + 'js/libs/fluidbook/fluidbook.accessibility.js', + 'js/libs/fluidbook/fluidbook.privacy.js', + 'js/libs/fluidbook/fluidbook.zoom.js', + 'js/libs/fluidbook/fluidbook.menu.js', + 'js/libs/fluidbook/fluidbook.sound.js', + 'js/libs/fluidbook/fluidbook.contentlock.js', + 'js/libs/fluidbook/fluidbook.scorm.js', + 'js/libs/fluidbook/fluidbook.3dflip.js', + 'js/libs/fluidbook/menu/fluidbook.chapters.js', + 'js/libs/fluidbook/menu/fluidbook.index.js', + 'js/libs/fluidbook/fluidbook.landingpage.js', + 'js/libs/fluidbook/fluidbook.print.js', + 'js/libs/fluidbook/fluidbook.secure.js', + 'js/libs/fluidbook/fluidbook.tabs.js', + 'js/libs/fluidbook/fluidbook.articles.js', + 'js/libs/fluidbook/fluidbook.widget.js', + 'js/libs/fluidbook/fluidbook.keyboard.js', + 'js/libs/fluidbook/fluidbook.posad.js', + 'js/libs/fluidbook/fluidbook.notes.js', + 'js/libs/fluidbook/fluidbook.gamify.js', + 'js/libs/fluidbook/fluidbook.js', + 'js/main.js'], + 'mobilefirst' => [ + 'js/libs/fluidbook/fluidbook.mobilefirst.js', + 'js/libs/fluidbook/mobilefirst/fluidbook.mobilefirst.slider.js', + ], + ]; + + protected $specialJsFiles = array(); + + + public $jsFiles = []; + + // Collection of LESS files to be compiled + // Filename with no extension, relative to the /style directory in the player build folder + public $lessFiles = ['fluidbook']; + + public $specialCSS = array(); + public $phonegapStandardPlugins = array('ios' => array('ExternalFileUtil'), + 'android' => array('webintent')); + public $pluginCSS = array(); + public $pluginJs = array(); + public $htmlmultimedia = array(); + public $cssX = array(); + public $cssY = array(); + public $cssWidths = array(); + public $pdf2htmlRatio; + public $scale; + public $multiply; + public $div = array(); + public $numerotation; + public $fontDocs = array(); + public $dir; + public $z = 3; + protected $_lottieIDByHash = []; + + public $pages; + public $theme; + public $devversion; + public $book_id; + public $themeRoot; + public $needToRecompileContents = true; + public $needToRecompileSettings = true; + public $width; + public $height; + public $cssWidth; + public $cssHeight; + public $cssOneWidth; + public $cssOneHeight; + public $cssScale; + public $linkScale; + public $optimalWidth = 567; + public $optimalHeight = 709; + public $additionalConfig = array(); + public $fontScale = 1; + public $cache = array(); + public $backgroundsPrefix = array(); + public $svg = true; + public $assets = ''; + public $phonegap = false; + public $phonegapVersion; + public $standalone = false; + public $hiddenContents = array(); + public $appcache; + public $home; + public $widget = true; + public $multiApp = false; + public $pageLabels = array(); + public $stylesheets = array(); + public $logfp = null; + public $logtime = null; + public $beginBody = array(); + public $seoArticles = []; + public $securityPolicyWhitelist = ['*.google-analytics.com', '*.youtube.com', '*.ytimg.com', '*.googletagmanager.com']; + public $writeLinksData = false; + public $content_lock = []; + public $cssfont = []; + public $lessVariables = ["import-cart-styles" => 'none']; + protected $_indexVars = null; + public $accessibleTexts = []; + protected $_svgSymbols = []; + protected $_addedPDFJS = false; + protected $audioDescriptionTextsList = []; + protected $hybrid = false; + + protected $_docDimensions = []; + + public $_signature; + public $seo = null; + + /** + * @var \Cubist\Backpack\Magic\EntityData + */ + public $fluidbookSettings; + + /** + * @var \Cubist\Backpack\Magic\EntityData + */ + public $themeSettings; + + /** + * @var Command + */ + protected $_command = null; + + + use \App\Fluidbook\Compiler\Links; + use Cart; + + /** + * @param FluidbookPublication $book + * @param bool $scormVariant + * @param $phonegap + * @param $phonegapVersion + * @param $dir + * @param $standalone + * @param $appcache + * @param $home + * @param $theme FluidbookTheme|null + * @param $hybrid + * @param Command|null $command + * @throws \Exception + */ + + function __construct(FluidbookPublication $book, $scormVariant = false, $phonegap = false, $phonegapVersion = 'latest', $dir = null, $standalone = false, $appcache = false, $home = false, FluidbookTheme $theme = null, $hybrid = false, Command $command = null) + { + ExcelToArray::setCache(protected_path('fluidbookpublication/cache/exceltoarray')); + + parent::__construct(); + + $this->setFluidbook($book); + $this->setCommand($command); + + $this->phonegapVersion = self::getPhonegapVersion($phonegapVersion); + $this->appcache = $appcache; + $this->multiApp = $this->home = $home; + $this->devversion = $this->getFluidbook()->mobileLVersion; + $this->scormVariant = $scormVariant; + + $this->hybrid = $hybrid; + + $this->assets = self::getSourcesPath($this->devversion); + $this->compiledAssets = self::getCompiledSourcesPath($this->devversion); + + $this->phonegap = $phonegap; + $this->standalone = $standalone || $this->phonegap; + $this->appcache = $appcache; + $this->widget = !$this->phonegap; + + $this->fluidbookSettings = $this->getFluidbook()->getSettings(); + + PHP::memoryAllocate('12G'); + + $this->book_id = $this->getFluidbook()->id; + $this->log('Start compilation'); + + $this->dir = $this->getFluidbook()->getFinalPath($theme, $scormVariant); + $this->vdir = new VirtualDirectory($this->dir); + + $this->wdir = $this->getFluidbook()->getAssetDir(); + + $this->widget = false; + + $this->pages = $this->getFluidbook()->composition; + $this->maxRes = min(self::MAX_RES, $this->fluidbookSettings->maxResolution); + + $this->theme = $theme ?? $this->getFluidbook()->getTheme(); + + $this->themeSettings = $this->theme->getPageData(); + $this->log('Got data from database'); + + $this->width = round($this->getFluidbook()->getPageWidth(), 8); + $this->height = round($this->getFluidbook()->getPageHeight(), 8); + + $this->imageFormat = $this->fluidbookSettings->imageFormat; + + $p1 = $this->getFluidbook()->getFile(1, $this->imageFormat, 150); + $imagesize = Image::getimagesize($p1); + $this->pdf2htmlRatio = round(($imagesize[0] * 0.48) / $this->width, 12); + + $this->linkScale = $this->cssScale = $this->z * min($this->optimalWidth / $this->width, $this->optimalHeight / $this->height); + + $this->cssOneScale = $this->z * min(($this->optimalWidth * 2) / $this->width, $this->optimalHeight / $this->height); + + $this->cssWidth = $this->width * $this->cssScale; + $this->cssHeight = $this->height * $this->cssScale; + + $this->cssOneWidth = $this->width * $this->cssOneScale; + $this->cssOneHeight = $this->height * $this->cssOneScale; + + $this->scale = 1; + + if ($this->isMobileFirst()) { + $this->cssScale = $this->cssOneScale = 480 / $this->width; + $this->linkScale = $this->cssScale; + $this->cssOneWidth = $this->cssWidth = $this->width * $this->cssScale; + $this->cssOneHeight = $this->cssHeight = $this->height * $this->cssScale; + $this->initMobileFirst(); + } + + $this->svgfiles = array_unique([$this->assets . '/images/symbols/interface.svg', + storage_path('icons/15.svg')]); + if ($this->themeSettings->iconSet > 15) { + $this->svgfiles[] = storage_path('icons/' . $this->themeSettings->iconSet . '.svg'); + } + if ($symbols = $this->themeAsset('symbols')) { + $this->svgfiles[] = $symbols->getPathname(); + } + + if ($this->isMobileFirst()) { + $this->multiply = $this->pdf2htmlRatio * $this->scale * $this->cssOneScale; + } else { + $this->multiply = $this->pdf2htmlRatio * $this->scale * $this->cssScale; + } + + $this->initConfig(); + $this->log('Defined dimensions'); + } + + public function getFinalPath() + { + return $this->dir; + } + + + public function getSetting($key, $default = null) + { + if ($this->fluidbookSettings->has($key)) { + return $this->fluidbookSettings->get($key, $default); + } + if ($this->themeSettings->has($key)) { + return $this->themeSettings->get($key, $default); + } + return $default; + } + + + public function setSetting($key, $value) + { + if ($this->themeSettings->has($key)) { + $this->themeSettings->set($key, $value); + return; + } + $this->fluidbookSettings->set($key, $value); + } + + + /** + * @param $key + * @param $default + * @return null|SplFileInfo + */ + public function themeAsset($key) + { + $collection = $this->theme->{$key}; + + if ($collection) { + $path = $this->theme->getFirstMediaPath($collection); + if (!$path || !file_exists($path)) { + $res = false; + } else { + $res = new SplFileInfo($path); + } + } else { + $res = false; + } + if (null !== $this->config) { + if ($res instanceof SplFileInfo) { + $this->config->set($key, $res->getFilename()); + } else { + $this->config->set($key, ''); + } + } + return $res; + } + + /** + * @return FluidbookPublication + */ + public function getFluidbook(): FluidbookPublication + { + return $this->_fluidbook; + } + + /** + * @param FluidbookPublication $fluidbook + */ + public function setFluidbook(FluidbookPublication $fluidbook): void + { + $this->_fluidbook = $fluidbook; + } + + /** + * @return Command|null + */ + public function getCommand(): ?Command + { + return $this->_command; + } + + /** + * @param Command|null $command + */ + public function setCommand(?Command $command): void + { + $this->_command = $command; + } + + public function isMobileFirst() + { + return $this->fluidbookSettings->mobileNavigationType === 'mobilefirst'; + } + + public function initMobileFirst() + { + $this->themeSettings->usePageEdges = false; + } + + public function initConfig() + { + if (!$this->scormVariant) { + $this->fluidbookSettings->scorm_enable = false; + } + + $this->config = new Data(array_merge($this->fluidbookSettings->getRawData()['settings'], $this->themeSettings->getRawData())); + $this->config->pages = count($this->getFluidbook()->composition); + $this->config->bookmarkDisablePages = ArrayUtil::parseRange($this->config->bookmarkDisablePages); + $this->config->rasterizePages = ArrayUtil::parseRange($this->config->rasterizePages); + $this->config->vectorPages = array_diff(ArrayUtil::parseRange($this->config->vectorPages), $this->config->rasterizePages); + $this->numerotation = $this->config->numerotation = explode(',', $this->getFluidbook()->page_numbers); + + $hideOnPages = ArrayUtil::parseRange($this->config->tabsHideOnPages); + $this->config->tabsDisabledOnPages = ArrayUtil::parseRange($this->config->tabsDisabledOnPages); + + if ($this->config->tabsHideOnCover) { + $hideOnPages[] = 0; + $hideOnPages[] = 1; + } + if ($this->config->tabsHideOnLastPage) { + $hideOnPages[] = count($this->pages); + } + $this->config->tabsHideOnPages = $hideOnPages; + $this->config->triggersLinks = []; + $this->config->hasContentLock = false; + } + + public function populateConfig() + { + $this->config->id = $this->getFluidbook()->book_id; + $this->config->cid = $this->getFluidbook()->cid; + $this->config->cacheDate = time(); + $this->config->width = round($this->cssWidth, 2); + $this->config->height = round($this->cssHeight, 2); + $this->config->optimalWidth = round($this->optimalWidth, 2); + $this->config->optimalHeight = round($this->optimalHeight, 2); + $this->config->chapters = $this->getFluidbook()->chapters; + $this->config->videoFormats = $this->getVideosFormats(false); + $this->config->htmlmultimedia = $this->htmlmultimedia; + $this->config->phonegap = $this->phonegap; + $this->config->retinaResolution = min($this->fluidbookSettings->maxResolution, $this->maxRes); + $this->config->standardResolution = min($this->fluidbookSettings->maxResolution, 150); + $this->config->pageLabels = $this->pageLabels; + $this->config->pageZoomFactor = $this->z; + $this->config->multiply = round($this->multiply, 6); + $this->config->cssScale = round($this->cssScale, 6); + $this->config->pdfZoomFactor = round($this->pdf2htmlRatio, 6); + if ($this->home) { + $this->config->home = 'http://home'; + } + $this->config->multiApp = $this->multiApp; + foreach ($this->additionalConfig as $k => $v) { + $this->config->$k = $v; + } + if ($this->phonegap && ($this->fluidbookSettings->offlineLink == '' || $this->fluidbookSettings->offlineLink == 'http://')) { + $this->config->share = false; + } + if ($this->config->maxPages > 0) { + $this->addContentLock($this->config->maxPages); + } + + // We need to be able to reference both navOrder and navOrderH so convert both to arrays + // We also make sure there are no empty items in the arrays (see: http://php.net/manual/en/function.array-filter.php#111091) + $this->config->navOrder = array_filter(array_map('trim', explode(',', $this->config->navOrder)), 'strlen'); + $this->config->navOrderH = array_filter(array_map('trim', explode(',', $this->config->navOrderH)), 'strlen'); + + $this->config->standalone = $this->standalone; + if ($this->config->phonegap) { + $this->config->manifest = $this->writeManifest(); + } + + if ($this->config->form == 'bulle') { + $this->addJsLib('bulle', 'js/libs/fluidbook/forms/fluidbook.form.bulle.js'); + } else if ($this->config->form == 'bourbon') { + $this->addJsLib('parsley', 'js/libs/parsley.min.js'); + $this->addJsLib('bourbon', 'js/libs/fluidbook/forms/fluidbook.form.bourbon.js'); + } else if ($this->config->form == 'avery') { + $this->addJsLib('parsley', 'js/libs/parsley.min.js'); + $this->addJsLib('avery', 'js/libs/fluidbook/forms/fluidbook.form.avery.js'); + $this->addLess('form/avery'); + $this->writeCountries(); + } + $this->config->seoArticles = $this->seoArticles; + } + + + public function log($step) + { + $currenttime = microtime(true); + if (null === $this->logfp) { + $this->logfp = fopen(Files::mkdir(storage_path('logs/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); + fflush($this->logfp); + $this->logtime = $currenttime; + + if (null !== $this->getCommand()) { + $this->getCommand()->info(trim($log)); + } + } + + public function addFacebookSDK() + { + $lang = str_replace('-', '_', $this->getFluidbook()->lang); + $e = explode('_', $lang); + if (count($e) > 1) { + $e[1] = mb_strtoupper($lang); + } + $lang = implode('_', $e); + + $langsMap = ['fr' => 'fr_FR', 'en' => 'en_US']; + + if (isset($langsMap[$lang])) { + $lang = $langsMap[$lang]; + } + + $this->beginBody[] = "
+"; + $this->securityPolicyWhitelist[] = '*.facebook.net'; + $this->securityPolicyWhitelist[] = 'data:'; + } + + public function addPageLabel($page, $label) + { + $this->pageLabels[$label] = $page; + } + + public function getResolutions() + { + return self::getBookResolutions($this->getFluidbook()); + } + + + public static function getBookResolutions($book) + { + $maxRes = min(self::MAX_RES, $book->settings['maxResolution']); + $res = []; + if ($maxRes == self::MAX_RES) { + $res = [150, self::MAX_RES]; + } else if ($maxRes <= 150) { + $res = [$maxRes]; + } + return $res; + } + + public function getCssScale() + { + return $this->cssScale; + } + + public function getLinkScale() + { + return $this->linkScale; + } + + public function virtualToPhysical($virtual): string|int + { + if (isset($this->pageLabels[$virtual])) { + return $virtual; + } + if (!in_array($virtual, $this->numerotation)) { + return $virtual; + } + $p = array_search($virtual, $this->numerotation); + return $p + 1; + } + + public function handle() + { + $this->log('Preprocess images'); + FluidbookImagesPreprocess::dispatchSync($this->book_id); + $this->log('Start compile process'); + + // Raw copy of some directories + $directories = array('style/fonts/OpenSans', 'images', 'sound'); + foreach ($directories as $directory) { + $from = $this->assets . '/' . $directory; + $this->vdir->copyDirectory($from, $directory); + } + + if ($this->fluidbookSettings->scorm_enable || $this->fluidbookSettings->secureClientSidePassword) { + $this->fluidbookSettings->seoVersion = false; + } + if ($this->fluidbookSettings->embedAllLibraries) { + $this->addVideoJs(); + $this->addSlideshowLibrary(false); + $this->addSlideshowLibrary(true); + } + + $this->log('Copied assets'); + $this->writeSecure(); + $this->loadPlugins(); + $this->log('Plugins loaded'); + $this->writeImages(); + $this->log('Images written'); + $this->writeCartConfig(); + $this->writeXMLArticles(); + $this->log('XML Articles written'); + $this->writeSlider(); + $this->log('Slider written'); + $linksCSS = $this->writeLinks(); + $this->log('Links written'); + $this->writeArticles(); + $this->log('Articles written'); + $this->writeStats(); + $this->log('Stats written'); + $this->writeLangs(); + $this->log('Langs written'); + $this->writeSEO(); + $this->log('SEO written'); + $this->writeWidget(); + $this->log('Widget written'); + $this->writeSounds(); + $this->log('Sound written'); + $this->writeTexts(); + $this->log('Texts written'); + $this->writeAccessibility(); + $this->log('Accessibility written'); + $this->writeExtras(); + $this->log('Extras written'); + $this->populateConfig(); + $this->log('Config populated'); + $this->writeCSS($linksCSS); + $this->log('CSS written'); + $this->writeIndex(); + $this->log('Index written'); + if ($this->fluidbookSettings->scorm_enable) { + $this->writeScorm(); + $this->log('SCORM written'); + } + $this->writeJs(); + $this->log('Js written'); + $this->vdir->sync(true, $this); + $this->log('Files Synced'); +// $f=rtrim(str_replace('/html5/', '/compiletime/', $this->dir)); +// touch($f); + } + + protected function writeSlider() + { + if ($this->fluidbookSettings->sliderImage) { + $dim = Image::getimagesize($this->wdir . '/' . $this->fluidbookSettings->sliderImage); + $this->config->sliderImageDimensions = $dim; + $this->copyLinkFile($this->fluidbookSettings->sliderImage, 'data/interface'); + } + } + + protected function writeStats() + { + if ($this->fluidbookSettings->stats) { + $this->config->statsMatomo = $this->book_id; + $this->config->statsMatomoServer = 3; + if ($this->book_id >= 21210) { + $this->config->statsMatomoServer = 4 + ($this->book_id % 2); + } + } else { + $this->config->statsMatomo = false; + } + + if ($this->fluidbookSettings->tagcommander_id) { + $id = $this->fluidbookSettings->tagcommander_id; + if (!$this->fluidbookSettings->tagcommander_prod) { + $id .= '/uat'; + } + + $default = ['page_name' => '']; + $this->config->tagcommander_default_vars = array_merge($default, $this->parseVariables($this->fluidbookSettings->tagcommander_default_vars)); + $this->config->tagcommander_default_vars['env_work'] = $this->fluidbookSettings->tagcommander_prod ? 'prod' : 'pre-prod'; + + $scriptNames = explode(',', $this->config->tagcommander_scriptname); + $this->fluidbookSettings->googleAnalyticsCustom .= ''; + for ($i = 1; $i < count($scriptNames); $i++) { + $this->fluidbookSettings->statsCustom .= ''; + } + + if ($this->fluidbookSettings->tagcommander_plan) { + $planPath = $this->_wdirOrAbsolute($this->fluidbookSettings->tagcommander_plan); + + $plan = ExcelToArray::excelToArrayKeyVars($planPath); + $fixedplan = []; + foreach ($plan as $k => $v) { + $e = explode('#', $k); + if (count($e) === 2) { + $k = $e[1]; + } + + $fixedplan[$this->_labelToPage($k)] = $v; + } + $this->config->tagcommander_plan = $fixedplan; + } + } + if (isset($this->fluidbookSettings->googleTagManager) && $this->fluidbookSettings->googleTagManager) { + $this->fluidbookSettings->googleAnalyticsCustom .= " + + +"; + $this->fluidbookSettings->statsCustom = ' + +'; + + + } + } + + + protected function _wdirOrAbsolute($path) + { + $e = explode('#', $path); + if (file_exists($e[0])) { + return $path; + } + return $this->wdir . $path; + + } + + protected function _labelToPage($k) + { + $k = trim($k, '#/'); + $k = str_replace('page/page', 'page', $k); + + if (preg_match('/^page\/(\d+)$/', $k, $matches)) { + return $k; + } + + if (preg_match('/^page\/(.+)$/', $k, $matches)) { + $matches[1] = Text::removeAccents($matches[1]); + $matches[1] = mb_strtolower($matches[1]); + if (isset($this->pageLabels[$matches[1]])) { + return 'page/' . $this->pageLabels[$matches[1]]; + } + } + return $k; + } + + protected function writeSecure() + { + if ($this->fluidbookSettings->secureClientSidePassword) { + $credentials = Text::explodeNewLines($this->fluidbookSettings->secureClientSidePasswordCredentials); + $credentials[] = 'fluidbook:LatacaM4##*'; + $users = []; + foreach ($credentials as $credential) { + $salt = bin2hex(random_bytes(5)); + $e = explode(':', $credential); + if (count($e) <= 1) { + continue; + } + $usersalt = bin2hex(random_bytes(5)); + $user = hash("sha256", $usersalt . '+' . $e[0]); + $users[$user] = ['salt' => $salt, 'usersalt' => $usersalt, 'hash' => hash("sha256", $salt . '-' . $e[1])]; + } + + $secure = file_get_contents($this->wdir . '/' . $this->fluidbookSettings->secureClientSidePassword); + $secure = str_replace('$CREDENTIALS', 'var CREDENTIALS=' . json_encode($users) . ';', $secure); + $secure = str_replace('$TITLE', $this->fluidbookSettings->title, $secure); + $secure = str_replace('$CODE', '$(function () { + $(\'form\').on(\'submit\', function () { + var u = $("#username").val(); + var p = $("#password").val(); + var error = true; + $.each(CREDENTIALS, function (user, data) { + if (forge_sha256(data.usersalt + \'+\' + u) === user && forge_sha256(data.salt + \'-\' + p) === data.hash) { + error = false; + window.sessionStorage.setItem(\'secureUsername\', u); + window.sessionStorage.setItem(\'securePassword\', p); + window.location = \'index.html\'; + } + }); + if (error) { + $("#message").text(\'Wrong username or password\'); + } + return false; + }); + });', $secure); + $this->vdir->file_put_contents('secure.html', $secure); + $this->config->secureClientSidePasswordCredentials = $users; + } + + if ($this->fluidbookSettings->recaptcha) { + $this->beginBody[] = ''; + } + } + + protected function loadPlugins() + { + $e = explode("\n", $this->fluidbookSettings->mobilePlugins); + $main = array_pop($this->jsFiles); + + $plugins = array(); + + foreach ($e as $plugin) { + $plugin = trim($plugin); + if ($plugin == '') { + continue; + } + + $d = 'plugins/' . str_replace('.', '/', $plugin); + $dir = $this->assets . '/' . $d; + if (!file_exists($dir)) { + continue; + } + + $plugins[] = $plugin; + + if (file_exists($dir . '/plugin.js')) { + $f = $d . '/plugin.js'; + $this->pluginJs[] = $f; + $this->vdir->copy($dir . '/plugin.js', $f); + } + if (file_exists($dir . '/plugin.css')) { + $f = $d . '/plugin.css'; + $this->pluginCSS[] = $f; + $this->vdir->copy($dir . '/plugin.css', $f); + } + } + + $this->config->plugins = $plugins; + + array_push($this->jsFiles, $main); + } + + public function getVideosFormats($poster = true) + { + $res = []; + $res[] = 'mp4'; + + if ($poster) { + $res[] = 'jpg'; + } + return $res; + } + + /** + * 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, $collection = null) + { + + if (null === $collection) { + // 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 string The path of the file relative to the /style folder, without any extension + */ + public function addLess($path) + { + if (!in_array($path, $this->lessFiles)) { + $this->lessFiles[] = $path; + } + } + + /** + * @throws \Exception + */ + protected function writeSounds() + { + if ($this->fluidbookSettings->soundTheme == '') { + return; + } + $dir = resource_path('fluidbookpublication/sounds/' . $this->fluidbookSettings->soundTheme); + $this->setSetting('simpleSoundTheme', file_exists($dir . '/flip.mp3')); + $this->vdir->copyDirectory($dir, 'data/sounds'); + } + + protected function writeAccessibility() + { + if ($this->fluidbookSettings->audiodescriptionTexts) { + + $file = $this->wdir . '/' . $this->fluidbookSettings->audiodescriptionTexts; + if (file_exists($file)) { + new PHPExcel(); + $reader = new PHPExcel_Reader_Excel2007(); + $phpexcel = $reader->load($file); + + $sheet = $phpexcel->getActiveSheet(); + $maxRow = $sheet->getHighestRow(0); + + for ($i = 0; $i <= $maxRow; $i++) { + $page = trim($sheet->getCellByColumnAndRow(0, $i)->getValue()); + $text = trim($sheet->getCellByColumnAndRow(1, $i)->getValue()); + $voice = trim($sheet->getCellByColumnAndRow(2, $i)->getValue()); + if ($page == '' || $text == '') { + continue; + } + $data = ['text' => $text]; + if ($voice) { + $data['voice'] = $voice; + } + $this->audioDescriptionTextsList[$page] = $data; + } + } + } + + foreach ($this->audioDescriptionTextsList as $page => $data) { + $replace = [ + '`' => "'", + '“' => '"', + '”' => '"', + '’' => "'", + '—' => " - ", + '‘' => "'", + "…" => "...", + ]; + + $text = trim($data['text']); + $text = str_replace(array_keys($replace), array_values($replace), $text); + $text = Text::cleanUTF8($text, ''); + + $voiceInfos = $data['voice'] ?? $this->fluidbookSettings->audiodescriptionVoice; + + if ($voiceInfos) { + $e = explode(':', $voiceInfos); + + if (count($e) === 1) { + $engine = 'azuretts'; + $voice = $voiceInfos; + } else { + $engine = $e[0]; + $voice = $e[1]; + } + + $hash = hash('sha256', $engine . ':' . $voice . '_^_' . $text); + $fname = $hash . '.mp3'; + $dir = Files::mkdir(protected_path('audiodescription')); + + $file = $dir . $fname; + + if (!file_exists($file) || filesize($file) === 0) { + if ($engine == 'azuretts') { + $e = explode('/', $voice); + $this->_azureTTS($text, $e[0], $e[1], $e[2], $file); + } + } + + $this->config->audiodescription[$page] = $fname; + $this->vdir->copy($file, 'data/audiodescription/' . $fname); + } + $this->accessibleTexts[$page] = $text; + } + + if (count($this->accessibleTexts) > 0) { + $this->config->accessibleTexts = $this->accessibleTexts; + } + } + + + protected function _azureTTS($text, $locale, $gender, $voiceName, $output) + { + try { + $api = new \Cubist\Azure\TTS\Api('28fdfcdcc7f141b29cd9db4afc5779c5'); + $api->textToSpeech($text, $locale, $gender, $voiceName, $output); + } catch (Exception $e) { + dd($e); + } + } + + protected function _writeIndex($page) + { + if (!isset($this->seo->pages[$page])) { + return; + } + /** @var Page $seo */ + $seo = $this->seo->pages[$page]; + if (!$this->fluidbookSettings->seoVersion) { + $seo->robots = false; + } + $html = $seo->getHTML(); + + if ($this->fluidbookSettings->seoVersion) { + $seo->writePage($html, $this->vdir); + } + if ($page == 1) { + $seo->writePage($html, $this->vdir, 'index.html'); + } + } + + /** + * @throws \Exception + */ + public function getIndexVars() + { + if (null === $this->_indexVars) { + $titre = $this->fluidbookSettings->title; + + if (null === $this->_signature) { + $this->_signature = Signature::find($this->fluidbookSettings->signature); + $credits = $this->_signature->credits; + } else { + $credits = ''; + } + $hiddenContents = implode("\n", $this->hiddenContents); + $bgcolor = $this->themeSettings->loadingBackColor; + + // Feuilles de style + $sheets = array_merge($this->stylesheets, $this->specialCSS); + + $style = array(); + foreach ($sheets as $sheet) { + $style[] = ''; + } + $style = implode("\n\t\t", $style); + + $this->log('Got index vars 1'); + + $pagesContents = ''; + + $cache = ''; + + $beginbody = implode("\n", array_unique($this->beginBody)); + + $jstime = "?j=" . time(); + + $iscript = ''; + if (count($this->htmlmultimedia)) { + $iscript .= '' . "\n"; + } + + $script = '' . "\n"; + foreach ($this->jsLibs as $jsLib => $files) { + $script .= "\t" . '' . "\n"; + } + if ($this->fluidbookSettings->scorm_enable) { + $script .= "\t" . '' . "\n"; + } + if (count($this->specialJsFiles)) { + $script .= "\t" . '' . "\n"; + } + foreach ($this->pluginJs as $p) { + $script .= "\t" . '' . "\n"; + } + $script .= $iscript; + + $this->log('Got index vars 2'); + + $socialTitle = htmlspecialchars($this->fluidbookSettings->facebook_title ?: $titre, ENT_COMPAT); + $socialDescription = htmlspecialchars($this->fluidbookSettings->facebook_description ?: $this->fluidbookSettings->seoDescription, ENT_COMPAT); + + $socialImage = 'https://toolbox.fluidbook.com/services/socialimage/' . $this->getFluidbook()->cid; + $dim = self::getSocialImageSize($this->getFluidbook()); + + $socialImageWidth = $dim[0]; + $socialImageHeight = $dim[1]; + + $this->log('Got index vars 2.5'); + + + $titre = $this->fluidbookSettings->title; + + $description = ''; + + $twittercard = ' + + + + '; + $opengraph = ' + + + + '; + + $this->log('Got index vars 3'); + + $favicon = ''; + if ($this->theme->hasFaviconFile()) { + $pngFile = $this->theme->getFaviconPath('png'); + $this->vdir->copy($this->theme->getFaviconPath('ico'), 'data/favicon.ico'); + $this->vdir->copy($pngFile, 'data/favicon.png'); + $this->vdir->copy($pngFile, 'data/apple-touch-icon.png'); + + $datapng = 'data:image/png;base64,' . base64_encode(file_get_contents($pngFile)); + + $favicon .= '' . "\n\t"; + $favicon .= ''; + } + + $print = $this->writePDF(); + $message = ''; + + $this->log('Got index vars 4'); + + $splash = ''; + $splashstyles = ''; + $splashImage = $this->themeAsset('splashImage'); + if ($splashImage) { + $this->vdir->copy($splashImage->getPathname(), 'data/images/' . $splashImage->getFilename()); + $splashstyles = 'background-image:url(' . 'data/images/' . $splashImage->getFilename() . ');background-size:contain;background-position:50% 50%;'; + if ($this->fluidbookSettings->splashURL !== '') { + $splash = ''; + } + } else if ($logoLoader = $this->themeAsset('logoLoader')) { + $dim = Image::getimagesize($logoLoader->getPathname()); + if ($dim !== false) { + $this->vdir->copy($logoLoader->getPathname(), 'data/images/' . $logoLoader->getFilename()); + $splash .= ''; + } + } + $svg = $this->_mergeSVG(); + + if ($this->phonegap) { + $csp = "securityPolicyWhitelist)) . "; img-src * data:\">"; + } + $lang = $this->getFluidbook()->lang; + + $console = ''; + if ($this->fluidbookSettings->debugConsole) { + $console = '
+
+ +'; + } + + $this->log('Got index vars 5'); + $vars = array('lang', 'titre', 'credits', 'style', 'script', 'pagesContents', 'print', 'hiddenContents', 'splash', 'splashstyles', 'cache', 'bgcolor', 'message', 'favicon', 'svg', 'beginbody', 'csp', 'opengraph', 'twittercard', 'description', 'console'); + + $res = []; + foreach ($vars as $v) { + if (isset($$v)) { + $res[''] = $$v; + } else { + $res[''] = ''; + } + } + $this->_indexVars = $res; + $this->log('Got index vars 6'); + } + return $this->_indexVars; + } + + protected function _mergeSVG() + { + $symbols = []; + foreach ($this->svgfiles as $svgfile) { + $symbols = array_merge($symbols, $this->_getSVGSymbols($svgfile)); + } + $symbols = array_merge($symbols, $this->_svgSymbols); + return '' . str_replace('> <', '><', Text::removeNewLines(implode('', $symbols))) . ''; + } + + protected function _getSVGSymbols($svg) + { + if (file_exists($svg)) { + $svg = file_get_contents($svg); + } + $svg = str_replace('$bookmark-color', Color::colorToCSS($this->themeSettings->bookmarkBackgroundColor), $svg); + $res = []; + $xml = simplexml_load_string($svg); + if (!$xml) { + return $res; + } + $xml->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg'); + foreach ($xml->xpath('//svg:symbol') as $item) { + $res[(string)$item['id']] = $item->asXML(); + } + + return $res; + } + + protected function writeIndex() + { + $iv = $this->getIndexVars(); + $this->log('Got index vars'); + foreach ($iv as $k => $v) { + $this->seo->html = str_replace($k, $v, $this->seo->html); + } + if ($this->fluidbookSettings->seoVersion) { + foreach ($this->pages as $page => $infos) { + $this->_writeIndex($page); + } + } else { + $this->_writeIndex(1); + } + } + + protected function writeWidget() + { + // Write widget html +// if ($this->widget) { +// $whtml = file_get_contents($this->assets . '/widget.html'); +// $script = ''; +// $script .= ''; +// +// $style = ''; +// $vars = array('titre', 'style', 'script'); +// foreach ($vars as $v) { +// if (isset($$v)) { +// $whtml = str_replace('', $$v, $whtml); +// } else { +// $whtml = str_replace('', '', $whtml); +// } +// } +// $this->vdir->file_put_contents('widget.html', $whtml); +// } + } + + function writeSEO() + { + foreach ($this->seoArticles as $seoArticle) { + if ($this->hybrid) { + $html = file_get_contents($this->assets . '/_seohybrid.html'); + } else { + $html = file_get_contents($this->assets . '/_seo.html'); + } + $a = $seoArticle; + unset($a['image']); + $a['imageurl'] = 'https://workshop.fluidbook.com/services/facebook_thumbnail?cid=' . $this->getFluidbook()->cid . '&j=' . time(); + if ($seoArticle['image']) { + $a['imageurl'] .= '&image=' . $seoArticle['image']; + } + $dim = Image::getimagesize($a['imageurl']); + $a['imagewidth'] = $dim[0]; + $a['imageheight'] = $dim[1]; + foreach ($a as $k => $v) { + $html = str_replace('$' . $k, $v, $html); + } + $this->vdir->file_put_contents('p/' . $seoArticle['url'], $html); + } + $this->seo = new Document($this); + } + + public function addContentLock($page, $unlockConditions = '') + { + $this->config->hasContentLock = true; + $unlockConditions = Text::explodeNewLines($unlockConditions); + $conditions = []; + foreach ($unlockConditions as $unlockCondition) { + $e = explode(',', $unlockCondition); + if (!isset($e[1])) { + $e[1] = 'click'; + } + $conditions[] = $e; + } + $page = max(1, $page); + if (!isset($this->content_lock[$page])) { + $this->content_lock[$page] = ['unlocked' => 0, 'conditions' => []]; + } + $this->content_lock[$page]['conditions'] = array_merge($this->content_lock[$page]['conditions'], $conditions); + } + + protected function writeScorm() + { + $manifestfiles = ['1.2' => '_imsmanifest.12.xml', '2004' => '_imsmanifest.2004.xml', '2004.3' => '_imsmanifest.2004-3.xml']; + $manifestfile = $manifestfiles[(string)$this->fluidbookSettings->scorm_version]; + + $manifest = file_get_contents($this->assets . '/' . $manifestfile); + if (!$this->fluidbookSettings->scorm_title) { + $this->fluidbookSettings->scorm_title = $this->fluidbookSettings->title; + } + if (!$this->fluidbookSettings->scorm_id || ($this->getFluidbook()->book_id > 16614 && $this->fluidbookSettings->scorm_id === 'MFMCTE091mobile')) { + $this->fluidbookSettings->scorm_id = 'fb_' . $this->getFluidbook()->book_id; + } + if (!$this->fluidbookSettings->scorm_org) { + $this->fluidbookSettings->scorm_org = 'Fluidbook'; + } + + $vars = array('scorm_id', 'scorm_org', 'scorm_title'); + foreach ($vars as $v) { + $manifest = str_replace('$' . $v, htmlspecialchars($this->fluidbookSettings->$v, ENT_QUOTES), $manifest); + } + $this->vdir->file_put_contents('imsmanifest.xml', $manifest); + + + $this->config->scorm_variables = $this->fluidbookSettings->scorm_variables = $this->parseVariables($this->fluidbookSettings->scorm_variables); + if ($this->fluidbookSettings->scorm_quizdata) { + $this->config->scorm_quizdata = ExcelToArray::excelToArray($this->wdir . '/' . $this->fluidbookSettings->scorm_quizdata); + } + } + + protected function parseVariables($f) + { + $variables = []; + $f = str_replace("\r", "\n", $f); + $e = Text::explodeNewLines($f); + foreach ($e as $item) { + $item = trim($item); + if ($item == '') { + continue; + } + $f = explode('=', $item, 2); + $variables[trim($f[0])] = trim($f[1]); + } + return $variables; + } + + protected function writePDF() + { + if (!$this->fluidbookSettings->print && !$this->fluidbookSettings->pdf) { + return; + } + + $res = PDF::compilePDF($this->getFluidbook()); + if (!$this->config->pdfName) { + $this->config->pdfName = 'document.pdf'; + } + $this->config->pdfName = Text::removeAccents($this->config->pdfName); + if (mb_strtolower(substr($this->config->pdfName, -4)) !== '.pdf') { + $this->config->pdfName .= '.pdf'; + } + + if ($res !== false) { + $this->vdir->copy($res, 'data/' . $this->config->pdfName); + } + $this->log('PDF written'); + return ''; + } + + protected function addFilesInfos($key, $file) + { + if (!file_exists($file)) { + return; + } + if (!isset($this->config->filesInfos)) { + $this->config->filesInfos = array(); + } + $infos = array('filesize' => filesize($file)); + $dim = Image::getimagesize($file); + if ($dim !== false) { + $infos['width'] = $dim[0]; + $infos['height'] = $dim[1]; + } + $this->config->filesInfos[$key] = $infos; + } + + protected function __($str) + { + if (!isset($this->config->l10n)) { + $this->writeLangs(); + } + return $this->config->get('l10n.default.' . $str, $str); + } + + protected function writeLangs() + { + $this->config->defaultLang = $this->getFluidbook()->locale; + $l10n = FluidbookTranslate::getCompiledTranslations(); + $l10n['default'] = $this->getFluidbook()->getDefaultTranslations($l10n); + $this->config->setRaw('l10n', $l10n); + + + $multilang = Text::explodeNewLines($this->config->get('multilang', '')); + if (count($multilang)) { + $m = array(); + foreach ($multilang as $line) { + $line = trim($line); + if ($line == '') { + continue; + } + $l = explode(',', $line); + $locale = $l[0]; + $flag = $l[1]; + $this->getVirtualDirectory()->copy(resource_path('fluidbookpublication/flags/' . $flag . '.png'), 'images/flags/' . $flag . '.png'); + $l[3] = Text::ucfirst(Locale::translate($locale, $locale)); + $l[4] = Country::translate($flag, $locale); + $m[] = implode(',', $l); + } + + $this->config->setRaw('multilang', implode("\n", $m)); + } + } + + protected function writeExtras() + { + //dd($this->themeAsset('afterSearch')); + if ($afterSearch = $this->themeAsset('afterSearch')) { + $this->vdir->copy($afterSearch->getPathname(), 'data/images/' . $afterSearch->getFilename()); + } + if ($this->fluidbookSettings->externalArchives != '') { + $this->addFilesInfos('archives', $this->wdir . '/' . $this->fluidbookSettings->externalArchives); + $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->externalArchives, 'data/images/' . $this->fluidbookSettings->externalArchives); + } + + if (stristr($this->fluidbookSettings->navExtraImage, '.')) { + $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->navExtraImage, 'data/images/' . $this->fluidbookSettings->navExtraImage); + } + + if (stristr($this->fluidbookSettings->navExtraImageMobile, '.')) { + $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->navExtraImageMobile, 'data/images/' . $this->fluidbookSettings->navExtraImageMobile); + } + + for ($i = 1; $i <= 5; $i++) { + $ic = $this->fluidbookSettings->{'navExtraIcon' . $i}; + if ($ic != '') { + if (stristr($ic, '.svg')) { + $e = explode('.', $ic); + $sname = 'external-' . $e[0]; + $this->addSVGSymbolFromFile($this->wdir . '/' . $ic, $sname); + $this->config->{'navExtraIcon' . $i} = $sname; + } else if (stristr($ic, '.')) { + $this->vdir->copy($this->wdir . '/' . $ic, 'data/images/' . $ic); + } + } + } + } + + protected function addSVGSymbolFromFile($svg, $symbolName) + { + $svg = SVGTools::optimizeSVG($svg); + + $xml = simplexml_load_string(file_get_contents($svg)); + $viewBox = (string)$xml['viewBox']; + + $this->_svgSymbols[$symbolName] = '' . $this->SimpleXMLElement_innerXML($xml) . ''; + } + + + + /** + * @return bool + */ + public function isOnePage(): bool + { + return $this->_fluidbook->isOnePage(); + } + + /** + * @param $e \Exception + * @param $link Link + * @return void + * @throws \Exception + */ + protected function triggerLinkError($e, $link) + { + Log::error($e); + + /*$c = explode('\\', get_class($link)); + $type = array_pop($c); + $type = str_replace('Link', '', $type); + + throw new \Exception('Error on the ' . $type . ' link to ' . $link->to . ' on page ' . $link->page . ' with message : ' . $e->getMessage());*/ + } + + protected function _htmlLinkList($list) + { + if (!count($list)) { + return []; + } + $res = []; + foreach ($list as $blendmode => $l) { + usort($l, [$this, '_sortLinksByDepth']); + $res[$blendmode] = []; + foreach ($l as $item) { + $res[$blendmode][] = $item->getHTMLContainer(); + } + + } + return $res; + + } + + public function getBookSurface() + { + return $this->width * $this->height; + } + + protected function _sortLinksByDepth($a, $b) + { + $c = $a->getDepth() - $b->getDepth(); + if ($c === 0) { + $c = $b->getSurface() - $a->getSurface(); + } + if ($c === 0) { + $c = $b->getInitialOrder() - $a->getInitialOrder(); + } + + return $c; + } + + public function addSlideshowLibrary($inline = true) + { + $l = ($inline ? $this->config->inlineSlideshowLibrary : $this->config->popupSlideshowLibrary); + if ($l === 'splide') { + $this->addJsLib('splide', 'js/libs/splide/splide.js'); + } + + $this->addJsLib('slideshow', ['js/libs/fluidbook/slideshow/fluidbook.slideshow.js', + 'js/libs/fluidbook/slideshow/fluidbook.slideshow.' . $l . '.js']); + $this->addLess('slideshow/' . $l); + } + + public function addSEOArticle($page, $title, $intro, $image, $id = null, $url = null, $content = '') + { + if (null === $url) { + $url = Text::str2URL($title) . '.html'; + } + if (null === $id) { + $id = $title; + } + + $this->seoArticles[$id] = ['title' => $title, 'description' => $intro, 'image' => $image, 'content' => $content, 'page' => $page, 'url' => $url, 'id' => $id]; + } + + public function _sortLinks($a, $b) + { + + $priorities = array(26 => -1, 35 => 1); + + $pa = isset($priorities[$a['type']]) ? -$priorities[$a['type']] : 0; + $pb = isset($priorities[$b['type']]) ? -$priorities[$b['type']] : 0; + return $pb - $pa; + } + + public function addBookmarkGroup($link) + { + if ($link['left'] > $this->fluidbookSettings->width) { + //$link['page']++; + } + if ($link['page'] <= 0 || $link['page'] > $this->fluidbookSettings->pages) { + return; + } + + $this->config->bookmarkGroups[] = array('page' => ($link['page']), 'nb' => $link['to'], 'name' => $link['extra']); + } + + public function addTriggersLink($page, $link, $delay = 0) + { + $this->config->push('triggersLinks', ['page' => $page, 'link' => $link, 'delay' => $delay]); + } + + public function addAudiodescription($link) + { + + $e = explode('.', $link['to']); + $ext = mb_strtolower(array_pop($e)); + if ($ext === 'txt') { + $file = $this->wdir . '/' . $link['to']; + if (file_exists($file)) { + $this->audioDescriptionTextsList[$link['page']] = ['text' => file_get_contents($file)]; + } + } else { + $this->config->set('audiodescription.' . $link['page'], $link['to']); + $this->copyLinkFile($link['to'], 'data/audiodescription/'); + } + } + + protected function beforeWriteConfig() + { + // Dynamic background + $dbc = []; + $p = $this->parseVariables($this->fluidbookSettings->dynamicBackgroundColor); + foreach ($p as $range => $color) { + $e = explode(',', $color); + $pages = ArrayUtil::parseRange($range); + foreach ($pages as $page) { + $dbc[$page] = $e; + } + } + $this->config->dynamicBackgroundColor = $dbc; + if ($this->fluidbookSettings->textsThickness > 1) { + if ($this->fluidbookSettings->textsThicknessPages == '') { + $this->config->textsThicknessPages = range(1, $this->fluidbookSettings->pages); + } else { + $this->config->textsThicknessPages = ArrayUtil::parseRange($this->fluidbookSettings->textsThicknessPages); + } + } else { + $this->config->textsThickness = 1; + $this->config->textsThicknessPages = []; + } + + // Content locks + uasort($this->content_lock, function ($a, $b) { + return $a['page'] - $b['page']; + }); + + // Gamify + $p = $this->parseVariables($this->fluidbookSettings->gamify_coins_pages); + foreach ($p as $range => $coins) { + $pages = ArrayUtil::parseRange($range); + foreach ($pages as $page) { + $this->config->gamifyCoins['visit_page_' . $page] = (int)$coins; + } + } + + $this->config->content_lock = $this->content_lock; + } + + public function addPDFJS($force = false) + { + if ($this->_addedPDFJS) { + return; + } + + if (stripos($this->fluidbookSettings->PDFRenderer, 'pdfjs') !== false) { + $renderer = $this->fluidbookSettings->PDFRenderer; + } else if ($force) { + $renderer = 'pdfjs-legacy'; + } else { + return; + } + + $this->_addedPDFJS = true; + + + if ($renderer === 'pdfjs') { + $resource = resource_path('pdfjs/dist-min'); + } else if ($renderer === 'pdfjs-legacy') { + $resource = resource_path('pdfjs/legacy-min'); + } + $this->vdir->copyDirectory($resource, 'pdfjs'); + $this->vdir->copy($this->assets . '/js/libs/pdfjs/custom.js', 'pdfjs/web/custom.js'); + + + $css = '.seamless #sidebarContainer, .seamless .toolbar {display:none !important;}'; + $css .= '.seamless .pdfViewer{padding:0 !important;}'; + $css .= '.seamless #viewerContainer{top:0 !important;overflow:visible !important;}'; + $css .= '.seamless{--page-border:0;--page-margin:0;--body-bg-color:transparent;}'; + $css .= '.openFile,.rotateCw,.rotateCcw,.rotateCcw + .horizontalToolbarSeparator{display:none !important;}' . $this->fluidbookSettings->PDFJSCSS; + $this->vdir->file_put_contents('pdfjs/web/viewer.css', file_get_contents($resource . '/web/viewer.css') . $css); + } + + protected function writeJs() + { + $this->beforeWriteConfig(); + + $config = $this->writeConfig(); + $this->vdir->file_put_contents('data/datas.js', $config); + + $finals = $this->jsLibs; + $this->addPDFJS(); + + if ($this->fluidbookSettings->scorm_enable) { + $finals['scorm'] = array(); + $finals['scorm'][] = 'js/libs/scorm/apiwrapper.js'; + $finals['scorm'][] = 'js/libs/scorm/scorm.js'; + } + if (count($this->specialJsFiles)) { + $finals['special'] = $this->specialJsFiles; + } + if ($this->widget) { + $finals['widget'] = $this->widgetJsFiles; + } + + $dirminimized = Files::mkdir($this->compiledAssets . '/js/min'); + + foreach ($finals as $jsfinal => $files) { + $mintime = 0; + $hash = hash('sha256', json_encode($files)); + $minimized = $dirminimized . $jsfinal . '-' . $hash . '-min.js'; + if (file_exists($minimized) && filesize($minimized) > 0) { + $mintime = filemtime($minimized); + $reminimize = false; + } else { + $mintime = 0; + $reminimize = true; + } + + if (!$reminimize) { + foreach ($files as $file) { + $f = $this->assets . '/' . $file; + if (file_exists($f) && filemtime($f) > $mintime) { + $reminimize = true; + break; + } + } + } + + if (!$reminimize) { + if (filemtime(__FILE__) > $mintime || (file_exists(__DIR__ . '/class.ws.html5.links.php') && filemtime(__DIR__ . '/class.ws.html5.links.php') > $mintime)) { + $reminimize = true; + } + } + + if ($reminimize) { + $js = ''; + $hasNonMin = false; + foreach ($files as $file) { + $f = $this->assets . '/' . $file; + if (!file_exists($f)) { + continue; + } + if (strpos($f, '.min.') === false) { + $hasNonMin = true; + } + $js .= file_get_contents($f); + $js .= ";\n\n"; + } + $tmp = Files::tempnam(); + file_put_contents($tmp, $js); + + if (file_exists($minimized)) { + unlink($minimized); + } + + if (file_exists($tmp) && filesize($tmp) > 0) { + if ($hasNonMin) { + $uglify = new CommandLine('uglifyjs'); + $uglify->setArg('o', $minimized); + $uglify->setArg(null, $tmp); + $uglify->execute(); + } else { + $uglify = null; + copy($tmp, $minimized); + } + + if (!file_exists($minimized) || filesize($minimized) == 0) { + die('An error occured while uglifying ' . $hasNonMin . '? ' . $minimized . ': ' . ($uglify ? $uglify->commande : '') . ' :: ' . ($uglify ? $uglify->output : '') . '(' . implode(',', $files) . ')'); + } + } + } + $dest = 'data/' . $jsfinal . '.js'; + $this->vdir->copy($minimized, $dest); + } + + + if ($this->phonegap) { + // $this->vdir->copy(WS_COMPILE_ASSETS . '/_html5/js/libs/phonegap/' . $this->phonegapVersion . '/cordova-' . $this->phonegap . '.js', 'data/cordova.js'); + } + $this->vdir->copyDirectory($this->assets . '/js/libs/fluidbook/workers', 'js/libs/fluidbook/workers'); + $this->vdir->copyDirectory($this->assets . '/js/libs/stand', 'js/libs/stand'); + $this->vdir->copyDirectory($this->assets . '/js/libs/polyfills', 'js/libs/polyfills'); + } + + public function getCacheDir($path): string + { + return Files::mkdir(protected_path('fluidbookpublication/cache/' . $path)); + } + + public function writeTexts() + { + $cache = sha1($this->fluidbookSettings->highlightResults . '/--/' . $this->fluidbookSettings->searchWordSelectionAlgorithm . '///' . $this->fluidbookSettings->textExtraction . '|--|' . $this->fluidbookSettings->ignoreSearchSeparators . '|||' . $this->getFluidbook()->getCompositionUpdate() . '()()()' . FWSTK::lastUpdate()); + $cacheDir = Files::mkdir(protected_path('fluidbookpublication/index/' . $this->book_id . '/' . $cache . '/')); + $indexFile = $cacheDir . '/search.index.js'; + $textFile = $cacheDir . '/search.texts.js'; + $hightlightsFile = $cacheDir . '/search.highlight.js'; + + if (!file_exists($indexFile) || !file_exists($textFile)) { + SearchIndex::makeTextsIndexes($this, $cacheDir, $index, $texts, true); + file_put_contents($indexFile, 'var INDEX=' . $index . ';' . "\r"); + file_put_contents($textFile, 'var TEXTS=' . $texts . ";\r"); + } + if ($this->fluidbookSettings->highlightResults && !file_exists($hightlightsFile)) { + file_put_contents($hightlightsFile, 'var HIGHLIGHTS=' . json_encode(SearchIndex::makeHighlightIndex($this)) . ";\r"); + } + $this->vdir->copy($cacheDir . '/search.index.js', 'data/search.index.js'); + if ($this->fluidbookSettings->highlightResults) { + $this->vdir->copy($cacheDir . '/search.highlight.js', 'data/search.highlight.js'); + } + if ($this->fluidbookSettings->searchWordSelectionAlgorithm == 'expression') { + $this->vdir->copy($cacheDir . '/search.texts.js', 'data/search.texts.js'); + } + } + + protected function _SVGCleanAsset($a) + { + if (!stristr($a, '.svg')) { + return $a; + } + $clean = str_replace('.svg', '.o.svg', $a); + $path = $this->wdir . '/' . $a; + $opt = $this->wdir . '/' . $clean; + + if (!file_exists($opt) || !filesize($opt) || filemtime($path) > filemtime($opt)) { + if (file_exists($opt) && is_link($opt)) { + unlink($opt); + } + SVGTools::_optimizeSVG($path, $opt); + } + return $clean; + + } + + public function supportSVG() + { + if (!$this->phonegap) { + return false; + } else if ($this->phonegap == 'ios') { + return true; + } else { + return false; + } + } + + protected function writeConfig() + { + $data = $this->config->getRawData(); + foreach ($data as $k => $v) { + if (null === $v) { + $v = $data[$k] = ''; + } + if ($this->getFluidbook()->getField($k) instanceof Checkbox) { + $v = $data[$k] = !!$v; + } + } + $data['id'] = $this->book_id; + $data['compiler'] = 3; + return 'var SETTINGS=' . json_encode($data) . ';' . "\n"; + } + + protected function writeCountries() + { + $c = Country::getList($this->getFluidbook()->locale); + asort($c); + $this->config->countries = $c; + } + + protected function writeManifest() + { + $res = array(); + // TODO: Why was this function missing a return statement? It's called from populateConfig() is expected to return a value. + return $res; + } + + protected function writeImages() + { + switch ($this->fluidbookSettings->mobileVersion) { + case 'html5-desktop': + $this->backgroundsPrefix = array(true, false); + $this->svg = true; + break; + case 'html5-images': + $this->backgroundsPrefix = array(true); + $this->svg = false; + break; + default: + $this->backgroundsPrefix = array(false); + $this->svg = true; + break; + } + + $rasterizePages = $this->config->rasterizePages; + $this->config->pagesDimensions = []; + + if ($this->fluidbookSettings->mobileNavigationType === 'mobilefirst') { + $imdir = 'mf'; + } else { + $imdir = 'html'; + } + + $thumbs = array(); + foreach ($this->pages as $page => $infos) { + $thisrasterize = in_array($page, $rasterizePages); + $thisimagesvg = !$thisrasterize && $this->svg; + $thisbackgroundPrefix = $thisrasterize ? [true] : $this->backgroundsPrefix; + + foreach ($this->getResolutions() as $r) { + foreach ($thisbackgroundPrefix as $backgroundsPrefix) { + $source = $this->getFluidbook()->getFile($page, $this->imageFormat, $r, $backgroundsPrefix, true, $imdir); + if ($r === $this->maxRes) { + $this->getPageDimension($page); + } + $this->vdir->copy($source, 'data/background/' . $r . '/' . ($backgroundsPrefix ? 't' : 'p') . $page . '.' . $this->imageFormat); + } + } + + if ($thisimagesvg) { + $this->vdir->copy( + $this->getFluidbook()->getFile($page, 'svg', 150, true, + in_array($page, $this->config->vectorPages), 'html') + , 'data/contents/p' . $page . '.svg'); + } + + $t = $this->getFluidbook()->getThumbFile($page, $this->imageFormat); + $this->vdir->copy($t, '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'); + } + + + /** + * @param $page + * @return array + */ + protected function getPageDimension($page) + { + $k = 'pagesDimensions.' . $page; + if (!$this->config->has($k)) { + $d = $this->getFluidbook()->getDocumentSize($page); + $res = [round($this->cssWidth, 2), round($d[1] * ($this->cssWidth / $d[0]), 2)]; + $this->config->set($k, $res); + return $res; + } + return $this->config->get($k); + } + + public function getWidth() + { + return $this->getPageDimension(1)[0]; + } + + public function getHeight() + { + return $this->getPageDimension(1)[1]; + } + + + protected function _makeCover($orig) + { + $cached = $this->wdir . '/_cover.jpg'; + + if (!file_exists($cached) || filemtime($cached) < filemtime($orig)) { + $size = Image::getimagesize($orig); + $w = $size[0]; + $h = $size[1]; + + $tmp = Files::tempnam() . '.png'; + + $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 .= $cached; + $convert->setManualArg($cmd); + $convert->execute(); + + unlink($tmp); + } + $this->vdir->copy($cached, 'cover.jpg', true); + + } + + protected function _lessBoolean($val) + { + return $this->_themeBoolean($val) ? 'true' : 'false'; + } + + protected function _font($f) + { + $default = 'Arial, Helvetica, sans-serif'; + if ($f === 'OpenSans') { + $f = 'Open Sans'; + } + switch ($f) { + case 'Montserrat': + case 'Open Sans': + $this->addFontKit($f); + return "'" . $f . "', " . $default; + case 'sans-serif': + return $f; + case 'Arial': + return $default; + default: + return "'Open Sans', Arial, Helverica, sans-serif"; + } + } + + protected function _themeBoolean($v) + { + return !(null === $v || $v === '0' || $v === 0 || $v === false || !$v); + } + + protected function writeCSS($links) + { + $res = array(); + + $this->addFontKit('OpenSans'); + + $lessContents = ''; + + $this->lessVariables['font'] = $this->_font($this->themeSettings->interfaceFont); + $this->lessVariables['text-transform'] = $this->_themeBoolean($this->themeSettings->interfaceFontUppercase) ? 'uppercase' : 'inherit'; + + $this->lessVariables['css-scale'] = $this->cssScale; + + $this->lessVariables['slider-background'] = Color::colorToCSS(!$this->themeSettings->sliderBackground ? 'rgba(0,0,0,0.1)' : $this->themeSettings->sliderBackground); + $this->lessVariables['slider-handle'] = Color::colorToCSS(!$this->themeSettings->sliderHandle ? '#ffffff' : $this->themeSettings->sliderHandle); + $this->lessVariables['slider-display'] = $this->_lessBoolean($this->themeSettings->pagesBar); + $this->lessVariables['slider-thumb-background'] = Color::colorToCSS($this->themeSettings->pageBarThumbBack); + $this->lessVariables['pages-background'] = $this->fluidbookSettings->forceWhiteBackground ? '#ffffff' : 'transparent'; + + $this->log('CSS 1'); + + // General theme + $cssWidth = $this->cssWidth; + $cssHeight = $this->cssHeight; + $cssScale = $this->cssScale; + $w2 = ($cssWidth * 2) . 'px'; + $h = $cssHeight . 'px'; + + $wm = ($this->width * $this->multiply) . 'px'; + $hm = ($this->height * $this->multiply) . 'px'; + $w = $cssWidth . 'px'; + $offsetLeft = round(($this->optimalWidth - $cssWidth) / 2, 3); + $offsetLeft2 = $offsetLeft * 2; + $offsetTop = round(($this->optimalHeight - $cssHeight) / 2, 3); + $navTop = ($cssHeight - 40 - 100) / 2; + $leftOfRightPage = (floor($cssWidth) - 1) . 'px'; + + $this->lessVariables['z'] = $this->z; + $this->lessVariables['book-page-width'] = $w; + + + $this->lessVariables['book-page-correct-width'] = $w; + $this->lessVariables['book-page-correct-height'] = $h; + + + $this->log('CSS 2'); + $this->lessVariables['book-page-height'] = $h; + $this->lessVariables['book-page-ratio'] = floatval($w) / floatval($h); + + $this->lessVariables['page-shade-opacity'] = min(1, $this->themeSettings->shadeAlpha / 50); + $c = new Color($this->themeSettings->bookShadeColor); + $this->lessVariables['shadow-opacity'] = $c->getAlpha() * 1.2; + $this->lessVariables['edges-display'] = $this->_lessBoolean($this->themeSettings->usePageEdges); + $this->lessVariables['edge-left-offset'] = 0; + $this->lessVariables['edge-right-offset'] = 0; + $this->lessVariables['edges-opacity'] = 1; + + + $this->lessVariables['audioplayer-background-color'] = Color::colorToCSS($this->themeSettings->audioplayerBackgroundColor ?: $this->themeSettings->couleurL); + $this->lessVariables['audioplayer-icon-color'] = Color::colorToCSS($this->themeSettings->audioplayerIconColor); + $this->config->audioplayerStrokeColor = $this->lessVariables['audioplayer-stroke-color'] = Color::colorToCSS($this->themeSettings->audioplayerStrokeColor ?: $this->themeSettings->couleurL); + + $this->lessVariables['page-number-color'] = Color::colorToCSS($this->themeSettings->colorPageNumber); + $this->lessVariables['display-page-number'] = $this->_lessBoolean($this->themeSettings->displayPageNumber); + $this->lessVariables['page-transition-duration'] = $this->fluidbookSettings->mobileTransitionDuration . 's'; + + $this->config->mobileTransitionDurationSlide = ($this->fluidbookSettings->mobileTransitionDurationSlide ?: $this->fluidbookSettings->mobileTransitionDuration); + $this->lessVariables['page-transition-slide-duration'] = $this->config->mobileTransitionDurationSlide . 's'; + + $corrText = $this->isMobileFirst() ? 0 : 4; + $this->log('CSS 3'); + + // Theme + $shade = '.page .shade{'; + $shade .= 'opacity:' . min(($this->themeSettings->shadeAlpha * 2) / 100, 1) . ';'; + $shade .= '}'; + $res[] = $shade; + + // SVG + $res[] = 'svg .fill-c-menu-back{fill:' . Color::colorToCSS($this->themeSettings->couleurB) . ';}'; + $res[] = 'svg .fill-c-menu-text{fill:' . Color::colorToCSS($this->themeSettings->subTextColor) . ';}'; + + // Background + $res[] = $this->_cssBackground(); + $this->log('CSS 4'); + // Archives + // Header + $header = 'header{'; + $header .= 'height:' . $this->themeSettings->menuHeight . 'px;'; + if ($mi = $this->themeAsset('menuImage')) { + $this->vdir->copy($mi->getPathname(), 'data/images/' . $mi->getFilename()); + $header .= 'background-image:url(../images/' . $mi->getFilename() . ');'; + $header .= 'background-repeat:no-repeat;'; + $header .= 'background-size:100% ' . $this->themeSettings->menuHeight . 'px;'; + } else { + // Force redo + $header .= 'background-color:' . Color::colorToCSS($this->themeSettings->menuColor) . ';'; + } + $header .= '}'; + $res[] = $header; + $this->log('CSS 5'); + // Logo + $logo = '#logo{'; + if ($l = $this->themeAsset('logo')) { + $this->vdir->copy($l->getPathname(), 'data/images/' . $l->getFilename()); + $dim = Image::getimagesize($l->getPathname()); + $logo .= 'background-image:url(../images/' . $l->getFilename() . ');width:' . $dim[0] . 'px;height:' . $dim[1] . 'px;'; + } + $logo .= '}'; + $res[] = $logo; + + // Credits + $res[] = 'footer,footer a{color:' . Color::colorToCSS($this->themeSettings->creditsColor) . ';}'; + $this->log('CSS 6'); + // Arrows + $this->lessVariables['arrows-background'] = Color::colorToCSS($this->themeSettings->couleurA); + $this->lessVariables['arrows-color'] = Color::colorToCSS($this->themeSettings->arrowsColor); + + // Loader + $this->lessVariables['loader-background-color'] = Color::colorToCSS($this->themeSettings->couleurL); + $this->lessVariables['loader-foreground-color'] = Color::colorToCSS($this->themeSettings->loadingSecColor); + + // Audio description buttons + $this->lessVariables['audiodescription-background'] = Color::colorToCSS($this->themeSettings->couleurA); + $this->lessVariables['audiodescription-color'] = Color::colorToCSS($this->themeSettings->couleurA); + $this->log('CSS 7'); + // Links Styles + $this->lessVariables['links-color'] = Color::colorToCSS($this->themeSettings->linksColor); + $this->lessVariables['slideshow-color'] = Color::colorToCSS($this->themeSettings->slideshowColor ?: $this->themeSettings->couleurB); + $this->lessVariables['inlineslideshow-transition-time'] = (floatval($this->fluidbookSettings->inlineSlideshowTransitionDuration) * 1000) . 'ms'; + $this->lessVariables['slideshow-caption-size'] = $this->fluidbookSettings->slideshowCaptionSize ?: '16px'; + + $res = array_merge($res, $links); + + // Bookmarks + if (!isset($this->fluidbookSettings->bookmarkCornerSize)) { + $this->fluidbookSettings->bookmarkCornerSize = 10; + } + $this->log('CSS 8'); + $this->lessVariables['bookmark-star-disabled-color'] = Color::colorToCSS($this->themeSettings->bookmarkStarDisabledColor); + $this->lessVariables['bookmark-star-enabled-color'] = Color::colorToCSS($this->themeSettings->bookmarkStarEnabledColor); + $this->lessVariables['bookmark-color'] = Color::colorToCSS($this->themeSettings->bookmarkBackgroundColor); + $this->lessVariables['bookmark-corner-size'] = round($this->width * $this->fluidbookSettings->bookmarkCornerSize * 0.0075 * $this->z) . 'px'; + $this->lessVariables['bookmark-corner-offset'] = $this->fluidbookSettings->bookmarkOffset . 'px'; + + // Menus + $menuColor = new Color($this->themeSettings->couleurB); + $menuColor->setAlpha(1); + $menuTextColor = Color::colorToCSS($this->themeSettings->subTextColor); + $menuBreakpoint = empty($this->fluidbookSettings->menuBreakpoint) ? '1023px' : $this->fluidbookSettings->menuBreakpoint; + + $this->lessVariables['menu-breakpoint'] = $menuBreakpoint; + $this->lessVariables['menu-background'] = $menuColor->toCSS(); + if ($this->themeSettings->subSecondaryColor) { + $this->lessVariables['menu-button-background'] = Color::colorToCSS($this->themeSettings->subSecondaryColor); + } else { + $this->lessVariables['menu-background-green'] = 'max(45, min(255-45, green(@menu-background)))'; + $this->lessVariables['menu-background-red'] = 'max(45, min(255-45, red(@menu-background)))'; + $this->lessVariables['menu-background-blue'] = 'max(45, min(255-45, blue(@menu-background)))'; + $this->lessVariables['menu-button-background'] = 'overlay(rgb(@menu-background-red, @menu-background-green, @menu-background-blue), #c0c0c0)'; + } + $this->log('CSS 9'); + $this->lessVariables['menu-text'] = $menuTextColor; + $this->lessVariables['menu-field-background'] = Color::colorToCSS($this->themeSettings->subFieldColor); + $this->lessVariables['menu-field-text'] = Color::colorToCSS($this->themeSettings->subTextFieldColor); + $this->lessVariables['menu-select-background'] = Color::colorToCSS($this->themeSettings->subSelectColor); + $this->lessVariables['menu-select-text'] = Color::colorToCSS($this->themeSettings->subTextSelectColor); + $this->lessVariables['icon-color'] = Color::colorToCSS($this->themeSettings->couleurI); + $this->lessVariables['menu-overlay'] = Color::colorToCSS($this->themeSettings->popupVideoOverlay); + + $this->log('CSS 10'); + // Chapters + $this->lessVariables['menu-chapters-columns-count'] = max(1, min(6, $this->fluidbookSettings->chaptersColumns)); + $this->lessVariables['menu-chapters-columns-width'] = $this->fluidbookSettings->chaptersColMaxWidth; + $this->lessVariables['menu-chapters-font-size'] = $this->fluidbookSettings->chaptersFontSize; + + foreach ($this->getFluidbook()->getChapters() as $chapter) { + if ($chapter['color'] == '') { + continue; + } + $color = trim($chapter['color'], '#'); + $lessContents .= '.mview.c_' . $color . '{.menu-color(' . Color::colorToCSS($color) . ');}'; + } + + // Archives +// if ($this->>getFluidbook()->parametres->externalArchivesBack) { +// $this->vdir->copy($this->wdir . '/' . $this->>getFluidbook()->parametres->externalArchivesBack, 'data/images/' . $this->>getFluidbook()->parametres->externalArchivesBack); +// $res[] = '.mview.archives{background-image:url("../images/' . $this->>getFluidbook()->parametres->externalArchivesBack . '");}'; +// } + $this->log('CSS 11'); + # Index + $thumbw = $this->fluidbookSettings->mobileNavigationType === 'portrait' ? 200 : 100; + $this->lessVariables['thumb-width'] = $thumbw . 'px'; + $ratio = $this->width / $this->height; + $thumbh = round($thumbw / $ratio); + $this->config->thumbWidth = $thumbw; + $this->config->thumbHeight = $thumbh; + + $this->lessVariables['thumb-height'] = $thumbh . 'px'; + + #tooltip + $this->lessVariables['tooltip-background'] = Color::colorToCSS($this->themeSettings->tooltipBackColor); + $this->lessVariables['tooltip-color'] = Color::colorToCSS($this->themeSettings->tooltipTextColor); + $this->lessVariables['tooltip-font-size'] = $this->themeSettings->tooltipTextSize == 100 ? 14 : $this->themeSettings->tooltipTextSize; + $this->lessVariables['tooltip-padding'] = $this->themeSettings->tooltipPadding ?: 20; + $this->log('CSS 12'); + #Videos + if ($this->fluidbookSettings->bigPlayImage) { + $this->lessVariables['video-bigplay-image'] = '~"../data/links/' . $this->fluidbookSettings->bigPlayImage . '"'; + $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->bigPlayImage, 'data/links/' . $this->fluidbookSettings->bigPlayImage); + } else { + $this->lessVariables['video-bigplay-image'] = '~"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMTMuNCAxMTMuNCI+PHN0eWxlPi5zdDB7b3BhY2l0eTowLjg7fSAuc3Qxe2ZpbGw6I0ZGRkZGRjt9PC9zdHlsZT48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTEwLjUgMTEzLjRIMi45Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlWMi45QzAgMS4zIDEuMyAwIDIuOSAwaDEwNy42YzEuNiAwIDIuOSAxLjMgMi45IDIuOXYxMDcuNmMwIDEuNi0xLjMgMi45LTIuOSAyLjl6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTQ1LjggMzcuOGwzMS41IDE3LjljLjguNS44IDEuNiAwIDIuMUw0NS44IDc1LjZjLS44LjUtMS44LS4xLTEuOC0xVjM4LjhjMC0uOSAxLTEuNSAxLjgtMXoiLz48L3N2Zz4="'; + } + + #fonts + foreach ($this->cssfont as $hash => $item) { + $res[] = '@font-face{font-family: "' . $hash . '";src:url("../../data/fonts/' . $hash . '.woff") format("woff");}'; + } + + if ($this->fluidbookSettings->textPopupStylesheet) { + $res[] = file_get_contents($this->wdir . '/' . $this->fluidbookSettings->textPopupStylesheet); + } + $this->log('CSS 13'); + $this->_writeLess($this->lessVariables, $lessContents); + $this->stylesheets[] = 'data/style/style.css'; + $this->vdir->file_put_contents('data/style/style.css', implode("\n", $res)); + $this->log('Write CSS'); + } + + protected function _writeLess($variables, $lessContents = '') + { + if ($this->widget) { + $this->lessFiles[] = 'widget'; + } + foreach ($this->specialCSS as $s) { + $this->lessFiles[] = 'special/' . $s; + } + + $tmp = Files::tmpdir(); + + $from = $this->assets . '/style/*'; + `cp -r $from $tmp`; + + $bookVariables = array(); + foreach ($variables as $k => $v) { + $bookVariables[] = '@' . trim($k) . ':' . $v . ';'; + } + file_put_contents($tmp . '/book-variables.less', implode("\n", $bookVariables)); + file_put_contents($tmp . '/additional.less', $lessContents); + + foreach ($this->lessFiles as $f) { + $source_less = $this->assets . '/style/' . $f . '.less'; + $destination_less = $tmp . '/' . $f . '.less'; + $destination_css = $tmp . '/' . $f . '.css'; + + if (!file_exists($source_less)) { + die($source_less); + continue; + } + + $dir = dirname($destination_css); + + if (file_exists($dir) && !is_dir($dir)) { + unlink($dir); + } + // LESS file might be in a subfolder, so create if it doesn't exist + if (!file_exists($dir)) { + mkdir($dir, 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); + $less = new CommandLine('lessc'); + $less->setArg(null, $destination_less); + $less->setArg(null, $destination_css); + $less->execute(); + if (!file_exists($destination_css)) { + die($less->output); + continue; + } + $this->vdir->copy($destination_css, 'style/' . $f . '.css'); + if ($f != 'widget') { + $this->stylesheets[] = 'style/' . $f . '.css'; + } + } + } + + protected function _cssBackground() + { + $body = '#background, #splash {'; + + switch ($this->themeSettings->repeat) { + case FluidbookTheme::REPEAT: + $body .= 'background-repeat:repeat;'; + break; + case FluidbookTheme::NONE: + $body .= 'background-repeat:no-repeat;'; + break; + case FluidbookTheme::RATIO: + $body .= 'background-repeat:no-repeat;'; + $body .= 'background-size:cover;'; + break; + case FluidbookTheme::STRETCH: + $body .= 'background-repeat:no-repeat;'; + $body .= 'background-size:100% 100%;'; + break; + } + + if ($backgroundImage = $this->themeAsset('backgroundImage')) { + + $dbi = Image::getimagesize($backgroundImage->getPathname()); + $this->config->backgroundImageDimensions = array('width' => $dbi[0], 'height' => $dbi[1]); + + + $this->vdir->copy($backgroundImage->getPathname(), 'data/images/' . $backgroundImage->getFilename()); + $body .= 'background-image:url(../images/' . $backgroundImage->getFilename() . ');'; + $body .= 'background-position:'; + + switch ($this->themeSettings->backgroundVAlign) { + case FluidbookTheme::TOP: + $body .= 'top'; + break; + case FluidbookTheme::MIDDLE: + $body .= 'center'; + break; + case FluidbookTheme::BOTTOM: + $body .= 'bottom'; + break; + } + + $body .= ' '; + + switch ($this->themeSettings->backgroundHAlign) { + case FluidbookTheme::LEFT: + $body .= 'left'; + break; + case FluidbookTheme::CENTER: + $body .= 'center'; + break; + case FluidbookTheme::RIGHT: + $body .= 'right'; + break; + } + $body .= ';'; + } + + $body .= '}'; + + + if ($this->_themeBoolean($this->themeSettings->displayBackgroundDuringLoading)) { + $body .= '#background, #splash { + background-color:' . Color::colorToCSS($this->themeSettings->backgroundColor) . ' !important; + }'; + } else { + $body .= '#background { + visibility: hidden; + opacity: 0; + background-color:' . Color::colorToCSS($this->themeSettings->backgroundColor) . ' !important; + }'; + + $body .= '#splash { + background-color:' . Color::colorToCSS($this->themeSettings->loadingBackColor) . ' !important; + background-image: none; + }'; + } + + return $body; + } + + public static function writeCSSUA($property, $value) + { + $res = array(); + foreach (self::$uaPrefixes as $prefix) { + $res[] = $prefix . $property . ':' . $value; + } + return implode(';', $res); + } + + protected function base62($val) + { + $chars = '0123456789abcdefghijklmnopqrstuvwxyz'; + $base = strlen($chars); + $str = ''; + do { + $i = $val % $base; + $str = $chars[$i] . $str; + $val = ($val - $i) / $base; + } while ($val > 0); + return $str; + } + + public function copyLinkDir($source, $dest) + { + $this->vdir->copyDirectory($source, $dest); + } + + public function simpleCopyLinkFile($source, $dest) + { + if (stripos($source, '.svg') !== false) { + $source = $this->_fixSVG($source); + } + + $this->vdir->copy($source, $dest); + } + + protected function _fixSVG($source) + { + $fixed = str_replace('.svg', '.f.svg', $source); + if (file_exists($fixed) && filemtime($fixed) >= filemtime($source)) { + return $fixed; + } + if (file_exists($fixed) && is_link($fixed)) { + unlink($fixed); + } + $svg = simplexml_load_string(file_get_contents($source)); + $attr = $svg->attributes(); + if (isset($attr['width'], $attr['height'])) { + copy($source, $fixed); + return $fixed; + } + + $dim = Image::getimagesize($source); + $svg->addAttribute('preserveAspectRatio', 'none'); + $svg->addAttribute('width', $dim[0]); + $svg->addAttribute('height', $dim[1]); + file_put_contents($fixed, $svg->asXML()); + + return $fixed; + } + + public function addVideoJs() + { + $locale = $this->getFluidbook()->lang; + $map = ['pt' => 'pt-PT', 'pt-br' => 'pt-BR', 'zh' => 'zh-CN', 'es-pr' => 'es']; + if (isset($map[$locale])) { + $locale = $map[$locale]; + } + + $this->addJsLib('videojs', ['js/libs/videojs/video.min.js', 'js/libs/videojs/lang/' . $locale . '.js']); + $this->addLess('videojs/videojs'); + } + + public function addParallax() + { + $this->addJsLib('parallax', ['js/libs/fluidbook/fluidbook.parallax.js']); + } + + public function addLottie($animationData, $params, $hash) + { + if (isset($this->_lottieIDByHash[$hash])) { + return $this->_lottieIDByHash[$hash]; + } + + $this->addJsLib('lottie', 'js/libs/lottie.min.js'); + + if (!isset($this->config->lottieAnimations)) { + $this->config->lottieAnimations = []; + } + + $id = count($this->config->lottieAnimations); + $this->config->lottieAnimations[] = [$params, $animationData]; + $this->_lottieIDByHash[$hash] = $id; + return $id; + } + + public function addFont($fontFile) + { + $f = $this->wdir . '/' . $fontFile; + $e = explode('.', $f); + $ext = array_pop($e); + $hash = 'fb_' . substr(md5($fontFile), 0, 10); + if (!isset($this->cssfont[$hash])) { + $final = $hash . '.woff'; + $dest = $this->wdir . '/' . $final; + if (!file_exists($dest) || filemtime($dest) < filemtime($f)) { + $script = resource_path('tools/fonts/convertrn.pe'); + if (!is_executable($script)) { + chmod($script, 755); + } + $fontforge = new CommandLine('fontforge'); + $fontforge->setArg('-script', $script); + $fontforge->setArg(null, $f); + $fontforge->setArg(null, $dest); + $fontforge->execute(); + //$fontforge->debug(); + } + $this->vdir->copy($dest, 'data/fonts/' . $hash . '.woff'); + $fontline = new CommandLine('font-line'); + $fontline->setArg(null, 'report'); + $fontline->setArg(null, $f); + $fontline->execute(); + //$fontline->debug(); + $report = explode("\n", $fontline->getOutput()); + + foreach ($report as $item) { + $item = trim($item); + if (!stristr($item, ':')) { + continue; + } + list($k, $v) = explode(':', $item, 2); + $v = trim($v); + if ($k == '[head] Units per Em') { + $fontHeight = $v; + } + if ($k == '[OS/2] CapHeight') { + $fontCapHeight = $v; + } + if ($k == '[OS/2] TypoAscender') { + $ascender = abs($v); + } + if ($k == '[OS/2] TypoDescender') { + $descender = abs($v); + } + } + $capHeight = 1; + if (isset($fontCapHeight) && isset($fontHeight)) { + $capHeight = $fontCapHeight / $fontHeight; + } + $font = ['family' => $hash, 'capHeight' => $capHeight, 'ascender' => $ascender / $fontHeight, 'descender' => $descender / $fontHeight]; + $this->cssfont[$hash] = $font; + } + return $this->cssfont[$hash]; + } + + public function addJsLib($name, $files) + { + if (!isset($this->jsLibs[$name])) { + $this->jsLibs[$name] = []; + } + if (!is_array($files)) { + $files = [$files]; + } + $diff = array_diff($files, $this->jsLibs[$name]); + if (count($diff)) { + $this->jsLibs[$name] = array_merge($this->jsLibs[$name], $diff); + } + } + + public static function encodeWebVideos($file, $dir = null, $async = true, $force = false, $format = 'all') + { + $file = new SplFileInfo($file); + if (is_null($dir)) { + $dir = $file->getPath(); + } + + $videos = array('mp4', 'jpg'); + + if (is_string($format)) { + if ($format == 'none') { + $format = array(); + } elseif ($format == 'all') { + $format = $videos; + } else { + $format = array($format); + } + } + + if (!$force) { + $format = array(); + } + + + $base = $dir . '/' . $file->getBasename('.' . $file->getExtension()); + $log = $base . '.log'; + + foreach ($videos as $v) { + $vfile = $base . '.' . $v; + if (!file_exists($vfile)) { + $force = true; + } else if (filemtime($file) > filemtime($vfile) || in_array($v, $format)) { + $force = true; + unlink($vfile); + } + } + + if (!$force && file_exists($log) && filemtime($log) > filemtime($file)) { + return; + } + + $webvideo = new CommandLine('/application/scripts/webvideo', $log); + $webvideo->setArg(null, $file); + $webvideo->setArg(null, $dir); + $webvideo->execute(); + } + + + public function copyLinkFile($source, $dest, $video = false) + { + if ($video && $this->fluidbookSettings->mobileVideosPath != '') { + + } + $origDir = $this->wdir; + $types = $this->getVideosFormats(); + if ($video) { + self::encodeWebVideos($origDir . $source, null, true); + $e = explode('.', $source); + array_pop($e); + $base = implode('.', $e); + $source = array(); + foreach ($types as $type) { + $source[] = $base . '.' . $type; + } + } + + if (!is_array($source)) { + $source = array($source); + } + + foreach ($source as $so) { + $s = $origDir . $so; + if (file_exists($s)) { + $d = $dest . '/' . $so; + $this->simpleCopyLinkFile($s, $d, false); + } + } + } + + public function __destruct() + { + + } + + public function unzipFile($file, $moveAssets = false, $baseDir = null, $junkPaths = false) + { + $fdir = is_null($baseDir) ? 'data/links/' . str_replace('.', '_', $file) : $baseDir; + + $zipPath = $this->wdir . '/' . $file; + $dir = protected_path('fluidbookpublication/cache/unzip') . '/' . Files::hashFileAttributes($zipPath) . '_' . ($moveAssets ? '1' : '0') . '_' . ($junkPaths ? '1' : '0'); + + if (!file_exists($dir)) { + mkdir($dir, 0777, true); + Zip::extract($zipPath, $dir, $junkPaths); + if ($moveAssets) { + `mv $dir/Assets/* $dir`; + rmdir($dir . '/Assets'); + } + } + + return array('dir' => $dir, 'fdir' => $fdir); + } + + public function getConfigZIP($d) + { + $res = array('type' => 'zip', 'width' => 0, 'height' => 0); + if (file_exists($d . '/index.html')) { + $doc = new DOMDocument(); + @$doc->loadHTMLFile($d . '/index.html'); + $xpath = new DOMXPath($doc); + $c = $xpath->query("//canvas"); + foreach ($c as $canvas) { + /* @var $canvas DOMElement */ + $res['width'] = intval((string)$canvas->getAttribute('width')); + $res['height'] = intval((string)$canvas->getAttribute('height')); + } + + $m = $xpath->query('//meta[@name="width"]'); + foreach ($m as $meta) { + $res['width'] = intval((string)$meta->getAttribute('content')); + } + + $m = $xpath->query('//meta[@name="height"]'); + foreach ($m as $meta) { + $res['height'] = intval((string)$meta->getAttribute('content')); + } + + $r = array('html' => 'index.html', 'inject' => array(), 'injectcss' => array(), 'injectjs' => array()); + } else { + $r = array('html' => false, 'inject' => array(file_get_contents($d . '/init.js')), 'injectcss' => array('multimedia.css'), 'injectjs' => array('multimedia.js')); + } + return array_merge($res, $r); + } + + public function addFontKit($font) + { + if ($font === 'sans-serif') { + return; + } + if ($font === 'Open Sans') { + $font = 'OpenSans'; + } + + $path = 'style/fonts/' . $font; + $css = $path . '/font.css'; + if (in_array($css, $this->stylesheets)) { + return; + } + $this->stylesheets[] = $css; + $this->vdir->copyDirectory($this->assets . '/' . $path, $path); + return $path . '/font.css'; + } + + + public function SimpleXMLElement_innerXML($xml) + { + $innerXML = ''; + foreach (dom_import_simplexml($xml)->childNodes as $child) { + $innerXML .= $child->ownerDocument->saveXML($child); + } + return $innerXML; + } + + public function writeXMLArticles() + { + $f = $this->fluidbookSettings->articlesFile; + + $this->lessVariables['articles-title-color'] = '#000000'; + $this->lessVariables['articles-font'] = 'Open Sans'; + + if (!$f || !file_exists($this->wdir . '/' . $f) || !is_file($this->wdir . '/' . $f)) { + return; + } + $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); + + $list = $this->config->articlesList ?? []; + + + $this->lessVariables['articles-title-color'] = '#565657'; + + + $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'; + } + + $specificStyles = '## h3, ## figure figcaption{background-color:' . $color . '}'; + $specificStyles .= '## .chapo, ## blockquote, ## a{color:' . $color . ';}'; + + $inner = '
'; + $inner .= '
'; + if ($this->fluidbookSettings->articlesShare && $this->fluidbookSettings->share) { + $inner .= ''; + } + $inner .= ''; + $inner .= '
'; + + $inner .= '
'; + + $title = ''; + $lead = ''; + $image = ''; + + $first = true; + + foreach ($a->children() as $child) { + if ($first) { + $first = false; + if ($child->getName() !== 'category') { + $inner .= '

 

'; + } + } + $inner .= $this->_articleToHTML($child, $title, $lead, $image, $dir); + } + $inner .= '
'; + + if (!$title) { + $title = 'Article sans titre ' . $k; + } + + if (!$id) { + $id = Text::str2URL($title); + } + + if (!$url) { + $url = $id . '.html'; + } + + $inner = str_replace(array('$id', '$url'), array($id, $url), $inner); + + $article = ['id' => $id, + 'url' => $url, + 'color' => $color, + 'contents' => '', + 'type' => 'xml']; + + $article['contents'] = $inner; + $content = ''; + $content .= ''; + $content .= ''; + $content .= ''; + $content .= ''; + $content .= ''; + $content .= $svg; + $content .= $inner; + $content .= ''; + $article['print'] = $content; + $list[] = $article; + + $this->addSEOArticle('#/article/' . $article['url'], $title, $lead, $image, $article['id'], $article['url'], $inner); + } + + if (isset($list)) { + $this->config->articlesList = $list; + } + } + + public function findArticleById($id) + { + foreach ($this->config->articlesList as $item) { + if ($item['id'] === $id) { + return $item; + } + } + return null; + } + + public function updateArticleById($id, $article) + { + foreach ($this->config->articlesList as $k => $item) { + if ($item['id'] === $id) { + $this->config->articlesList[$k] = $article; + break; + } + } + } + + public function writeArticles() + { + $list = $this->config->articlesList ?? []; + + $nb = count($list); + + usort($list, function ($a, $b) { + if ($a['page'] == $b['page']) { + $ea = explode('-', $a['id']); + $eb = explode('-', $b['id']); + if (is_numeric($ea[0]) && is_numeric($eb[0])) { + return $ea[0] - $eb[0]; + } + return strcmp($a['id'], $b['id']); + } + return $a['page'] - $b['page']; + }); + + foreach ($list as $k => $item) { + $nextIndex = ($k + 1) % $nb; + $prevIndex = ($k - 1 + $nb) % $nb; + $list[$k]['prev'] = $list[$prevIndex]['url']; + $list[$k]['next'] = $list[$nextIndex]['url']; + } + + + $idlist = []; + foreach ($list as $item) { + $idlist[$item['id']] = $item; + } + + $this->config->articlesList = $idlist; + } + + /** + * @param $child SimpleXMLElement + * @param $title + * @param $lead + * @param $image + * @return string|void + */ + protected function _articleToHTML($child, &$title, &$lead, &$image, $dir = null) + { + $markupMap = ['category' => 'h3', + 'subtitle' => 'h2', + 'legend' => 'figcaption', + 'title' => 'h1', + 'lead' => 'div.chapo', + 'paragraph' => 'p', + 'note' => 'div.note', + 'quote' => 'blockquote', + 'signature' => 'div.author', + 'intertitle' => 'h2.inter', + 'bigfont' => 'h2.bigfont', + 'separator' => 'hr', + 'link' => 'a']; + + $attrsmap = ['a' => ['link' => 'href']]; + + $dirattr = ''; + if (isset($child['dir'])) { + $d = (string)$child['dir']; + if ($d !== $dir) { + $dirattr = ' dir="' . $d . '"'; + $dir = $d; + } + } + + $res = ''; + $tag = $child->getName(); + if ($tag === 'encadre') { + $res .= ''; + foreach ($child->children() as $sub) { + $res .= $this->_articleToHTML($sub, $a1, $a2, $a3, $dir); + } + $res .= ''; + } else if ($tag === 'youtube') { + $res .= '
'; + } else if ($tag === 'image') { + $srcattrs = ['href', 'src', 'file']; + $file = ''; + foreach ($srcattrs as $srcattr) { + if (isset($child[$srcattr])) { + $file = (string)$child[$srcattr]; + break; + } + } + if ($image === '') { + $image = 'articles/' . $file; + } + $filepath = $this->wdir . '/articles/' . $file; + $this->vdir->copy($filepath, 'data/articles/' . $file); + $legend = (string)$child; + $caption = $legend ? '
' . $legend . '
' : ''; + if (file_exists($filepath)) { + $dim = getimagesize($filepath); + } else { + $dim = [0 => 1024, 1 => 10]; + } + $res .= '' . $legend . '' . $caption . ''; + } else { + $c = trim($this->SimpleXMLElement_innerXML($child)); + if (!$c) { + return; + } + if ($title === '' && $tag === 'title') { + $title = $c; + } + if ($lead === '' && $tag === 'lead') { + $lead = $c; + } + $m = $markupMap[$tag] ?? $tag; + $e = explode('.', $m); + $markup = $e[0]; + $attrs = $dirattr; + if (count($e) === 2) { + $attrs .= ' class="' . $e[1] . '"'; + } + if ($m === 'a') { + $attrs .= ' target="_blank"'; + } + foreach ($child->attributes() as $name => $v) { + $n = $attrsmap[$m][$name] ?? $name; + $attrs .= ' ' . $n . '="' . htmlspecialchars($v) . '"'; + } + $res .= '<' . $markup . $attrs . '>' . $c . ''; + } + return $res; + } + + public static function getPhonegapVersion($v = 'latest') + { + if ($v != 'latest') { + return $v; + } + + $versions = self::getPhonegapVersions(); + return array_pop($versions); + } + + public static function getPhonegapVersions() + { + $versions = array(); + $phonegap_dir = resource_path('fluidbookpublication/phonegap'); + + if (is_dir($phonegap_dir)) { + $dr = opendir($phonegap_dir); + while ($file = readdir($dr)) { + if ($file == '.' || $file == '..' || $file == 'plugins') { + continue; + } + $versions[] = $file; + } + usort($versions, 'version_compare'); + } + + return $versions; + } + + public static function getSourcesPath($version, $dir = null) + { + $res = self::getFluidbookPlayerBaseDirectory(); + if (null !== $dir) { + $res .= $dir . '/'; + } + if ($version === 'stable') { + $res .= 'branches/master'; + } else if ($version === 'dev') { + $res .= 'local/master'; + } else { + list($branch, $location) = explode('|', $version); + $res .= ($location === 'git' ? 'branches' : $location) . '/' . $branch; + } + return $res; + } + + public static function getCompiledSourcesPath($version) + { + return self::getSourcesPath($version, 'compiled'); + } + + public function source_path($path = ''): string + { + $res = $this->assets; + if ($path) { + $res .= '/' . $path; + } + return $res; + } + + public function page_path($page, $path = ''): string + { + return ''; + } + + public function getPagePDFSource($page): string + { + return $this->getFluidbook()->getPDFSplitSource($page); + } + + public function getWidthForLinks() + { + return $this->getWidth() / $this->getLinkScale(); + } + + public function getHeightForLinks() + { + return $this->getHeight() / $this->getLinkScale(); + } +} diff --git a/app/Fluidbook/Compiler/Links.php b/app/Fluidbook/Compiler/Links.php new file mode 100644 index 000000000..bca5aeb99 --- /dev/null +++ b/app/Fluidbook/Compiler/Links.php @@ -0,0 +1,394 @@ +book_id, $links, $rulers, 'latest', true); + } + + /** + * @throws \SodiumException + */ + protected function writeLinks() + { + + switch ($this->fluidbookSettings->customLinkClass) { + case 'WescoSalesLink': + $this->specialJsFiles[] = 'js/libs/interact.min.js'; + $this->specialJsFiles[] = 'js/libs/fluidbook/special/wescosales.js'; + $this->specialCSS[] = 'wescosales'; + break; + case 'AtlanticDownloadLink': + $this->specialJsFiles[] = 'js/libs/fluidbook/special/atlanticdownload.js'; + $this->specialCSS[] = 'atlanticdownload'; + break; + case 'MiraklEaster2021': + $this->specialJsFiles[] = 'js/libs/fluidbook/special/mirakleaster2021.js'; + $this->specialCSS[] = 'mirakleaster2021'; + break; + } + + $this->config->links = array(); + $this->config->clinks = array(); + $this->config->bookmarkGroups = array(); + + $ignore = $this->fluidbookSettings->ignoreLinksTypes; + if (!$ignore) { + $ignore = array(); + } else { + $ignore = explode(',', $ignore); + } + + 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->width = $meta['width']; + $this->config->externalChaptersSize->height = $meta['height']; + $this->vdir->copyDirectory($d['dir'], $d['fdir']); + } + + $this->getLinksAndRulers($links, $rulers); + $this->_fluidbook->normalizeLinks($links); + + if ($this->fluidbookSettings->basketManager === 'Puma') { + foreach ($links as $k => $init) { + if ($init['type'] == Link::CART && isset($this->config->product_zoom_references[$init['to']]) && count($this->config->product_zoom_references[$init['to']]) > 0 && implode('', $this->config->product_zoom_references[$init['to']]) != '') { + $init['infobulle'] = 'Digital information'; + $init['animation'] = 'reflet-anim.html'; + $links[$k] = $init; + } + if ($init['type'] == Link::CUSTOM) { + $init['image'] = ''; + $init['display_area'] = false; + $links[$k] = $init; + } + } + + } + + // Custom landing page content + if ($this->fluidbookSettings->landingPage != '') { + $d = $this->unzipFile($this->fluidbookSettings->landingPage, false, 'data/landing-page/'); + $this->vdir->copyDirectory($d['dir'], $d['fdir']); + } + + if ($this->fluidbookSettings->tabsHTML5 != '' && file_exists($this->wdir . '/' . $this->fluidbookSettings->tabsHTML5)) { + $ext = Files::getExtension($this->fluidbookSettings->tabsHTML5); + if ($ext === 'zip') { + $links['tabs'] = [ + 'page' => 'background', + 'top' => 0, + 'left' => 0, + 'width' => 100, + 'height' => 100, + 'type' => Link::MULTIMEDIA, + 'to' => $this->fluidbookSettings->tabsHTML5, + 'image' => '', + 'inline' => 1, + 'interactive' => 1, + 'class' => 'tabslink', + 'uid' => 'tabs', + ]; + } else if ($ext === 'svg') { + $this->vdir->copy($this->wdir . '/' . $this->fluidbookSettings->tabsHTML5, 'data/tabs.svg'); + $this->config->svgTabs = true; + $pagesLists = ['tabsPages', 'tabsSections']; + + foreach ($pagesLists as $pagesList) { + $e = explode(',', $this->fluidbookSettings->$pagesList); + $list = []; + foreach ($e as $k => $v) { + $v = trim($v); + if ($v === '') { + continue; + } + if ($v !== '-') { + if ($this->fluidbookSettings->tabsPagesNumbers === 'virtual') { + $v = $this->virtualToPhysical($v); + } + } + $list[] = $v; + } + $this->config->$pagesList = $list; + } + } + } + + $pagesOfCustomLinks = []; + $hiddenLinks = []; + $anchorExists = []; + $closedLinks = []; + + $linksCopy = $links; + + + foreach ($linksCopy as $k => $linkData) { + if ($this->fluidbookSettings->PDFRendererIframe === 'svg' && (($linkData['type'] == Link::IFRAME && stristr($linkData['to'], '.pdf')) || ($linkData['type'] == Link::MULTIMEDIA && stristr($linkData['alternative'], '.pdf')))) { + $ofile = $this->wdir . '/' . $linkData['to']; + $dfile = $this->wdir . '/' . $linkData['to'] . '.svg'; + if (!file_exists($dfile) || filemtime($dfile) < filemtime($ofile)) { + $cmd = "pdftocairo -svg -f 1 -l 1 $ofile $dfile"; + `$cmd`; + } + $linkData['type'] = Link::MULTIMEDIA; + $linkData['to'] = $linkData['to'] . '.svg'; + $linkData['backgroundColor'] = '#fff'; + $links[$k] = $linkData; + } + if ($linkData['type'] == Link::PAGE_LABEL || $linkData == Link::ANCHOR) { + $linkData['to'] = AnchorLink::normalizeAnchor($linkData['to']); + $anchorExists[$linkData['to']] = $linkData; + } + if ($linkData['type'] == Link::TEXT || $linkData['type'] == Link::IMAGE || $linkData['type'] == Link::LAYER) { + $linkData = Link::decryptLink($linkData); + $animations = ContentLink::parseAnimations($linkData['image_rollover']); + foreach ($animations as $animation) { + if (isset($animation['backgroundcolor']) && $animation['backgroundcolor'] !== 'transparent') { + $dupData = $linkData; + $dupData['type'] = Link::COLOR; + $dupData['to'] = $animation['backgroundcolor']; + + $dupData['uid'] = 'b_' . $linkData['uid']; + $dupData['addzindex'] = -1; + $dupData['image_rollover'] = ''; + array_push($links, $dupData); + array_push($links, $linkData); + unset($links[$k]); + } + } + } + if (isset($linkData['image']) && $linkData['image'] && $linkData['type'] != Link::ARTICLE && $linkData['type'] != Link::TEXT && $linkData['type'] != Link::COLOR) { + $dupData = $linkData; + $dupData['image'] = ''; + $dupData['animation'] = ''; + $dupData['to'] = self::_SVGCleanAsset($linkData['image']); + if ($dupData['image_rollover'] != 'none' && !stristr($dupData['image_rollover'], '=')) { + $dupData['rollover'] = $dupData['image_rollover']; + } + $dupData['image_rollover'] = ''; + $dupData['type'] = Link::IMAGE; + $dupData['uid'] = 'i_' . $linkData['uid']; + if (Link::isScorm($linkData)) { + $dupData['scorm'] = true; + } + array_push($links, $dupData); + } + if (isset($linkData['animation']) && $linkData['animation']) { + $dupData = $linkData; + $dupData['image'] = ''; + $dupData['animation'] = ''; + $dupData['inline'] = true; + $dupData['interactive'] = false; + $dupData['to'] = $linkData['animation']; + $dupData['type'] = Link::MULTIMEDIA; + $linkData['relatedAnimation'] = $dupData['uid'] = 'a_' . $linkData['uid']; + $dupData['video_width'] = $dupData['video_height'] = 0; + if (Link::isScorm($linkData)) { + $dupData['scorm'] = true; + } + $links[$k] = $linkData; + array_push($links, $dupData); + } + if ($linkData['type'] == Link::CUSTOM) { + $k = $linkData['to']; + $e = explode(':', $k); + if (count($e) > 1) { + $k = $e[1]; + } + if (!isset($pagesOfCustomLinks[$k])) { + $pagesOfCustomLinks[$k] = []; + } + if (!in_array($linkData['page'], $pagesOfCustomLinks[$k])) { + $pagesOfCustomLinks[$k][] = $linkData['page']; + } + } + + if ($linkData['type'] == Link::SHOWLINK && $linkData['target'] !== 'hide') { + $ids = explode(',', $linkData['to']); + $close = ($linkData['video_service'] && $linkData['video_service'] !== 'none'); + foreach ($ids as $id) { + $id = trim($id); + if ($id === 'tabs') { + $this->config->tabsHiddenAtStartup = true; + } else { + if ($close) { + $closedLinks[] = $id; + $closedLinks[] = 'i_' . $id; + } + $hiddenLinks[] = $id; + $hiddenLinks[] = 'i_' . $id; + } + } + } + } + + if ($this->fluidbookSettings->anchorsAliases && file_exists($this->fluidbookSettings->anchorsAliases)) { + $aliases = []; + for ($i = 0; $i <= 2; $i++) { + $lines = Text::explodeNewLines(file_get_contents($this->fluidbookSettings->anchorsAliases)); + foreach ($lines as $line) { + $e = explode("\t", $line); + $from = AnchorLink::normalizeAnchor($e[0]); + $to = AnchorLink::normalizeAnchor($e[1]); + $aliases[$from] = $to; + if (is_numeric($to) && !isset($anchorExists[$from])) { + $anchor = [ + 'page' => $to, + 'top' => 0, + 'left' => 0, + 'width' => 100, + 'height' => 100, + 'type' => 26, + 'to' => $from, + 'uid' => LinksData::generateUID() + ]; + $anchorExists[$from] = $anchor; + $links[] = $anchor; + } else { + if (!isset($anchorExists[$from]) && isset($anchorExists[$to])) { + $anchor = $anchorExists[$to]; + $anchor['to'] = $from; + $anchor['uid'] = LinksData::generateUID(); + $anchorExists[$from] = $anchor; + $links[] = $anchor; + } + } + } + } + } + + + $this->config->pagesOfCustomLinks = $pagesOfCustomLinks; + + $i = 1; + $pages = array(); + $cpages = array(); + $ctpages = array(); + $css = array(); + $linkPages = []; + $allLinksData = []; + $gamifyCoins = []; + + usort($links, array($this, '_sortLinks')); + + foreach ($links as $linkData) { + if (in_array($linkData['type'], $ignore)) { + continue; + } + if ($linkData['uid'] === 'slider') { + $linkData['page'] = 'background'; + } + + $linkData['hidden'] = in_array($linkData['uid'], $hiddenLinks); + if (isset($linkData['zindex']) && $linkData['zindex'] < 50 && in_array($linkData['uid'], $closedLinks)) { + $linkData['zindex'] = 50; + } + if ($linkData['type'] == Link::ARTICLE) { + $this->addSEOArticle('#/page/' . $linkData['page'], $linkData['to'], $linkData['extra'], $linkData['image']); + continue; + } + + $link = Link::getInstance($this->base62($i), $linkData, $this); + if (is_null($link) || $link->ignore()) { + continue; + } + + $linksToAdd = [$link]; + if ($link->overlapDoublePage() && !$this->isOnePage()) { + $linksToAdd[] = $link->getRightClone(); + } + + foreach ($linksToAdd as $lta) { + try { + /** @var $lta Link */ + // Keep this line because some properties of the link (like blend mode) are parsed with this function + $c = $lta->getHTMLContainer(); + + + $css[] = $lta->getCSSContainer(); + if (!isset($pages[$lta->page])) { + $pages[$lta->page] = ['normal' => []]; + $cpages[$lta->page] = ['normal' => []]; + $ctpages[$lta->page] = ['normal' => []]; + } + + + $d = $lta->getDepth(); + if ($d < 30) { + $v = 'ctpages'; + } else if ($d < 50) { + $v = 'cpages'; + } else { + $v = 'pages'; + } + + $lta->setInitialOrder($i); + if (!isset($$v[$lta->page][$lta->blendmode])) { + $$v[$lta->page][$lta->blendmode] = []; + } + + array_push($$v[$lta->page][$lta->blendmode], $lta); + $i++; + } catch (\Exception $e) { + $this->triggerLinkError($e, $lta); + } + } + + + // Make old "aftersearch" link compatible with new "extra" menu option by extracting link URL + if ($link->page == 'aftersearch') { + $this->config->afterSearchLink = $link->to; + $this->config->afterSearchTooltip = $link->infobulle; + } + + if (strpos($link->page, 'link_') === 0) { + $linkPages[$link->page] = true; + } + + if ($link->gamifyCoins) { + $gamifyCoins[$linkData['uid']] = $link->gamifyCoins; + } + + $allLinksData[$linkData['uid']] = $linkData; + + if ($link->keep()) { + $this->hiddenContents[] = $link->getHTMLContainer(); + } + } + + $allpages = range(0, $this->getFluidbook()->getPagesNumber() + 1); + if ($this->fluidbookSettings->themeEnableAfterSearch) { + $allpages[] = 'aftersearch'; + } + $allpages[] = 'background'; + $allpages[] = 'archives'; + $allpages[] = 'slider'; + foreach ($linkPages as $linkPage => $true) { + $allpages[] = $linkPage; + } + + foreach ($allpages as $i) { + $this->config->set('links.' . $i, $this->_htmlLinkList($pages[$i] ?? [])); + $this->config->set('clinks.' . $i, $this->_htmlLinkList($cpages[$i] ?? [])); + $this->config->set('ctlinks.' . $i, $this->_htmlLinkList($ctpages[$i] ?? [])); + } + + if ($this->writeLinksData) { + $this->config->linksData = $allLinksData; + } + $this->config->gamifyCoins = $gamifyCoins; + + return $css; + } +} diff --git a/app/Fluidbook/Link/Custom/InpesPopinLink.php b/app/Fluidbook/Link/Custom/InpesPopinLink.php index 2f2a6806d..b7077f70a 100644 --- a/app/Fluidbook/Link/Custom/InpesPopinLink.php +++ b/app/Fluidbook/Link/Custom/InpesPopinLink.php @@ -2,7 +2,7 @@ namespace App\Fluidbook\Link\Custom; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use Fluidbook\Tools\Links\HTMLMultimediaLink; class InpesPopinLink extends HTMLMultimediaLink diff --git a/app/Fluidbook/Link/LinksData.php b/app/Fluidbook/Link/LinksData.php new file mode 100644 index 000000000..515848847 --- /dev/null +++ b/app/Fluidbook/Link/LinksData.php @@ -0,0 +1,596 @@ + 'youtube', 1 => 'dailymotion', 2 => 'vimeo', 3 => 'brightcove', 'none' => 'youtube']; + + /** + * @throws Exception + */ + 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'), + 'close_button' => __('Bouton de fermeture'), + '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'), + 'pdfjs' => __('Mode PDFJS'), + ); + + $comments = array(); + + $xls = new Spreadsheet(); + $s = $xls->setActiveSheetIndex(0); + $s->setTitle('Links'); + + // Labels + $i = 1; + foreach ($cols as $id => $label) { + $s->setCellValueByColumnAndRow($i, 1, $id); + $s->getColumnDimensionByColumn($i)->setAutoSize(true); + $s->getStyleByColumnAndRow($i, 1)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + $i++; + } + + // Links + self::_fixWebVideoServices($links); + $j = 2; + foreach ($links as $l) { + $i = 1; + 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(DataType::TYPE_STRING)->getStyle()->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT); + } + $value = $l[$id]; + } else { + $value = ''; + } + } + + $s->setCellValueExplicitByColumnAndRow($i, $j, $value, DataType::TYPE_STRING); + $i++; + } + $j++; + } + // Rulers + $s = $xls->createSheet(); + $s->setTitle('Rulers'); + + $rcols = array('page', 'type', 'pos'); + $i = 1; + // Labels + foreach ($rcols as $id) { + $s->setCellValueByColumnAndRow($i, 1, $id); + $s->getColumnDimensionByColumn($i)->setAutoSize(true); + $i++; + } + + // Contents + $j = 2; + foreach ($rulers as $r) { + $i = 1; + 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(Alignment::HORIZONTAL_LEFT); + $i++; + } + $j++; + } + + $xls->setActiveSheetIndex(0); + return $xls; + } + + + public static function getLinksAndRulers($book_id, &$links, &$rulers, $time = 'latest', $forceDecrypt = false) + { + if (null === $time) { + $time = 'latest'; + } + $dir = self::getLinksDir($book_id); + + $versions = self::getLinksVersions($book_id); + + $file = Files::firstThatExists($dir . '/' . $time . '.links3.gz', $dir . '/' . $time . '.links.gz'); + $metafile = Files::firstThatExists($dir . '/' . $time . '.meta3.gz', $dir . '/' . $time . '.meta.gz'); + if ($time === 'latest' && !file_exists($file)) { + + foreach ($versions as $version => $m) { + $lf = Files::firstThatExists($dir . '/' . $version . '.links3.gz', $dir . '/' . $version . '.links.gz'); + $mf = Files::firstThatExists($dir . '/' . $version . '.meta3.gz', $dir . '/' . $version . '.meta.gz'); + if (!file_exists($lf) || !file_exists($mf)) { + continue; + } + copy($lf, $dir . '/latest.links3.gz'); + copy($mf, $dir . '/latest.meta3.gz'); + break; + } + } + if (!file_exists($file)) { + $links = []; + $rulers = []; + return; + } + + $r = self::_decodegzfile($file); + $meta = array_merge(['version' => 2, 'onepage' => false], self::_decodegzfile($metafile)); + + /** @var FluidbookPublication $fluidbook */ + $fluidbook = FluidbookPublication::find($book_id); + if ($fluidbook->isOnePage() && !$meta['onepage']) { + self::_moveToOnePageLinks($r['links'], $r['rulers'], $fluidbook); + } + + $links = self::_UID($r['links']); + $rulers = self::_UID($r['rulers']); + + if ($forceDecrypt || can('fluidbook-publication:links:edit-animations')) { + $links = Link::decryptLinks($links); + } else { + $links = Link::encryptLinks($links); + } + + self::_fixLinks($links); + } + + protected static function _decodegzfile($file) + { + return json_decode(gzdecode(file_get_contents($file)), true); + } + + /** + * @param $links array[] + * @param $rulers array[] + * @param $fluidbook FluidbookPublication + * @return void + */ + public static function _moveToOnePageLinks(&$links, &$rulers, $fluidbook) + { + $w = $fluidbook->getPageWidth(); + foreach ($links as $k => $link) { + // Si le lien est totalement hors de la page à droite, on le déplace à la page suivante + if ($link['left'] > $w) { + $link['left'] -= $w; + $link['page']++; + } + // Si le lien est totalement hors de la page à gauche, on le déplace à la page précédente + if ($link['left'] + $link['width'] < 0) { + $link['left'] += $w; + $link['page']--; + } + // Si le lien dépasse à droite, on le déplace à la page suivante si la surface qui dépasse est supérieure à 50% de la surface du lien + if ($link['left'] < $w && $link['left'] + $link['width'] > $w && ($w - $link['left']) < ($link['width'] / 2)) { + $link['left'] -= $w; + $link['page']++; + } + // Si le lien dépasse à gauche, on le déplace à la page précédente si la surface qui dépasse est supérieure à 50% de la surface du lien + if ($link['left'] < 0 && $link['left'] < ($link['width'] / -2)) { + $link['left'] += $w; + $link['page']--; + } + + $links[$k] = $link; + } + } + + protected static function _UID($items) + { + $res = []; + foreach ($items as $item) { + if (!isset($item['uid'])) { + $item['uid'] = self::uid(); + } + $res[$item['uid']] = $item; + } + return $res; + } + + protected static function uid() + { + return Str::lower(Str::random(12)); + } + + protected static function _fixLinks(&$links) + { + self::_correctImageSpecialLinks($links); + self::_fixWebVideoServices($links); + self::_fixMultimedia($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['to']) { + $links[$k]['page'] = 'link_' . md5($l['to']); + break; + } + } + } else if (preg_match('/^([0-9a-f]{32})$/', $link['page'], $matches)) { + $links[$k]['page'] = 'link_' . $matches[1]; + } + } + } + + protected static function _fixWebVideoServices(&$links) + { + foreach ($links as $k => $link) { + if ($link['type'] == 10) { + if (!isset($link['video_service'])) { + $links[$k]['video_service'] = $link['video_service'] = 0; + } + if (is_numeric($link['video_service'])) { + $links[$k]['video_service'] = self::$_webvideoServicesMap[$link['video_service']]; + } + } + } + } + + protected static function _fixMultimedia(&$links) + { + foreach ($links as $k => $link) { + if (isset($link['video_width'], $link['video_height']) && $link['video_width'] == 320 & $link['video_height'] == 240) { + $links[$k]['video_width'] = $links[$k]['video_height'] = ''; + } + if (isset($link['alternative']) && $link['alternative'] && $link['type'] == 6) { + $links[$k]['to'] = $link['alternative']; + unset($links[$k]['alternative']); + } + } + } + + /** + * @param $xls Spreadsheet + * @param $links [] + * @param $rulers [] + * @return void + */ + public static function getLinksFromExcel($xls, &$links, &$rulers) + { + + $rulers = array(); + $links = array(); + + if ($xls->getSheetCount() === 1) { + $s = $xls->setActiveSheetIndex(0); + } else { + try { + $s = $xls->setActiveSheetIndexByName('Links'); + } catch (\Exception $e) { + throw new \Exception(__('Format du fichier Excel invalide (pas de feuille nommée :name)', ['name' => 'Links'])); + } + } + $i = 0; + + 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++; + } + self::_fixLinks($links); + + + if ($xls->getSheetCount() === 1) { + return; + } + $i = 0; + try { + $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 { + $j = 0; + foreach ($cellIterator as $cell) { + $ruler[$cols[$j]] = $cell->getValue(); + $j++; + } + + $rulers[] = $ruler; + } + $i++; + } + } catch (\Exception $e) { + + } + } + + 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::_fixLinks($links); + } + + public static function saveLinksInFile($book_id, $user_id, $comments, $links, $rulers = [], $specialLinks = [], $specialRulers = []) + { + /** @var FluidbookPublication $fluidbook */ + $fluidbook = FluidbookPublication::find($book_id); + + $lr = self::mergeLinksAndRulers($links, $rulers, $specialLinks, $specialRulers); + $meta = ['links' => count($lr['links']), 'rulers' => count($lr['rulers']), 'comments' => $comments, 'user' => $user_id, 'version' => 3, 'onepage' => $fluidbook->isOnePage()]; + $base = self::getLinksDir($book_id) . '/' . time(); + $latestLinks = self::getLinksDir($book_id) . '/latest.links3.gz'; + $latestMeta = self::getLinksDir($book_id) . '/latest.meta3.gz'; + file_put_contents($base . '.meta3.gz', gzencode(json_encode($meta))); + file_put_contents($base . '.links3.gz', gzencode(json_encode($lr))); + copy($base . '.links3.gz', $latestLinks); + copy($base . '.meta3.gz', $latestMeta); + } + + + public static function getLinksDir($book_id) + { + return Files::mkdir(protected_path('fluidbookpublication/links/' . $book_id)); + } + + public static function getLinksVersions($book_id) + { + $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[1] !== 'meta3.gz') || $e[0] === 'latest') { + continue; + } + + $updates[$e[0]] = self::getMeta($book_id, $e[0]); + } + krsort($updates); + if (!count($updates)) { + LinksData::addLinksFromPDF($book_id); + return self::getLinksVersions($book_id); + } + + + $res = []; + foreach ($updates as $timestamp => $u) { + try { + $u['name'] = User::find($u['user'])->name; + } catch (\Exception $e) { + $u['name'] = '-'; + } + $u['date'] = date('Y-m-d H:i:s', $timestamp); + $u['timestamp'] = $timestamp; + $res[] = $u; + } + + return $res; + } + + public static function getMeta($book_id, $update = 'latest') + { + return json_decode(gzdecode(file_get_contents(Files::firstThatExists(self::getLinksDir($book_id) . '/' . $update . '.meta3.gz', 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)); + + $k = 0; + foreach ($l as $item) { + $item['id'] = $k + 1; + if (!isset($item['to'])) { + $item['to'] = ''; + } + $finalLinks[] = $item; + $k++; + } + + self::_fixLinks($finalLinks); + + return ['links' => Link::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) + { + /** @var FluidbookPublication $book */ + $book = FluidbookPublication::find($book_id); + + $booleans = array('video_loop', 'video_auto_start', 'video_controls', 'video_sound_on'); + $numbers = ['left', 'top', 'width', 'height']; + + $links = []; + foreach ($book->composition as $page => $doc) { + $fp = Gzip::fopen($book->getDocument($page)->path('links/p' . $doc[1] . '.csv')); + while (true) { + $line = fgetcsv($fp, 512, ';', '"'); + // End of file + if (!$line) { + break; + } + + // Commentaire || ligne vide + if (str_starts_with($line[0], '#') || is_null($line[0])) { + continue; + } + + $link = []; + $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, 'pdfjs' => 'normal'); + $k = 0; + foreach ($cols as $col => $default) { + if (isset($line[$k])) { + if (in_array($col, $numbers)) { + $link[$col] = (float)str_replace(',', '.', $line[$k]); + } else if (in_array($col, $booleans)) { + $link[$col] = ($line[$k] == '1'); + } else { + $link[$col] = $line[$k]; + } + } else { + $link[$col] = $default; + } + $k++; + } + + if ($link['type'] == 18) { + $link['infobulle'] = $link['to']; + $link['to'] = ''; + } + + $webvideo = WebVideo::parse($link['to'], true); + if ($webvideo !== false) { + $link['type'] = '10'; + $link['video_service'] = $webvideo['service']; + $link['inline'] = 'popup'; + $link['to'] = $webvideo['id']; + } + + $link['display_area'] = '1'; + $link['page'] = $page; + $link['uid'] = self::generateUID(); + $links[] = $link; + } + fclose($fp); + } + + self::saveLinksInFile($book_id, backpack_user() ? backpack_user()->id : 0, 'Links imported from PDF', $links); + } + + public static function getLinksAndRulersFromExcelFile($path, &$links, &$rulers) + { + $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); + $xls = $reader->load($path); + LinksData::getLinksFromExcel($xls, $links, $rulers); + } + + public static function generateUID() + { + $characters = '0123456789abcdefghijklmnopqrstuvwxyz'; + $randstring = ''; + for ($i = 0; $i < 12; $i++) { + $randstring .= $characters[rand(0, 35)]; + } + return $randstring; + } + + public static function copy($source, $dest, $sourceVersion = 'latest') + { + self::getLinksAndRulers($source, $links, $rulers, $sourceVersion); + self::saveLinksInFile($dest, backpack_user()->id, __('Copier les liens à partir du fluidbook :fluidbook', ['fluidbook' => $source]), $links, $rulers); + } +} diff --git a/app/Fluidbook/Links.php b/app/Fluidbook/Links.php deleted file mode 100644 index 7491afea1..000000000 --- a/app/Fluidbook/Links.php +++ /dev/null @@ -1,596 +0,0 @@ - 'youtube', 1 => 'dailymotion', 2 => 'vimeo', 3 => 'brightcove', 'none' => 'youtube']; - - /** - * @throws Exception - */ - 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'), - 'close_button' => __('Bouton de fermeture'), - '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'), - 'pdfjs' => __('Mode PDFJS'), - ); - - $comments = array(); - - $xls = new Spreadsheet(); - $s = $xls->setActiveSheetIndex(0); - $s->setTitle('Links'); - - // Labels - $i = 1; - foreach ($cols as $id => $label) { - $s->setCellValueByColumnAndRow($i, 1, $id); - $s->getColumnDimensionByColumn($i)->setAutoSize(true); - $s->getStyleByColumnAndRow($i, 1)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $i++; - } - - // Links - self::_fixWebVideoServices($links); - $j = 2; - foreach ($links as $l) { - $i = 1; - 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(DataType::TYPE_STRING)->getStyle()->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT); - } - $value = $l[$id]; - } else { - $value = ''; - } - } - - $s->setCellValueExplicitByColumnAndRow($i, $j, $value, DataType::TYPE_STRING); - $i++; - } - $j++; - } - // Rulers - $s = $xls->createSheet(); - $s->setTitle('Rulers'); - - $rcols = array('page', 'type', 'pos'); - $i = 1; - // Labels - foreach ($rcols as $id) { - $s->setCellValueByColumnAndRow($i, 1, $id); - $s->getColumnDimensionByColumn($i)->setAutoSize(true); - $i++; - } - - // Contents - $j = 2; - foreach ($rulers as $r) { - $i = 1; - 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(Alignment::HORIZONTAL_LEFT); - $i++; - } - $j++; - } - - $xls->setActiveSheetIndex(0); - return $xls; - } - - - public static function getLinksAndRulers($book_id, &$links, &$rulers, $time = 'latest', $forceDecrypt = false) - { - if (null === $time) { - $time = 'latest'; - } - $dir = self::getLinksDir($book_id); - - $versions = self::getLinksVersions($book_id); - - $file = Files::firstThatExists($dir . '/' . $time . '.links3.gz', $dir . '/' . $time . '.links.gz'); - $metafile = Files::firstThatExists($dir . '/' . $time . '.meta3.gz', $dir . '/' . $time . '.meta.gz'); - if ($time === 'latest' && !file_exists($file)) { - - foreach ($versions as $version => $m) { - $lf = Files::firstThatExists($dir . '/' . $version . '.links3.gz', $dir . '/' . $version . '.links.gz'); - $mf = Files::firstThatExists($dir . '/' . $version . '.meta3.gz', $dir . '/' . $version . '.meta.gz'); - if (!file_exists($lf) || !file_exists($mf)) { - continue; - } - copy($lf, $dir . '/latest.links3.gz'); - copy($mf, $dir . '/latest.meta3.gz'); - break; - } - } - if (!file_exists($file)) { - $links = []; - $rulers = []; - return; - } - - $r = self::_decodegzfile($file); - $meta = array_merge(['version' => 2, 'onepage' => false], self::_decodegzfile($metafile)); - - /** @var FluidbookPublication $fluidbook */ - $fluidbook = FluidbookPublication::find($book_id); - if ($fluidbook->isOnePage() && !$meta['onepage']) { - self::_moveToOnePageLinks($r['links'], $r['rulers'], $fluidbook); - } - - $links = self::_UID($r['links']); - $rulers = self::_UID($r['rulers']); - - if ($forceDecrypt || can('fluidbook-publication:links:edit-animations')) { - $links = Link::decryptLinks($links); - } else { - $links = Link::encryptLinks($links); - } - - self::_fixLinks($links); - } - - protected static function _decodegzfile($file) - { - return json_decode(gzdecode(file_get_contents($file)), true); - } - - /** - * @param $links array[] - * @param $rulers array[] - * @param $fluidbook FluidbookPublication - * @return void - */ - public static function _moveToOnePageLinks(&$links, &$rulers, $fluidbook) - { - $w = $fluidbook->getPageWidth(); - foreach ($links as $k => $link) { - // Si le lien est totalement hors de la page à droite, on le déplace à la page suivante - if ($link['left'] > $w) { - $link['left'] -= $w; - $link['page']++; - } - // Si le lien est totalement hors de la page à gauche, on le déplace à la page précédente - if ($link['left'] + $link['width'] < 0) { - $link['left'] += $w; - $link['page']--; - } - // Si le lien dépasse à droite, on le déplace à la page suivante si la surface qui dépasse est supérieure à 50% de la surface du lien - if ($link['left'] < $w && $link['left'] + $link['width'] > $w && ($w - $link['left']) < ($link['width'] / 2)) { - $link['left'] -= $w; - $link['page']++; - } - // Si le lien dépasse à gauche, on le déplace à la page précédente si la surface qui dépasse est supérieure à 50% de la surface du lien - if ($link['left'] < 0 && $link['left'] < ($link['width'] / -2)) { - $link['left'] += $w; - $link['page']--; - } - - $links[$k] = $link; - } - } - - protected static function _UID($items) - { - $res = []; - foreach ($items as $item) { - if (!isset($item['uid'])) { - $item['uid'] = self::uid(); - } - $res[$item['uid']] = $item; - } - return $res; - } - - protected static function uid() - { - return Str::lower(Str::random(12)); - } - - protected static function _fixLinks(&$links) - { - self::_correctImageSpecialLinks($links); - self::_fixWebVideoServices($links); - self::_fixMultimedia($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['to']) { - $links[$k]['page'] = 'link_' . md5($l['to']); - break; - } - } - } else if (preg_match('/^([0-9a-f]{32})$/', $link['page'], $matches)) { - $links[$k]['page'] = 'link_' . $matches[1]; - } - } - } - - protected static function _fixWebVideoServices(&$links) - { - foreach ($links as $k => $link) { - if ($link['type'] == 10) { - if (!isset($link['video_service'])) { - $links[$k]['video_service'] = $link['video_service'] = 0; - } - if (is_numeric($link['video_service'])) { - $links[$k]['video_service'] = self::$_webvideoServicesMap[$link['video_service']]; - } - } - } - } - - protected static function _fixMultimedia(&$links) - { - foreach ($links as $k => $link) { - if (isset($link['video_width'], $link['video_height']) && $link['video_width'] == 320 & $link['video_height'] == 240) { - $links[$k]['video_width'] = $links[$k]['video_height'] = ''; - } - if (isset($link['alternative']) && $link['alternative'] && $link['type'] == 6) { - $links[$k]['to'] = $link['alternative']; - unset($links[$k]['alternative']); - } - } - } - - /** - * @param $xls Spreadsheet - * @param $links [] - * @param $rulers [] - * @return void - */ - public static function getLinksFromExcel($xls, &$links, &$rulers) - { - - $rulers = array(); - $links = array(); - - if ($xls->getSheetCount() === 1) { - $s = $xls->setActiveSheetIndex(0); - } else { - try { - $s = $xls->setActiveSheetIndexByName('Links'); - } catch (\Exception $e) { - throw new \Exception(__('Format du fichier Excel invalide (pas de feuille nommée :name)', ['name' => 'Links'])); - } - } - $i = 0; - - 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++; - } - self::_fixLinks($links); - - - if ($xls->getSheetCount() === 1) { - return; - } - $i = 0; - try { - $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 { - $j = 0; - foreach ($cellIterator as $cell) { - $ruler[$cols[$j]] = $cell->getValue(); - $j++; - } - - $rulers[] = $ruler; - } - $i++; - } - } catch (\Exception $e) { - - } - } - - 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::_fixLinks($links); - } - - public static function saveLinksInFile($book_id, $user_id, $comments, $links, $rulers = [], $specialLinks = [], $specialRulers = []) - { - /** @var FluidbookPublication $fluidbook */ - $fluidbook = FluidbookPublication::find($book_id); - - $lr = self::mergeLinksAndRulers($links, $rulers, $specialLinks, $specialRulers); - $meta = ['links' => count($lr['links']), 'rulers' => count($lr['rulers']), 'comments' => $comments, 'user' => $user_id, 'version' => 3, 'onepage' => $fluidbook->isOnePage()]; - $base = self::getLinksDir($book_id) . '/' . time(); - $latestLinks = self::getLinksDir($book_id) . '/latest.links3.gz'; - $latestMeta = self::getLinksDir($book_id) . '/latest.meta3.gz'; - file_put_contents($base . '.meta3.gz', gzencode(json_encode($meta))); - file_put_contents($base . '.links3.gz', gzencode(json_encode($lr))); - copy($base . '.links3.gz', $latestLinks); - copy($base . '.meta3.gz', $latestMeta); - } - - - public static function getLinksDir($book_id) - { - return Files::mkdir(protected_path('fluidbookpublication/links/' . $book_id)); - } - - public static function getLinksVersions($book_id) - { - $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[1] !== 'meta3.gz') || $e[0] === 'latest') { - continue; - } - - $updates[$e[0]] = self::getMeta($book_id, $e[0]); - } - krsort($updates); - if (!count($updates)) { - Links::addLinksFromPDF($book_id); - return self::getLinksVersions($book_id); - } - - - $res = []; - foreach ($updates as $timestamp => $u) { - try { - $u['name'] = User::find($u['user'])->name; - } catch (\Exception $e) { - $u['name'] = '-'; - } - $u['date'] = date('Y-m-d H:i:s', $timestamp); - $u['timestamp'] = $timestamp; - $res[] = $u; - } - - return $res; - } - - public static function getMeta($book_id, $update = 'latest') - { - return json_decode(gzdecode(file_get_contents(Files::firstThatExists(self::getLinksDir($book_id) . '/' . $update . '.meta3.gz', 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)); - - $k = 0; - foreach ($l as $item) { - $item['id'] = $k + 1; - if (!isset($item['to'])) { - $item['to'] = ''; - } - $finalLinks[] = $item; - $k++; - } - - self::_fixLinks($finalLinks); - - return ['links' => Link::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) - { - /** @var FluidbookPublication $book */ - $book = FluidbookPublication::find($book_id); - - $booleans = array('video_loop', 'video_auto_start', 'video_controls', 'video_sound_on'); - $numbers = ['left', 'top', 'width', 'height']; - - $links = []; - foreach ($book->composition as $page => $doc) { - $fp = Gzip::fopen($book->getDocument($page)->path('links/p' . $doc[1] . '.csv')); - while (true) { - $line = fgetcsv($fp, 512, ';', '"'); - // End of file - if (!$line) { - break; - } - - // Commentaire || ligne vide - if (str_starts_with($line[0], '#') || is_null($line[0])) { - continue; - } - - $link = []; - $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, 'pdfjs' => 'normal'); - $k = 0; - foreach ($cols as $col => $default) { - if (isset($line[$k])) { - if (in_array($col, $numbers)) { - $link[$col] = (float)str_replace(',', '.', $line[$k]); - } else if (in_array($col, $booleans)) { - $link[$col] = ($line[$k] == '1'); - } else { - $link[$col] = $line[$k]; - } - } else { - $link[$col] = $default; - } - $k++; - } - - if ($link['type'] == 18) { - $link['infobulle'] = $link['to']; - $link['to'] = ''; - } - - $webvideo = WebVideo::parse($link['to'], true); - if ($webvideo !== false) { - $link['type'] = '10'; - $link['video_service'] = $webvideo['service']; - $link['inline'] = 'popup'; - $link['to'] = $webvideo['id']; - } - - $link['display_area'] = '1'; - $link['page'] = $page; - $link['uid'] = self::generateUID(); - $links[] = $link; - } - fclose($fp); - } - - self::saveLinksInFile($book_id, backpack_user() ? backpack_user()->id : 0, 'Links imported from PDF', $links); - } - - public static function getLinksAndRulersFromExcelFile($path, &$links, &$rulers) - { - $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); - $xls = $reader->load($path); - Links::getLinksFromExcel($xls, $links, $rulers); - } - - public static function generateUID() - { - $characters = '0123456789abcdefghijklmnopqrstuvwxyz'; - $randstring = ''; - for ($i = 0; $i < 12; $i++) { - $randstring .= $characters[rand(0, 35)]; - } - return $randstring; - } - - public static function copy($source, $dest, $sourceVersion = 'latest') - { - self::getLinksAndRulers($source, $links, $rulers, $sourceVersion); - self::saveLinksInFile($dest, backpack_user()->id, __('Copier les liens à partir du fluidbook :fluidbook', ['fluidbook' => $source]), $links, $rulers); - } -} diff --git a/app/Fluidbook/Packager/Packager.php b/app/Fluidbook/Packager/Packager.php index e095c533b..7047dc6b7 100644 --- a/app/Fluidbook/Packager/Packager.php +++ b/app/Fluidbook/Packager/Packager.php @@ -2,7 +2,7 @@ namespace App\Fluidbook\Packager; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use App\Models\FluidbookPublication; use App\Models\FluidbookTheme; use Cubist\Util\CommandLine; diff --git a/app/Fluidbook/SEO/Document.php b/app/Fluidbook/SEO/Document.php index 73e7da2e8..112d128fe 100644 --- a/app/Fluidbook/SEO/Document.php +++ b/app/Fluidbook/SEO/Document.php @@ -2,7 +2,7 @@ namespace App\Fluidbook\SEO; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use App\Models\FluidbookDocument; use Cubist\Excel\ExcelToArray; use Cubist\Util\Text; diff --git a/app/Fluidbook/SearchIndex.php b/app/Fluidbook/SearchIndex.php index d82296f55..ab3636764 100644 --- a/app/Fluidbook/SearchIndex.php +++ b/app/Fluidbook/SearchIndex.php @@ -2,6 +2,7 @@ namespace App\Fluidbook; +use App\Fluidbook\Compiler\Compiler; use App\Models\FluidbookDocument; use Cubist\Util\Gzip; diff --git a/app/Http/Controllers/Admin/Operations/FluidbookPublication/LinksOperation.php b/app/Http/Controllers/Admin/Operations/FluidbookPublication/LinksOperation.php index 6434090b2..5007fb2b0 100644 --- a/app/Http/Controllers/Admin/Operations/FluidbookPublication/LinksOperation.php +++ b/app/Http/Controllers/Admin/Operations/FluidbookPublication/LinksOperation.php @@ -4,8 +4,7 @@ namespace App\Http\Controllers\Admin\Operations\FluidbookPublication; // __('!!Paramètres des fluidbooks') -use App\Fluidbook\Farm; -use App\Fluidbook\Links; +use App\Fluidbook\Link\LinksData; use App\Models\FluidbookPublication; use Cubist\Backpack\Http\Controllers\Base\XSendFileController; use Cubist\Util\Files\Files; @@ -51,7 +50,7 @@ trait LinksOperation abort(401); } - Links::saveLinksInFile($fluidbook_id, + LinksData::saveLinksInFile($fluidbook_id, backpack_user()->id, request('message'), json_decode(request('links', '[]'), true), @@ -59,7 +58,7 @@ trait LinksOperation ); $fb = FluidbookPublication::find($fluidbook_id); - return response()->json(['assets' => $fb->getLinksAssetsDimensions(), 'versions' => Links::getLinksVersions($fluidbook_id)]); + return response()->json(['assets' => $fb->getLinksAssetsDimensions(), 'versions' => LinksData::getLinksVersions($fluidbook_id)]); } protected function moveLinks($fluidbook_id) @@ -80,7 +79,7 @@ trait LinksOperation $width = $fb->getPageWidth(); $isOnePage = $fb->isOnePage(); - Links::getLinksAndRulers($fluidbook_id, $links, $rulers); + LinksData::getLinksAndRulers($fluidbook_id, $links, $rulers); $rlinks = array(); foreach ($links as $k => $link) { @@ -128,7 +127,7 @@ trait LinksOperation $rrulers[$k] = $ruler; } - Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Décalage de :nb pages à partir de la page :page', ['nb' => $offset, 'page' => $from]), $rlinks, $rrulers); + LinksData::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Décalage de :nb pages à partir de la page :page', ['nb' => $offset, 'page' => $from]), $rlinks, $rrulers); return response()->json(['success' => 'ok']); } @@ -168,7 +167,7 @@ trait LinksOperation if (!FluidbookPublication::hasPermission($fluidbook_id)) { abort(401); } - $links = Links::getLinksVersions($fluidbook_id); + $links = LinksData::getLinksVersions($fluidbook_id); return response()->json($links); } @@ -177,8 +176,8 @@ trait LinksOperation if (!FluidbookPublication::hasPermission($fluidbook_id)) { abort(401); } - Links::getLinksAndRulers($fluidbook_id, $links, $rulers, $version); - $xlsx = Links::linksToExcel($links, $rulers); + LinksData::getLinksAndRulers($fluidbook_id, $links, $rulers, $version); + $xlsx = LinksData::linksToExcel($links, $rulers); $tmpfile = Files::tempnam() . '.xlsx'; $writer = new Xlsx($xlsx); $writer->save($tmpfile); @@ -191,8 +190,8 @@ trait LinksOperation abort(401); } - Links::getLinksAndRulers($fluidbook_id, $links, $rulers, $version); - Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Restaurer la sauvegarde des liens :date', ['date' => date('Y-m-d H:i:s', $version)]), $links, $rulers, [], []); + LinksData::getLinksAndRulers($fluidbook_id, $links, $rulers, $version); + LinksData::saveLinksInFile($fluidbook_id, backpack_user()->id, __('Restaurer la sauvegarde des liens :date', ['date' => date('Y-m-d H:i:s', $version)]), $links, $rulers, [], []); return response()->json(['success' => 'ok']); } @@ -204,8 +203,8 @@ trait LinksOperation /** @var UploadedFile $uploadedFile */ $uploadedFile = request()->file('file'); - Links::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers); - Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Remplacer les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]), $links, $rulers, [], []); + LinksData::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers); + LinksData::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Remplacer les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]), $links, $rulers, [], []); return response()->json(['success' => 'ok']); } @@ -218,8 +217,8 @@ trait LinksOperation /** @var UploadedFile $uploadedFile */ $uploadedFile = request()->file('file'); - Links::getLinksAndRulers($fluidbook_id, $merged_links, $merged_rulers); - Links::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers); + LinksData::getLinksAndRulers($fluidbook_id, $merged_links, $merged_rulers); + LinksData::getLinksAndRulersFromExcelFile($uploadedFile->getPathname(), $links, $rulers); $existing_uids = []; foreach ($merged_links as $merged_link) { $existing_uids[$merged_link['uid']] = true; @@ -227,7 +226,7 @@ trait LinksOperation foreach ($links as $link) { if (isset($existing_uids[$link['uid']])) { - $link['uid'] = Links::generateUID(); + $link['uid'] = LinksData::generateUID(); $existing_uids[$link['uid']] = true; } $merged_links[] = $link; @@ -235,7 +234,7 @@ trait LinksOperation $merged_rulers = array_merge($merged_rulers, $rulers); - Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Ajouter les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]) . ' ', $merged_links, $merged_rulers, [], []); + LinksData::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Ajouter les liens à partir du fichier :file", ['file' => $uploadedFile->getClientOriginalName()]) . ' ', $merged_links, $merged_rulers, [], []); return response()->json(['success' => 'ok']); } @@ -267,7 +266,7 @@ trait LinksOperation $book = FluidbookPublication::find($fluidbook_id); $w = $book->getPageWidth(); $w2 = $w * 2; - Links::getLinksAndRulers($fluidbook_id, $links, $rulers); + LinksData::getLinksAndRulers($fluidbook_id, $links, $rulers); foreach ($links as $i => $link) { $change = false; while (true) { @@ -286,6 +285,6 @@ trait LinksOperation $links[$i] = $link; } } - Links::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Corriger la dérive des liens"), $links, $rulers, [], []); + LinksData::saveLinksInFile($fluidbook_id, backpack_user()->id, __("Corriger la dérive des liens"), $links, $rulers, [], []); } } diff --git a/app/Http/Controllers/Admin/Operations/FluidbookPublication/PreviewOperation.php b/app/Http/Controllers/Admin/Operations/FluidbookPublication/PreviewOperation.php index bf8f7af1b..04e86eb86 100644 --- a/app/Http/Controllers/Admin/Operations/FluidbookPublication/PreviewOperation.php +++ b/app/Http/Controllers/Admin/Operations/FluidbookPublication/PreviewOperation.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Admin\Operations\FluidbookPublication; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use App\Http\Controllers\Admin\Operations\FluidbookPreviewOperation; use App\Http\Middleware\CheckIfAdmin; use App\Models\FluidbookPublication; diff --git a/app/Http/Controllers/Admin/Operations/Tools/FluidbookCopyLinks.php b/app/Http/Controllers/Admin/Operations/Tools/FluidbookCopyLinks.php index c0169492d..ef5b5a25d 100644 --- a/app/Http/Controllers/Admin/Operations/Tools/FluidbookCopyLinks.php +++ b/app/Http/Controllers/Admin/Operations/Tools/FluidbookCopyLinks.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Admin\Operations\Tools; use App\Fields\FluidbookID; -use App\Fluidbook\Links; +use App\Fluidbook\Link\LinksData; use App\Models\FluidbookPublication; use Cubist\Backpack\Magic\Fields\Checkbox; use Cubist\Backpack\Magic\Fields\SelectFromArray; @@ -48,7 +48,7 @@ trait FluidbookCopyLinks } if (request('links')) { - Links::copy(request('from'), request('to')); + LinksData::copy(request('from'), request('to')); } if (request('assets', 'no') !== 'no') { diff --git a/app/Jobs/FluidbookDocumentUpload.php b/app/Jobs/FluidbookDocumentUpload.php index 73b9ee505..a8f286a50 100644 --- a/app/Jobs/FluidbookDocumentUpload.php +++ b/app/Jobs/FluidbookDocumentUpload.php @@ -2,7 +2,6 @@ namespace App\Jobs; -use App\Fluidbook\Links; use App\Models\FluidbookDocument; use App\Models\User; use Illuminate\Support\Facades\Cache; diff --git a/app/Jobs/FluidbookImagesPreprocess.php b/app/Jobs/FluidbookImagesPreprocess.php index cbddf5267..8ffe401ab 100644 --- a/app/Jobs/FluidbookImagesPreprocess.php +++ b/app/Jobs/FluidbookImagesPreprocess.php @@ -2,7 +2,7 @@ namespace App\Jobs; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use App\Models\FluidbookPublication; use Cubist\Util\ArrayUtil; diff --git a/app/Models/FluidbookPublication.php b/app/Models/FluidbookPublication.php index 9e0d41ca3..00afd8062 100644 --- a/app/Models/FluidbookPublication.php +++ b/app/Models/FluidbookPublication.php @@ -10,7 +10,7 @@ use App\Fields\FluidbookLocale; use App\Fields\FluidbookStatus; use App\Fields\User; use App\Fluidbook\Farm; -use App\Fluidbook\Links; +use App\Fluidbook\Link\LinksData; use App\Http\Controllers\Admin\Operations\ChangeownerOperation; use App\Http\Controllers\Admin\Operations\FluidbookPublication\CloneOperation; use App\Http\Controllers\Admin\Operations\FluidbookPublication\CompositionOperation; @@ -28,7 +28,6 @@ use App\Models\Traits\CheckHash; use App\Models\Traits\PublicationSettings; use App\Models\Traits\SCORMVersionTrait; use App\Slack\Slack; -use Backpack\CRUD\app\Library\Widget; use Cubist\Backpack\Magic\Fields\FormBigSection; use Cubist\Backpack\Magic\Fields\FormSuperSection; use Cubist\Backpack\Magic\Fields\Hidden; @@ -498,7 +497,7 @@ class FluidbookPublication extends ToolboxSettingsModel public function getLinksAndRulers(&$links, &$rulers) { - Links::getLinksAndRulers($this->id, $links, $rulers); + LinksData::getLinksAndRulers($this->id, $links, $rulers); } public function getLinksAssetsDimensions() @@ -661,7 +660,7 @@ class FluidbookPublication extends ToolboxSettingsModel $new->save(); // Copy links & assets - Links::copy($this->id, $new->id); + LinksData::copy($this->id, $new->id); $this->_replicateMedia($new->id); return $new; diff --git a/app/SubForms/Link/Anchor.php b/app/SubForms/Link/Anchor.php index a292faf95..de6ceab76 100644 --- a/app/SubForms/Link/Anchor.php +++ b/app/SubForms/Link/Anchor.php @@ -2,9 +2,11 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class Anchor extends Meta { - public $type = self::ANCHOR; + public $type = Link::ANCHOR; protected $_extra = false; diff --git a/app/SubForms/Link/Article.php b/app/SubForms/Link/Article.php index e183814dc..4496c49d6 100644 --- a/app/SubForms/Link/Article.php +++ b/app/SubForms/Link/Article.php @@ -2,12 +2,13 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; use Cubist\Backpack\Magic\Fields\Textarea; // __('!! Editeur de liens') class Article extends Meta { - public $type = self::ARTICLE; + public $type = Link::ARTICLE; public function addDestinationField() { diff --git a/app/SubForms/Link/ArticleOpen.php b/app/SubForms/Link/ArticleOpen.php index af2d7408f..3e3805a1b 100644 --- a/app/SubForms/Link/ArticleOpen.php +++ b/app/SubForms/Link/ArticleOpen.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class ArticleOpen extends Base { - public $type = self::ARTICLE_OPEN; + public $type = Link::ARTICLE_OPEN; public function addDestinationField() { diff --git a/app/SubForms/Link/Audio.php b/app/SubForms/Link/Audio.php index d5fc894f7..d478a44c1 100644 --- a/app/SubForms/Link/Audio.php +++ b/app/SubForms/Link/Audio.php @@ -2,12 +2,13 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\CheckboxBasic; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Audio extends Base { - public $type = self::AUDIO; + public $type = Link::AUDIO; public $_integration = true; public $_multimedia = true; diff --git a/app/SubForms/Link/Audiodescription.php b/app/SubForms/Link/Audiodescription.php index ea5b09f07..e01a10295 100644 --- a/app/SubForms/Link/Audiodescription.php +++ b/app/SubForms/Link/Audiodescription.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Audiodescription extends Meta { - public $type = self::AUDIODESCRIPTION; + public $type = Link::AUDIODESCRIPTION; public function addDestinationField() { diff --git a/app/SubForms/Link/Base.php b/app/SubForms/Link/Base.php index f01ecface..b2418b29d 100644 --- a/app/SubForms/Link/Base.php +++ b/app/SubForms/Link/Base.php @@ -6,7 +6,7 @@ use App\Fields\FluidbookLinkEditor\Depth; use App\Fields\FluidbookLinkEditor\LinkType; use App\Fields\FluidbookLinkEditor\MultimediaIntegration; use App\Fields\FluidbookLinkEditor\RolloverAnimation; -use App\Fluidbook\Compiler; +use App\Fluidbook\Compiler\Compiler; use App\Fluidbook\Link\Link; use App\Models\FluidbookPublication; use Cubist\Backpack\Magic\Fields\Checkbox; @@ -25,53 +25,6 @@ use Cubist\Backpack\Magic\Form; // __('!! Editeur de liens') class Base extends Form { - const WEB_INFOS = 1; - const PRODUCT = 1; - const WEB = 2; - const GENERAL = 2; - const EMAIL = 3; - const VIDEO = 4; - const INTERNAL = 5; - const MULTIMEDIA = 6; - const PERSO = 7; - const CUSTOM = 7; - const PAGE_CORNER = 8; - const OBJECT3D = 9; - const WEBVIDEO = 10; - const ACTION = 11; - const CART = 12; - const BASKET = 12; - const ZOOM = 13; - const COLOR = 14; - const IMAGE = 15; - const FILE = 16; - const AUDIO = 17; - const TOOLTIP = 18; - const CALL = 19; - const BOOKMARKGROUP = 20; - const HTML5MULTIMEDIA = 21; - const BOOKMARK_CORNER = 22; - const STATSTAG = 23; - const PHONE = 24; - const AUDIODESCRIPTION = 25; - const PAGE_LABEL = 26; - const EVENT_OVERLAY = 27; - const ARTICLE = 28; - const LIKE = 29; - const SLIDESHOW = 30; - const IFRAME = 31; - const SHOWLINK = 32; - const ZOOMHD = 33; - const LOCK_CONTENTS = 34; - const TEXT = 35; - const ARTICLE_OPEN = 36; - const DOWNLOAD_PORTION = 37; - const TRIGGERSLINK = 38; - const LAYER = 39; - const ANCHOR = 40; - const FLIPCARD = 41; - - const PDF=42; /** @@ -111,47 +64,47 @@ class Base extends Form public static function types() { $res = [ - ['type' => self::WEB, 'label' => __('Adresse Web (URL)'), 'color' => '#3399cc', 'class' => Web::class, 'order' => 1], - ['type' => self::INTERNAL, 'label' => __('Lien vers une page'), 'color' => '#c7b405', 'class' => Internal::class, 'order' => 2], - ['type' => self::EMAIL, 'label' => __('Adresse e-mail'), 'color' => '#6c6360', 'class' => Email::class, 'order' => 3], - ['type' => self::VIDEO, 'label' => __('Vidéo'), 'color' => '#33ff00', 'class' => Video::class, 'order' => 4], + ['type' => \Fluidbook\Tools\Links\Link::WEB, 'label' => __('Adresse Web (URL)'), 'color' => '#3399cc', 'class' => Web::class, 'order' => 1], + ['type' => \Fluidbook\Tools\Links\Link::INTERNAL, 'label' => __('Lien vers une page'), 'color' => '#c7b405', 'class' => Internal::class, 'order' => 2], + ['type' => \Fluidbook\Tools\Links\Link::EMAIL, 'label' => __('Adresse e-mail'), 'color' => '#6c6360', 'class' => Email::class, 'order' => 3], + ['type' => \Fluidbook\Tools\Links\Link::VIDEO, 'label' => __('Vidéo'), 'color' => '#33ff00', 'class' => Video::class, 'order' => 4], ['type' => 'separator', 'order' => 5], - ['type' => self::COLOR, 'label' => __('Couleur'), 'color' => '#8C5E24', 'class' => Color::class], - ['type' => self::IMAGE, 'label' => __('Image'), 'color' => '#BE418D', 'class' => Image::class], - ['type' => self::LAYER, 'label' => __('Animation de calque'), 'color' => '#3D0254', 'class' => Layer::class], - ['type' => self::TEXT, 'label' => __('Texte'), 'color' => '#9090FF', 'class' => \App\SubForms\Link\Text::class], - ['type' => self::MULTIMEDIA, 'label' => __('Multimédia'), 'color' => '#ff00ff', 'class' => Multimedia::class], - ['type' => self::WEB_INFOS, 'label' => __('Adresse web « plus d\'infos »'), 'color' => '#ff0000', 'class' => WebInfos::class], - ['type' => self::CUSTOM, 'label' => __('Personnalisé'), 'color' => '#14511a', 'class' => Custom::class], - ['type' => self::WEBVIDEO, 'label' => __('Vidéo web'), 'color' => '#ffff00', 'class' => WebVideo::class], - ['type' => self::CART, 'label' => __('Panier'), 'color' => '#F2A4B7', 'class' => Cart::class], - ['type' => self::ZOOM, 'label' => __('Zone de zoom'), 'color' => '#322280', 'class' => ZoomArea::class], - ['type' => self::FILE, 'label' => __('Fichier'), 'color' => '#F19043', 'class' => File::class], - ['type' => self::AUDIO, 'label' => __('Audio'), 'color' => '#0065AE', 'class' => Audio::class], - ['type' => self::TOOLTIP, 'label' => __('Infobulle / Texte'), 'color' => '#20c45b', 'class' => Tooltip::class], - ['type' => self::BOOKMARKGROUP, 'label' => __('Groupe de marque-pages'), 'color' => '#d6520f', 'class' => BookmarkGroup::class], - ['type' => self::STATSTAG, 'label' => __('Tag statistique'), 'color' => '#dddddd', 'class' => StatsTag::class], - ['type' => self::PHONE, 'label' => __('Téléphone'), 'color' => '#333333', 'class' => Phone::class], - ['type' => self::AUDIODESCRIPTION, 'label' => __('Audiodescription'), 'color' => '#00535b', 'class' => Audiodescription::class], - ['type' => self::ANCHOR, 'label' => __('Ancre / Label de page'), 'color' => '#00E6D7', 'class' => Anchor::class, 'aliases' => self::PAGE_LABEL], - ['type' => self::EVENT_OVERLAY, 'label' => __('Capter les évenements'), 'color' => '#ffcc00', 'class' => EventOverlay::class], - ['type' => self::ARTICLE, 'label' => __('Article (définition)'), 'color' => '#ACC152', 'class' => Article::class], - ['type' => self::LIKE, 'label' => __('Like'), 'color' => '#4267B2', 'class' => Like::class], - ['type' => self::SLIDESHOW, 'label' => __('Diaporama'), 'color' => '#07b57a', 'class' => Slideshow::class], - ['type' => self::IFRAME, 'label' => __('iFrame'), 'color' => '#fcae25', 'class' => IFrame::class], - ['type' => self::SHOWLINK, 'label' => __('Afficher un lien'), 'color' => '#125C70', 'class' => ShowLink::class], - ['type' => self::ZOOMHD, 'label' => __('Zoom HD'), 'color' => '#E80C95', 'class' => ZoomHD::class], - ['type' => self::LOCK_CONTENTS, 'label' => __('Blocage des contenus'), 'color' => '#69D670', 'class' => LockContents::class], - ['type' => self::ARTICLE_OPEN, 'label' => __('Article (afficher)'), 'color' => '#ffcc00', 'class' => ArticleOpen::class], - ['type' => self::DOWNLOAD_PORTION, 'label' => __('Télécharger un extrait'), 'color' => '#AAAAAA', 'class' => DownloadPortion::class], - ['type' => self::TRIGGERSLINK, 'label' => __('Déclencher un lien'), 'color' => '#cc0000', 'class' => TriggerLink::class], - ['type' => self::FLIPCARD, 'label' => __('Flipcard'), 'color' => '#460e3f', 'class' => Flipcard::class], - ['type' => self::PDF, 'label' => __('PDF'), 'color' => '#af48d1', 'class' => PDF::class], - //['type' => self::ACTION, 'label' => __('Action'), 'color' => '#880000', 'class' => Action::class], - //['type' => self::HTML5MULTIMEDIA, 'label' => __('Lien Multimédia (HTML)'), 'color' => '#34A853', 'disabled' => true, 'class' => Web::class], - //['type' => self::BOOKMARK_CORNER, 'label' => __('Lien marque-page sur coin de page'), 'color' => '#000000', 'disabled' => true, 'class' => Web::class], - //['type' => self::PAGE_CORNER, 'label' => __('Coin de page'), 'color' => '#f19043', 'disabled' => true, 'class' => Web::class], - //['type' => self::OBJECT3D, 'label' => __('Objet 3D'), 'color' => '#00ffff', 'disabled' => true, 'class' => Web::class], + ['type' => \Fluidbook\Tools\Links\Link::COLOR, 'label' => __('Couleur'), 'color' => '#8C5E24', 'class' => Color::class], + ['type' => \Fluidbook\Tools\Links\Link::IMAGE, 'label' => __('Image'), 'color' => '#BE418D', 'class' => Image::class], + ['type' => \Fluidbook\Tools\Links\Link::LAYER, 'label' => __('Animation de calque'), 'color' => '#3D0254', 'class' => Layer::class], + ['type' => \Fluidbook\Tools\Links\Link::TEXT, 'label' => __('Texte'), 'color' => '#9090FF', 'class' => \App\SubForms\Link\Text::class], + ['type' => \Fluidbook\Tools\Links\Link::MULTIMEDIA, 'label' => __('Multimédia'), 'color' => '#ff00ff', 'class' => Multimedia::class], + ['type' => \Fluidbook\Tools\Links\Link::WEB_INFOS, 'label' => __('Adresse web « plus d\'infos »'), 'color' => '#ff0000', 'class' => WebInfos::class], + ['type' => \Fluidbook\Tools\Links\Link::CUSTOM, 'label' => __('Personnalisé'), 'color' => '#14511a', 'class' => Custom::class], + ['type' => \Fluidbook\Tools\Links\Link::WEBVIDEO, 'label' => __('Vidéo web'), 'color' => '#ffff00', 'class' => WebVideo::class], + ['type' => \Fluidbook\Tools\Links\Link::CART, 'label' => __('Panier'), 'color' => '#F2A4B7', 'class' => Cart::class], + ['type' => \Fluidbook\Tools\Links\Link::ZOOM, 'label' => __('Zone de zoom'), 'color' => '#322280', 'class' => ZoomArea::class], + ['type' => \Fluidbook\Tools\Links\Link::FILE, 'label' => __('Fichier'), 'color' => '#F19043', 'class' => File::class], + ['type' => \Fluidbook\Tools\Links\Link::AUDIO, 'label' => __('Audio'), 'color' => '#0065AE', 'class' => Audio::class], + ['type' => \Fluidbook\Tools\Links\Link::TOOLTIP, 'label' => __('Infobulle / Texte'), 'color' => '#20c45b', 'class' => Tooltip::class], + ['type' => \Fluidbook\Tools\Links\Link::BOOKMARKGROUP, 'label' => __('Groupe de marque-pages'), 'color' => '#d6520f', 'class' => BookmarkGroup::class], + ['type' => \Fluidbook\Tools\Links\Link::STATSTAG, 'label' => __('Tag statistique'), 'color' => '#dddddd', 'class' => StatsTag::class], + ['type' => \Fluidbook\Tools\Links\Link::PHONE, 'label' => __('Téléphone'), 'color' => '#333333', 'class' => Phone::class], + ['type' => \Fluidbook\Tools\Links\Link::AUDIODESCRIPTION, 'label' => __('Audiodescription'), 'color' => '#00535b', 'class' => Audiodescription::class], + ['type' => \Fluidbook\Tools\Links\Link::ANCHOR, 'label' => __('Ancre / Label de page'), 'color' => '#00E6D7', 'class' => Anchor::class, 'aliases' => \Fluidbook\Tools\Links\Link::PAGE_LABEL], + ['type' => \Fluidbook\Tools\Links\Link::EVENT_OVERLAY, 'label' => __('Capter les évenements'), 'color' => '#ffcc00', 'class' => EventOverlay::class], + ['type' => \Fluidbook\Tools\Links\Link::ARTICLE, 'label' => __('Article (définition)'), 'color' => '#ACC152', 'class' => Article::class], + ['type' => \Fluidbook\Tools\Links\Link::LIKE, 'label' => __('Like'), 'color' => '#4267B2', 'class' => Like::class], + ['type' => \Fluidbook\Tools\Links\Link::SLIDESHOW, 'label' => __('Diaporama'), 'color' => '#07b57a', 'class' => Slideshow::class], + ['type' => \Fluidbook\Tools\Links\Link::IFRAME, 'label' => __('iFrame'), 'color' => '#fcae25', 'class' => IFrame::class], + ['type' => \Fluidbook\Tools\Links\Link::SHOWLINK, 'label' => __('Afficher un lien'), 'color' => '#125C70', 'class' => ShowLink::class], + ['type' => \Fluidbook\Tools\Links\Link::ZOOMHD, 'label' => __('Zoom HD'), 'color' => '#E80C95', 'class' => ZoomHD::class], + ['type' => \Fluidbook\Tools\Links\Link::LOCK_CONTENTS, 'label' => __('Blocage des contenus'), 'color' => '#69D670', 'class' => LockContents::class], + ['type' => \Fluidbook\Tools\Links\Link::ARTICLE_OPEN, 'label' => __('Article (afficher)'), 'color' => '#ffcc00', 'class' => ArticleOpen::class], + ['type' => \Fluidbook\Tools\Links\Link::DOWNLOAD_PORTION, 'label' => __('Télécharger un extrait'), 'color' => '#AAAAAA', 'class' => DownloadPortion::class], + ['type' => \Fluidbook\Tools\Links\Link::TRIGGERSLINK, 'label' => __('Déclencher un lien'), 'color' => '#cc0000', 'class' => TriggerLink::class], + ['type' => \Fluidbook\Tools\Links\Link::FLIPCARD, 'label' => __('Flipcard'), 'color' => '#460e3f', 'class' => Flipcard::class], + ['type' => \Fluidbook\Tools\Links\Link::PDF, 'label' => __('PDF'), 'color' => '#af48d1', 'class' => PDF::class], + //['type' => \Fluidbook\Tools\Links\Link::ACTION, 'label' => __('Action'), 'color' => '#880000', 'class' => Action::class], + //['type' => \Fluidbook\Tools\Links\Link::HTML5MULTIMEDIA, 'label' => __('Lien Multimédia (HTML)'), 'color' => '#34A853', 'disabled' => true, 'class' => Web::class], + //['type' => \Fluidbook\Tools\Links\Link::BOOKMARK_CORNER, 'label' => __('Lien marque-page sur coin de page'), 'color' => '#000000', 'disabled' => true, 'class' => Web::class], + //['type' => \Fluidbook\Tools\Links\Link::PAGE_CORNER, 'label' => __('Coin de page'), 'color' => '#f19043', 'disabled' => true, 'class' => Web::class], + //['type' => \Fluidbook\Tools\Links\Link::OBJECT3D, 'label' => __('Objet 3D'), 'color' => '#00ffff', 'disabled' => true, 'class' => Web::class], ]; usort($res, function ($a, $b) { diff --git a/app/SubForms/Link/BookmarkGroup.php b/app/SubForms/Link/BookmarkGroup.php index c8565ca08..305e694e2 100644 --- a/app/SubForms/Link/BookmarkGroup.php +++ b/app/SubForms/Link/BookmarkGroup.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Integer; // __('!! Editeur de liens') class BookmarkGroup extends Meta { - public $type = self::BOOKMARKGROUP; + public $type = Link::BOOKMARKGROUP; public function addDestinationField() { diff --git a/app/SubForms/Link/Cart.php b/app/SubForms/Link/Cart.php index 930ed5568..c0cc31a93 100644 --- a/app/SubForms/Link/Cart.php +++ b/app/SubForms/Link/Cart.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Text; // __('!! Editeur de liens') class Cart extends Base { - public $type = self::CART; + public $type = Link::CART; public function addDestinationField() { diff --git a/app/SubForms/Link/Color.php b/app/SubForms/Link/Color.php index 52681b892..19abd8182 100644 --- a/app/SubForms/Link/Color.php +++ b/app/SubForms/Link/Color.php @@ -3,9 +3,11 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class Color extends Animated { - public $type = self::COLOR; + public $type = Link::COLOR; public function addDestinationField() { diff --git a/app/SubForms/Link/Custom.php b/app/SubForms/Link/Custom.php index 628b1b743..abc8a1640 100644 --- a/app/SubForms/Link/Custom.php +++ b/app/SubForms/Link/Custom.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Custom extends Base { - public $type = self::CUSTOM; + public $type = Link::CUSTOM; public function addDestinationField() { diff --git a/app/SubForms/Link/DownloadPortion.php b/app/SubForms/Link/DownloadPortion.php index 865d69ee3..b133624c8 100644 --- a/app/SubForms/Link/DownloadPortion.php +++ b/app/SubForms/Link/DownloadPortion.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Text; // __('!! Editeur de liens') class DownloadPortion extends Base { - public $type = self::DOWNLOAD_PORTION; + public $type = Link::DOWNLOAD_PORTION; public function addDestinationField() { diff --git a/app/SubForms/Link/Email.php b/app/SubForms/Link/Email.php index bef8cb90e..fc3b00f55 100644 --- a/app/SubForms/Link/Email.php +++ b/app/SubForms/Link/Email.php @@ -3,9 +3,11 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class Email extends Web { - public $type = self::EMAIL; + public $type = Link::EMAIL; public function addDestinationField() { diff --git a/app/SubForms/Link/EventOverlay.php b/app/SubForms/Link/EventOverlay.php index d8a8905f5..45126a135 100644 --- a/app/SubForms/Link/EventOverlay.php +++ b/app/SubForms/Link/EventOverlay.php @@ -2,7 +2,9 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class EventOverlay extends Meta { - public $type = self::EVENT_OVERLAY; + public $type = Link::EVENT_OVERLAY; } diff --git a/app/SubForms/Link/File.php b/app/SubForms/Link/File.php index 41c6ff0f8..de571714b 100644 --- a/app/SubForms/Link/File.php +++ b/app/SubForms/Link/File.php @@ -3,11 +3,12 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\Target; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class File extends Web { - public $type = self::FILE; + public $type = Link::FILE; public function addDestinationField() { diff --git a/app/SubForms/Link/Flipcard.php b/app/SubForms/Link/Flipcard.php index fb2218c41..aedc16b8d 100644 --- a/app/SubForms/Link/Flipcard.php +++ b/app/SubForms/Link/Flipcard.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Flipcard extends Base { - public $type = self::FLIPCARD; + public $type = Link::FLIPCARD; protected $_addedContents = false; diff --git a/app/SubForms/Link/IFrame.php b/app/SubForms/Link/IFrame.php index f113d83c9..fccc4265f 100644 --- a/app/SubForms/Link/IFrame.php +++ b/app/SubForms/Link/IFrame.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class IFrame extends Web { - public $type = self::IFRAME; + public $type = Link::IFRAME; protected $_integration = true; diff --git a/app/SubForms/Link/Image.php b/app/SubForms/Link/Image.php index 5309c62ea..320459f8b 100644 --- a/app/SubForms/Link/Image.php +++ b/app/SubForms/Link/Image.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Image extends Animated { - public $type = self::IMAGE; + public $type = Link::IMAGE; public function addDestinationField() { diff --git a/app/SubForms/Link/Internal.php b/app/SubForms/Link/Internal.php index 9e132fd1a..27bb4a556 100644 --- a/app/SubForms/Link/Internal.php +++ b/app/SubForms/Link/Internal.php @@ -3,11 +3,12 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\NumberingType; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Text; // __('!! Editeur de liens') class Internal extends Web { - public $type = self::INTERNAL; + public $type = Link::INTERNAL; public function addDestinationField() { diff --git a/app/SubForms/Link/Layer.php b/app/SubForms/Link/Layer.php index fb0ee0d97..88a78224a 100644 --- a/app/SubForms/Link/Layer.php +++ b/app/SubForms/Link/Layer.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Hidden; // __('!! Editeur de liens') class Layer extends Animated { - public $type = self::LAYER; + public $type = Link::LAYER; public function addDestinationField() { diff --git a/app/SubForms/Link/Like.php b/app/SubForms/Link/Like.php index b10b419c9..8a40b4608 100644 --- a/app/SubForms/Link/Like.php +++ b/app/SubForms/Link/Like.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\URL; // __('!! Editeur de liens') class Like extends Base { - public $type = self::LIKE; + public $type = Link::LIKE; protected $_extra = false; protected $_addedContents = false; diff --git a/app/SubForms/Link/LockContents.php b/app/SubForms/Link/LockContents.php index 0f3747fd6..ed4ca0637 100644 --- a/app/SubForms/Link/LockContents.php +++ b/app/SubForms/Link/LockContents.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Textarea; // __('!! Editeur de liens') class LockContents extends Meta { - public $type = self::LOCK_CONTENTS; + public $type = Link::LOCK_CONTENTS; public function addDestinationField() { diff --git a/app/SubForms/Link/Multimedia.php b/app/SubForms/Link/Multimedia.php index 94724797b..f21a82e07 100644 --- a/app/SubForms/Link/Multimedia.php +++ b/app/SubForms/Link/Multimedia.php @@ -2,12 +2,13 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\CheckboxBasic; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Multimedia extends Base { - public $type = self::MULTIMEDIA; + public $type = Link::MULTIMEDIA; public $_integration = true; public $_multimedia = true; diff --git a/app/SubForms/Link/PDF.php b/app/SubForms/Link/PDF.php index d96d11d62..242cff0ef 100644 --- a/app/SubForms/Link/PDF.php +++ b/app/SubForms/Link/PDF.php @@ -4,11 +4,14 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\PDFJSType; use App\Fields\FluidbookLinkEditor\Target; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; use Cubist\Backpack\Magic\Fields\SelectFromArray; class PDF extends File { + public $type = Link::PDF; + public function addDestinationField() { $this->addField('to', FilesOrURL::class, __('Fichier'), $this->getFilesOrURLEntry()); diff --git a/app/SubForms/Link/Phone.php b/app/SubForms/Link/Phone.php index 7ded88063..11b1add8a 100644 --- a/app/SubForms/Link/Phone.php +++ b/app/SubForms/Link/Phone.php @@ -2,9 +2,11 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class Phone extends Web { - public $type = self::PHONE; + public $type = Link::PHONE; public function addDestinationField() { diff --git a/app/SubForms/Link/ShowLink.php b/app/SubForms/Link/ShowLink.php index ffe9b0605..0fc851a32 100644 --- a/app/SubForms/Link/ShowLink.php +++ b/app/SubForms/Link/ShowLink.php @@ -4,11 +4,12 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\ShowLinkCloseMode; use App\Fields\FluidbookLinkEditor\ShowLinkMode; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Text; // __('!! Editeur de liens') class ShowLink extends Base { - public $type = self::SHOWLINK; + public $type = Link::SHOWLINK; public function addDestinationField() { diff --git a/app/SubForms/Link/Slideshow.php b/app/SubForms/Link/Slideshow.php index c29aa6834..7849c267a 100644 --- a/app/SubForms/Link/Slideshow.php +++ b/app/SubForms/Link/Slideshow.php @@ -2,12 +2,13 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; use Cubist\Backpack\Magic\Fields\Integer; // __('!! Editeur de liens') class Slideshow extends Web { - public $type = self::SLIDESHOW; + public $type = Link::SLIDESHOW; public function addDestinationField() { diff --git a/app/SubForms/Link/StatsTag.php b/app/SubForms/Link/StatsTag.php index ce0fd8d7a..0d3b4830b 100644 --- a/app/SubForms/Link/StatsTag.php +++ b/app/SubForms/Link/StatsTag.php @@ -2,13 +2,15 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class StatsTag extends Base { protected $_tooltip = false; protected $_addedContents = false; protected $_extra=false; - public $type = self::STATSTAG; + public $type = Link::STATSTAG; public function addDestinationField() { diff --git a/app/SubForms/Link/Text.php b/app/SubForms/Link/Text.php index b07aebe88..5cd84e1bd 100644 --- a/app/SubForms/Link/Text.php +++ b/app/SubForms/Link/Text.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Text extends Animated { - public $type = self::TEXT; + public $type = Link::TEXT; public function addDestinationField() { diff --git a/app/SubForms/Link/Tooltip.php b/app/SubForms/Link/Tooltip.php index f06307a38..dbd7e3872 100644 --- a/app/SubForms/Link/Tooltip.php +++ b/app/SubForms/Link/Tooltip.php @@ -2,12 +2,16 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\CheckboxBasic; use Cubist\Backpack\Magic\Fields\FormSection; use Cubist\Backpack\Magic\Fields\Textarea; + // __('!! Editeur de liens') class Tooltip extends Base { + public $type = Link::TOOLTIP; + public function initForm() { $this->addTypeField(); diff --git a/app/SubForms/Link/TriggerLink.php b/app/SubForms/Link/TriggerLink.php index 481146dbd..d3fff2144 100644 --- a/app/SubForms/Link/TriggerLink.php +++ b/app/SubForms/Link/TriggerLink.php @@ -3,11 +3,12 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\TriggerLinkEvent; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Text; // __('!! Editeur de liens') class TriggerLink extends Base { - public $type = self::TRIGGERSLINK; + public $type = Link::TRIGGERSLINK; public function addDestinationField() { diff --git a/app/SubForms/Link/Video.php b/app/SubForms/Link/Video.php index e797d244b..5de4ca721 100644 --- a/app/SubForms/Link/Video.php +++ b/app/SubForms/Link/Video.php @@ -2,12 +2,13 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\CheckboxBasic; use Cubist\Backpack\Magic\Fields\FilesOrURL; // __('!! Editeur de liens') class Video extends Base { - public $type = self::VIDEO; + public $type = Link::VIDEO; public $_integration = true; public $_multimedia = true; diff --git a/app/SubForms/Link/Web.php b/app/SubForms/Link/Web.php index 09bfabe57..c256b86b9 100644 --- a/app/SubForms/Link/Web.php +++ b/app/SubForms/Link/Web.php @@ -3,12 +3,13 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\Target; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\SelectFromArray; use Cubist\Backpack\Magic\Fields\URL; // __('!! Editeur de liens') class Web extends Base { - public $type = self::WEB; + public $type = Link::WEB; public function addDestinationField() { diff --git a/app/SubForms/Link/WebInfos.php b/app/SubForms/Link/WebInfos.php index 6516bab03..bf4412d31 100644 --- a/app/SubForms/Link/WebInfos.php +++ b/app/SubForms/Link/WebInfos.php @@ -2,7 +2,9 @@ namespace App\SubForms\Link; // __('!! Editeur de liens') +use App\Fluidbook\Link\Link; + class WebInfos extends Web { - public $type = self::WEB_INFOS; + public $type = Link::WEB_INFOS; } diff --git a/app/SubForms/Link/WebVideo.php b/app/SubForms/Link/WebVideo.php index 7e80ccc68..713ff9350 100644 --- a/app/SubForms/Link/WebVideo.php +++ b/app/SubForms/Link/WebVideo.php @@ -3,11 +3,12 @@ namespace App\SubForms\Link; use App\Fields\FluidbookLinkEditor\WebvideoService; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Text; // __('!! Editeur de liens') class WebVideo extends Video { - public $type = self::WEBVIDEO; + public $type = Link::WEBVIDEO; public function addDestinationField() { diff --git a/app/SubForms/Link/ZoomArea.php b/app/SubForms/Link/ZoomArea.php index c0375aa01..77b16a2d5 100644 --- a/app/SubForms/Link/ZoomArea.php +++ b/app/SubForms/Link/ZoomArea.php @@ -2,11 +2,12 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\Number; // __('!! Editeur de liens') class ZoomArea extends Base { - public $type = self::ZOOM; + public $type = Link::ZOOM; public function addDestinationField() { diff --git a/app/SubForms/Link/ZoomHD.php b/app/SubForms/Link/ZoomHD.php index 650500a98..fc5fca4b9 100644 --- a/app/SubForms/Link/ZoomHD.php +++ b/app/SubForms/Link/ZoomHD.php @@ -2,11 +2,13 @@ namespace App\SubForms\Link; +use App\Fluidbook\Link\Link; use Cubist\Backpack\Magic\Fields\FilesOrURL; + // __('!! Editeur de liens') class ZoomHD extends Base { - public $type = self::ZOOMHD; + public $type = Link::ZOOMHD; public function addDestinationField() { diff --git a/composer.lock b/composer.lock index abd32b0b0..91c235ca7 100644 --- a/composer.lock +++ b/composer.lock @@ -1505,13 +1505,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/cubedesigners_userdatabase.git", - "reference": "de3c655c9aa77497f2f33e7e80a8e98b2eb84899" + "reference": "457ac69e6f98888c441ba2c9150909088357dd86" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/cubedesigners/userdatabase/cubedesigners-userdatabase-dev-backpack4.1-97755b.tar", - "reference": "de3c655c9aa77497f2f33e7e80a8e98b2eb84899", - "shasum": "ffd64cccf8471c59b7c834526920f9fbd39436fc" + "url": "https://composer.cubedesigners.com/dist/cubedesigners/userdatabase/cubedesigners-userdatabase-dev-backpack4.1-336bca.tar", + "reference": "457ac69e6f98888c441ba2c9150909088357dd86", + "shasum": "3ca991e7ef3ce6d2c082504d506f5972c1d07cd2" }, "require": { "cubist/cms-back": "dev-backpack4.1" @@ -1542,7 +1542,7 @@ } ], "description": "Cubedesigners common users database", - "time": "2023-04-24T12:30:51+00:00" + "time": "2023-04-24T15:24:16+00:00" }, { "name": "cubist/azuretts", @@ -2098,13 +2098,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/cubist_util.git", - "reference": "8b554594188f73f0b31010cc0bf4f16c11cad2e4" + "reference": "18676401c228bfd48a6fc74c24f602e36a143bd2" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/cubist/util/cubist-util-dev-master-a5ed91.tar", - "reference": "8b554594188f73f0b31010cc0bf4f16c11cad2e4", - "shasum": "11dec95916b83c846368e4cee3bb70658403a3a3" + "url": "https://composer.cubedesigners.com/dist/cubist/util/cubist-util-dev-master-a551df.tar", + "reference": "18676401c228bfd48a6fc74c24f602e36a143bd2", + "shasum": "675fd965b43b7bf9d3bce9bef535aeaca0224b0a" }, "require": { "cubist/net": "dev-master", @@ -2137,7 +2137,7 @@ } ], "description": "Utilities class", - "time": "2023-04-21T17:02:35+00:00" + "time": "2023-05-04T13:49:10+00:00" }, { "name": "cviebrock/eloquent-sluggable", @@ -3427,13 +3427,13 @@ "source": { "type": "git", "url": "git://git.cubedesigners.com/fluidbook_tools.git", - "reference": "6aeaba834555ae729c6da5868390546fc51ffed7" + "reference": "d417ed09949a2861885219dbd4c3bedecb6d3cbe" }, "dist": { "type": "tar", - "url": "https://composer.cubedesigners.com/dist/fluidbook/tools/fluidbook-tools-dev-master-55ea59.tar", - "reference": "6aeaba834555ae729c6da5868390546fc51ffed7", - "shasum": "d9d17aba915b0c582301c0d543402401a2414838" + "url": "https://composer.cubedesigners.com/dist/fluidbook/tools/fluidbook-tools-dev-master-82474b.tar", + "reference": "d417ed09949a2861885219dbd4c3bedecb6d3cbe", + "shasum": "c74e93ca33ad6361d39be0ab1838d4fd2e6d4ac7" }, "require": { "barryvdh/laravel-debugbar": "*", @@ -3467,7 +3467,7 @@ } ], "description": "Fluidbook Tools", - "time": "2023-04-21T17:23:49+00:00" + "time": "2023-05-05T06:50:25+00:00" }, { "name": "genealabs/laravel-model-caching", @@ -4242,7 +4242,7 @@ }, { "name": "jane-php/json-schema-runtime", - "version": "v7.4.4", + "version": "v7.5.0", "source": { "type": "git", "url": "https://github.com/janephp/json-schema-runtime.git", @@ -4298,13 +4298,13 @@ ], "description": "Jane runtime Library", "support": { - "source": "https://github.com/janephp/json-schema-runtime/tree/v7.4.4" + "source": "https://github.com/janephp/json-schema-runtime/tree/v7.5.0" }, "time": "2023-01-24T07:25:29+00:00" }, { "name": "jane-php/open-api-runtime", - "version": "v7.4.4", + "version": "v7.5.0", "source": { "type": "git", "url": "https://github.com/janephp/open-api-runtime.git", @@ -4361,7 +4361,7 @@ ], "description": "Jane OpenAPI Runtime Library, dependencies and utility class for a library generated by jane/openapi", "support": { - "source": "https://github.com/janephp/open-api-runtime/tree/v7.4.4" + "source": "https://github.com/janephp/open-api-runtime/tree/v7.5.0" }, "time": "2021-12-16T13:26:58+00:00" }, @@ -6614,21 +6614,20 @@ }, { "name": "nyholm/psr7", - "version": "1.7.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7.git", - "reference": "ed7cf98f6562831dbc3c962406b5e49dc8179c8c" + "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/ed7cf98f6562831dbc3c962406b5e49dc8179c8c", - "reference": "ed7cf98f6562831dbc3c962406b5e49dc8179c8c", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/3cb4d163b58589e47b35103e8e5e6a6a475b47be", + "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be", "shasum": "" }, "require": { "php": ">=7.2", - "php-http/message-factory": "^1.0", "psr/http-factory": "^1.0", "psr/http-message": "^1.1 || ^2.0" }, @@ -6639,14 +6638,15 @@ }, "require-dev": { "http-interop/http-factory-tests": "^0.9", - "php-http/psr7-integration-tests": "^1.0@dev", - "phpunit/phpunit": "^7.5 || 8.5 || 9.4", + "php-http/message-factory": "^1.0", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", "symfony/error-handler": "^4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -6676,7 +6676,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.7.0" + "source": "https://github.com/Nyholm/psr7/tree/1.8.0" }, "funding": [ { @@ -6688,7 +6688,7 @@ "type": "github" } ], - "time": "2023-04-20T08:38:48+00:00" + "time": "2023-05-02T11:26:24+00:00" }, { "name": "opis/closure", @@ -6983,16 +6983,16 @@ }, { "name": "php-http/discovery", - "version": "1.15.3", + "version": "1.18.0", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "3ccd28dd9fb34b52db946abea1b538568e34eae8" + "reference": "29ae6fae35f4116bbfe4c8b96ccc3f687eb07cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/3ccd28dd9fb34b52db946abea1b538568e34eae8", - "reference": "3ccd28dd9fb34b52db946abea1b538568e34eae8", + "url": "https://api.github.com/repos/php-http/discovery/zipball/29ae6fae35f4116bbfe4c8b96ccc3f687eb07cd9", + "reference": "29ae6fae35f4116bbfe4c8b96ccc3f687eb07cd9", "shasum": "" }, "require": { @@ -7000,7 +7000,8 @@ "php": "^7.1 || ^8.0" }, "conflict": { - "nyholm/psr7": "<1.0" + "nyholm/psr7": "<1.0", + "zendframework/zend-diactoros": "*" }, "provide": { "php-http/async-client-implementation": "*", @@ -7025,7 +7026,10 @@ "autoload": { "psr-4": { "Http\\Discovery\\": "src/" - } + }, + "exclude-from-classmap": [ + "src/Composer/Plugin.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -7051,9 +7055,9 @@ ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.15.3" + "source": "https://github.com/php-http/discovery/tree/1.18.0" }, - "time": "2023-03-31T14:40:37+00:00" + "time": "2023-05-03T14:49:12+00:00" }, { "name": "php-http/httplug", @@ -7237,36 +7241,30 @@ }, { "name": "php-http/multipart-stream-builder", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/php-http/multipart-stream-builder.git", - "reference": "11c1d31f72e01c738bbce9e27649a7cca829c30e" + "reference": "f5938fd135d9fa442cc297dc98481805acfe2b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/11c1d31f72e01c738bbce9e27649a7cca829c30e", - "reference": "11c1d31f72e01c738bbce9e27649a7cca829c30e", + "url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/f5938fd135d9fa442cc297dc98481805acfe2b6a", + "reference": "f5938fd135d9fa442cc297dc98481805acfe2b6a", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", - "php-http/discovery": "^1.7", - "php-http/message-factory": "^1.0.2", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" + "php-http/discovery": "^1.15", + "psr/http-factory-implementation": "^1.0" }, "require-dev": { "nyholm/psr7": "^1.0", "php-http/message": "^1.5", + "php-http/message-factory": "^1.0.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, "autoload": { "psr-4": { "Http\\Message\\MultipartStream\\": "src/" @@ -7293,9 +7291,9 @@ ], "support": { "issues": "https://github.com/php-http/multipart-stream-builder/issues", - "source": "https://github.com/php-http/multipart-stream-builder/tree/1.2.0" + "source": "https://github.com/php-http/multipart-stream-builder/tree/1.3.0" }, - "time": "2021-05-21T08:32:01+00:00" + "time": "2023-04-28T14:10:22+00:00" }, { "name": "php-http/promise", @@ -8295,23 +8293,23 @@ }, { "name": "react/promise", - "version": "v2.9.0", + "version": "v2.10.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910" + "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/234f8fd1023c9158e2314fa9d7d0e6a83db42910", - "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910", + "url": "https://api.github.com/repos/reactphp/promise/zipball/f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", "shasum": "" }, "require": { "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36" + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { @@ -8355,19 +8353,15 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.9.0" + "source": "https://github.com/reactphp/promise/tree/v2.10.0" }, "funding": [ { - "url": "https://github.com/WyriHaximus", - "type": "github" - }, - { - "url": "https://github.com/clue", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2022-02-11T10:27:51+00:00" + "time": "2023-05-02T15:15:43+00:00" }, { "name": "rodneyrehm/plist", @@ -8492,16 +8486,16 @@ }, { "name": "spatie/db-dumper", - "version": "3.3.0", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/spatie/db-dumper.git", - "reference": "129b8254b2c9f10881a754a692bd9507b09a1893" + "reference": "3b9fd47899bf6a59d3452392121c9ce675d55d34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/db-dumper/zipball/129b8254b2c9f10881a754a692bd9507b09a1893", - "reference": "129b8254b2c9f10881a754a692bd9507b09a1893", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/3b9fd47899bf6a59d3452392121c9ce675d55d34", + "reference": "3b9fd47899bf6a59d3452392121c9ce675d55d34", "shasum": "" }, "require": { @@ -8509,7 +8503,7 @@ "symfony/process": "^5.0|^6.0" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "pestphp/pest": "^1.22" }, "type": "library", "autoload": { @@ -8539,7 +8533,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/db-dumper/tree/3.3.0" + "source": "https://github.com/spatie/db-dumper/tree/3.3.1" }, "funding": [ { @@ -8551,7 +8545,7 @@ "type": "github" } ], - "time": "2022-09-01T20:20:26+00:00" + "time": "2023-05-02T11:05:31+00:00" }, { "name": "spatie/image", @@ -9382,16 +9376,16 @@ }, { "name": "spatie/temporary-directory", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/spatie/temporary-directory.git", - "reference": "e2818d871783d520b319c2d38dc37c10ecdcde20" + "reference": "0c804873f6b4042aa8836839dca683c7d0f71831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/e2818d871783d520b319c2d38dc37c10ecdcde20", - "reference": "e2818d871783d520b319c2d38dc37c10ecdcde20", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/0c804873f6b4042aa8836839dca683c7d0f71831", + "reference": "0c804873f6b4042aa8836839dca683c7d0f71831", "shasum": "" }, "require": { @@ -9427,7 +9421,7 @@ ], "support": { "issues": "https://github.com/spatie/temporary-directory/issues", - "source": "https://github.com/spatie/temporary-directory/tree/2.1.1" + "source": "https://github.com/spatie/temporary-directory/tree/2.1.2" }, "funding": [ { @@ -9439,7 +9433,7 @@ "type": "github" } ], - "time": "2022-08-23T07:15:15+00:00" + "time": "2023-04-28T07:47:42+00:00" }, { "name": "spomky-labs/base64url", @@ -9764,16 +9758,16 @@ }, { "name": "symfony/cache", - "version": "v6.2.8", + "version": "v6.2.10", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "76babfd82f6bfd8f6cbe851a153b95dd074ffc53" + "reference": "1ce7ed8e7ca6948892b6a3a52bb60cf2b04f7c94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/76babfd82f6bfd8f6cbe851a153b95dd074ffc53", - "reference": "76babfd82f6bfd8f6cbe851a153b95dd074ffc53", + "url": "https://api.github.com/repos/symfony/cache/zipball/1ce7ed8e7ca6948892b6a3a52bb60cf2b04f7c94", + "reference": "1ce7ed8e7ca6948892b6a3a52bb60cf2b04f7c94", "shasum": "" }, "require": { @@ -9782,7 +9776,7 @@ "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^1.1.7|^2|^3", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/var-exporter": "^6.2.7" + "symfony/var-exporter": "^6.2.10" }, "conflict": { "doctrine/dbal": "<2.13.1", @@ -9840,7 +9834,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.2.8" + "source": "https://github.com/symfony/cache/tree/v6.2.10" }, "funding": [ { @@ -9856,7 +9850,7 @@ "type": "tidelift" } ], - "time": "2023-03-30T07:37:32+00:00" + "time": "2023-04-21T15:42:15+00:00" }, { "name": "symfony/cache-contracts", @@ -9939,16 +9933,16 @@ }, { "name": "symfony/console", - "version": "v5.4.22", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8" + "reference": "90f21e27d0d88ce38720556dd164d4a1e4c3934c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8", - "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8", + "url": "https://api.github.com/repos/symfony/console/zipball/90f21e27d0d88ce38720556dd164d4a1e4c3934c", + "reference": "90f21e27d0d88ce38720556dd164d4a1e4c3934c", "shasum": "" }, "require": { @@ -10018,7 +10012,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.22" + "source": "https://github.com/symfony/console/tree/v5.4.23" }, "funding": [ { @@ -10034,7 +10028,7 @@ "type": "tidelift" } ], - "time": "2023-03-25T09:27:28+00:00" + "time": "2023-04-24T18:47:29+00:00" }, { "name": "symfony/css-selector", @@ -10170,16 +10164,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.4.21", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "56a94aa8cb5a5fbc411551d8d014a296b5456549" + "reference": "218206b4772d9f412d7d277980c020d06e9d8a4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/56a94aa8cb5a5fbc411551d8d014a296b5456549", - "reference": "56a94aa8cb5a5fbc411551d8d014a296b5456549", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/218206b4772d9f412d7d277980c020d06e9d8a4e", + "reference": "218206b4772d9f412d7d277980c020d06e9d8a4e", "shasum": "" }, "require": { @@ -10221,7 +10215,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.21" + "source": "https://github.com/symfony/error-handler/tree/v5.4.23" }, "funding": [ { @@ -10237,7 +10231,7 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2023-04-17T10:03:27+00:00" }, { "name": "symfony/event-dispatcher", @@ -10466,16 +10460,16 @@ }, { "name": "symfony/http-client", - "version": "v6.2.9", + "version": "v6.2.10", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "7daf5d24c21a683164688b95bb73b7a4bd3b32fc" + "reference": "3f5545a91c8e79dedd1a06c4b04e1682c80c42f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/7daf5d24c21a683164688b95bb73b7a4bd3b32fc", - "reference": "7daf5d24c21a683164688b95bb73b7a4bd3b32fc", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3f5545a91c8e79dedd1a06c4b04e1682c80c42f9", + "reference": "3f5545a91c8e79dedd1a06c4b04e1682c80c42f9", "shasum": "" }, "require": { @@ -10534,7 +10528,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.2.9" + "source": "https://github.com/symfony/http-client/tree/v6.2.10" }, "funding": [ { @@ -10550,7 +10544,7 @@ "type": "tidelift" } ], - "time": "2023-04-11T16:03:19+00:00" + "time": "2023-04-20T13:12:48+00:00" }, { "name": "symfony/http-client-contracts", @@ -10635,16 +10629,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.4.22", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "05cd1acdd0e3ce8473aaba1d86c188321d85f313" + "reference": "af9fbb378f5f956c8f29d4886644c84c193780ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/05cd1acdd0e3ce8473aaba1d86c188321d85f313", - "reference": "05cd1acdd0e3ce8473aaba1d86c188321d85f313", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/af9fbb378f5f956c8f29d4886644c84c193780ac", + "reference": "af9fbb378f5f956c8f29d4886644c84c193780ac", "shasum": "" }, "require": { @@ -10691,7 +10685,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.22" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.23" }, "funding": [ { @@ -10707,20 +10701,20 @@ "type": "tidelift" } ], - "time": "2023-03-28T07:28:17+00:00" + "time": "2023-04-18T06:30:11+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.22", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "2d3a8be2c756353627398827c409af6f126c096d" + "reference": "48ea17a7c65ef1ede0c3b2dbc35adace99071810" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/2d3a8be2c756353627398827c409af6f126c096d", - "reference": "2d3a8be2c756353627398827c409af6f126c096d", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/48ea17a7c65ef1ede0c3b2dbc35adace99071810", + "reference": "48ea17a7c65ef1ede0c3b2dbc35adace99071810", "shasum": "" }, "require": { @@ -10803,7 +10797,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.22" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.23" }, "funding": [ { @@ -10819,20 +10813,20 @@ "type": "tidelift" } ], - "time": "2023-03-31T11:54:37+00:00" + "time": "2023-04-28T13:29:52+00:00" }, { "name": "symfony/mime", - "version": "v5.4.21", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd" + "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd", - "reference": "ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd", + "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3", + "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3", "shasum": "" }, "require": { @@ -10887,7 +10881,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.21" + "source": "https://github.com/symfony/mime/tree/v5.4.23" }, "funding": [ { @@ -10903,7 +10897,7 @@ "type": "tidelift" } ], - "time": "2023-02-21T19:46:44+00:00" + "time": "2023-04-19T09:49:13+00:00" }, { "name": "symfony/options-resolver", @@ -11712,16 +11706,16 @@ }, { "name": "symfony/process", - "version": "v5.4.22", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b" + "reference": "4b842fc4b61609e0a155a114082bd94e31e98287" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/4b850da0cc3a2a9181c1ed407adbca4733dc839b", - "reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b", + "url": "https://api.github.com/repos/symfony/process/zipball/4b842fc4b61609e0a155a114082bd94e31e98287", + "reference": "4b842fc4b61609e0a155a114082bd94e31e98287", "shasum": "" }, "require": { @@ -11754,7 +11748,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.22" + "source": "https://github.com/symfony/process/tree/v5.4.23" }, "funding": [ { @@ -11770,7 +11764,7 @@ "type": "tidelift" } ], - "time": "2023-03-06T21:29:33+00:00" + "time": "2023-04-18T13:50:24+00:00" }, { "name": "symfony/routing", @@ -11864,16 +11858,16 @@ }, { "name": "symfony/serializer", - "version": "v6.2.8", + "version": "v6.2.10", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "db9d36470bf0990990fda9320b8b001bb582f075" + "reference": "0732edf0ad28dd3faacde4f1200ab9d7a4d5f40d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/db9d36470bf0990990fda9320b8b001bb582f075", - "reference": "db9d36470bf0990990fda9320b8b001bb582f075", + "url": "https://api.github.com/repos/symfony/serializer/zipball/0732edf0ad28dd3faacde4f1200ab9d7a4d5f40d", + "reference": "0732edf0ad28dd3faacde4f1200ab9d7a4d5f40d", "shasum": "" }, "require": { @@ -11945,7 +11939,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.2.8" + "source": "https://github.com/symfony/serializer/tree/v6.2.10" }, "funding": [ { @@ -11961,7 +11955,7 @@ "type": "tidelift" } ], - "time": "2023-03-31T09:14:44+00:00" + "time": "2023-04-18T13:57:49+00:00" }, { "name": "symfony/service-contracts", @@ -12313,16 +12307,16 @@ }, { "name": "symfony/var-dumper", - "version": "v5.4.22", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4" + "reference": "9a8a5b6d6508928174ded2109e29328a55342a42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4", - "reference": "e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a8a5b6d6508928174ded2109e29328a55342a42", + "reference": "9a8a5b6d6508928174ded2109e29328a55342a42", "shasum": "" }, "require": { @@ -12382,7 +12376,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.22" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.23" }, "funding": [ { @@ -12398,20 +12392,20 @@ "type": "tidelift" } ], - "time": "2023-03-25T09:27:28+00:00" + "time": "2023-04-18T09:26:27+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.2.8", + "version": "v6.2.10", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "8302bb670204500d492c6b8c595ee9a27da62cd6" + "reference": "9a07920c2058bafee921ce4d90aeef2193837d63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/8302bb670204500d492c6b8c595ee9a27da62cd6", - "reference": "8302bb670204500d492c6b8c595ee9a27da62cd6", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/9a07920c2058bafee921ce4d90aeef2193837d63", + "reference": "9a07920c2058bafee921ce4d90aeef2193837d63", "shasum": "" }, "require": { @@ -12456,7 +12450,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.2.8" + "source": "https://github.com/symfony/var-exporter/tree/v6.2.10" }, "funding": [ { @@ -12472,20 +12466,20 @@ "type": "tidelift" } ], - "time": "2023-03-14T15:48:45+00:00" + "time": "2023-04-21T08:33:05+00:00" }, { "name": "symfony/yaml", - "version": "v6.2.7", + "version": "v6.2.10", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e8e6a1d59e050525f27a1f530aa9703423cb7f57" + "reference": "61916f3861b1e9705b18cfde723921a71dd1559d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e8e6a1d59e050525f27a1f530aa9703423cb7f57", - "reference": "e8e6a1d59e050525f27a1f530aa9703423cb7f57", + "url": "https://api.github.com/repos/symfony/yaml/zipball/61916f3861b1e9705b18cfde723921a71dd1559d", + "reference": "61916f3861b1e9705b18cfde723921a71dd1559d", "shasum": "" }, "require": { @@ -12530,7 +12524,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.2.7" + "source": "https://github.com/symfony/yaml/tree/v6.2.10" }, "funding": [ { @@ -12546,7 +12540,7 @@ "type": "tidelift" } ], - "time": "2023-02-16T09:57:23+00:00" + "time": "2023-04-28T13:25:36+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -14587,16 +14581,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.20.2", + "version": "1.20.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81" + "reference": "7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/90490bd8fd8530a272043c4950c180b6d0cf5f81", - "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd", + "reference": "7d568c87a9df9c5f7e8b5f075fc469aa8cb0a4cd", "shasum": "" }, "require": { @@ -14626,9 +14620,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.2" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.4" }, - "time": "2023-04-22T12:59:35+00:00" + "time": "2023-05-02T09:19:37+00:00" }, { "name": "phpunit/php-code-coverage", @@ -15026,16 +15020,16 @@ }, { "name": "psy/psysh", - "version": "v0.11.15", + "version": "v0.11.16", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "5350ce0ec8ecf2c5b5cf554cd2496f97b444af85" + "reference": "151b145906804eea8e5d71fea23bfb470c904bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/5350ce0ec8ecf2c5b5cf554cd2496f97b444af85", - "reference": "5350ce0ec8ecf2c5b5cf554cd2496f97b444af85", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/151b145906804eea8e5d71fea23bfb470c904bfb", + "reference": "151b145906804eea8e5d71fea23bfb470c904bfb", "shasum": "" }, "require": { @@ -15096,9 +15090,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.15" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.16" }, - "time": "2023-04-07T21:57:09+00:00" + "time": "2023-04-26T12:53:57+00:00" }, { "name": "sebastian/code-unit-reverse-lookup",