]> _ Git - fluidbook_tools.git/commitdiff
wip #4666 @1
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Thu, 16 Sep 2021 14:10:45 +0000 (16:10 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Thu, 16 Sep 2021 14:10:45 +0000 (16:10 +0200)
25 files changed:
.idea/fluidbook_tools.iml
resources/tools/fwstk/bin/com/fluidbook/fwstk/CustomStripper.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/Link.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/Main.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/TextsThread.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/Word.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/CubeMatrix.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/CubeRectangle.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/Point.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Group.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutElement.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutStripper.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Letter.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Line.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Page.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Separator.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Space.class
resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Word.class
resources/tools/fwstk/bin/cube/files/FileIO.class
resources/tools/fwstk/bin/cube/util/Array.class
resources/tools/fwstk/bin/cube/util/AsciiUtils.class
resources/tools/fwstk/bin/cube/util/StringUtil.class
resources/tools/fwstk/out/artifacts/fwstk_jar/fwstk.jar
src/Compiler/Compiler.php [new file with mode: 0644]
src/Links/Link.php [new file with mode: 0644]

index 192d0126cb4992f567481b79c0834c9c6a23827d..0ad947ca14ac24c12fbbca9fd9cb6f8328f34f7f 100644 (file)
@@ -5,8 +5,6 @@
     <output-test url="file://$MODULE_DIR$/out/test/fluidbook_tools" />
     <exclude-output />
     <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/resources/tools/fwstk/project_resources" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/resources/tools/fwstk/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Fluidbook\Tools\" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/brick/math" />
index 2046775b29539a133aff12b4a3d4becf572bb94b..5448b332f72d1125e87c4088230323f4efed0da0 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/CustomStripper.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/CustomStripper.class differ
index 774dc6de41c5565c2dc1b80b2f75f253d0f6d61e..b29d1b3b62855d1b14177109546739836e75fe50 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/Link.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/Link.class differ
index 6a321372479760411382964aef0be6ccd5ae2854..b720a9cf93ffd158886d83d9c9317f72f2bbc019 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/Main.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/Main.class differ
index eda65a128836f80c1ddfef8c7df85533f3dd4f94..d207548dbba79e615f23830c17f97ef37ec2bfa0 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/TextsThread.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/TextsThread.class differ
index 28597e7339f1b8a3ecd7b2a3b7b4b96b2e30ad6d..7bcca85cddc3ca3946e2ebd9b1936a6c37cc2bf4 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/Word.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/Word.class differ
index 36caf87da30ff82ec173a10f734387b477a4a4b3..736ddf8c1e378856581e09ee5424e9426d8eaa51 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/CubeMatrix.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/CubeMatrix.class differ
index d6f95c5516c0b353ce775401687307c6896e77cb..cb1138cda0c5abd6d2f93488e84ae48835f81695 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/CubeRectangle.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/CubeRectangle.class differ
index a83392abb085045f9b62fabee197ec38f9e62925..8d28e76a3c1233f12d62625b687223e783802184 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/Point.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/geom/Point.class differ
index a44092de7c7ae8cd920c19392ac3cdae68cd0c06..3437b08d0c167a16275bd8f3ec54b49cb9e1eb7a 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Group.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Group.class differ
index aa32469da9fe5b3aab33977be2667494e38cfdb6..1fbfee2a1d9d0fc3ec98b0e5487bf2fc05da2844 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutElement.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutElement.class differ
index 98e65a3182256a03fa685e372650588a282432a3..02bb84ba689f2cde6754fef9c35b24a61e9e3084 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutStripper.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/LayoutStripper.class differ
index 6258134278d80bfaa54b98936be3609f750f4ea4..75841fa4bdfe3c139f0eea3924b614bf6315ac85 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Letter.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Letter.class differ
index 4415f5cc934a9870778b866bf8c92982f3f38da4..b2b8dfbfb95da59777c92c1e12e837cdb48d0920 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Line.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Line.class differ
index 054c1c377381e2d9a4c0ebc48ba623919d9a4e77..8e89fe65e3ae19cbf3600f71e4e1bf259789f71c 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Page.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Page.class differ
index 18ace2b3bf6fa6e8df711419a20cefaf96d20db1..48e3a22062184a47438bdf79e3a7f81f1fc88073 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Separator.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Separator.class differ
index e5a0d845e2e38d966f416993df35003ba7aff93e..c05fd7c4abb3fb3aa4cdc8dfc2d16b85f1844aa9 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Space.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Space.class differ
index 4539d3bf7ae3f3e3628c5cea31283958b054c498..06983f25640064d162826d795151f0381343bdeb 100644 (file)
Binary files a/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Word.class and b/resources/tools/fwstk/bin/com/fluidbook/fwstk/layout/Word.class differ
index 85452f9699fb13cf56e0ec045a7caa5689cdc65d..c2a4aaacd5e87c3e45a965e78f4f4c5574b52b71 100644 (file)
Binary files a/resources/tools/fwstk/bin/cube/files/FileIO.class and b/resources/tools/fwstk/bin/cube/files/FileIO.class differ
index 1d67ea60ab887dc3a173c9373ca29ae2ce212973..0c55de6d0503f6840c51c4210ac567fe67afd09c 100644 (file)
Binary files a/resources/tools/fwstk/bin/cube/util/Array.class and b/resources/tools/fwstk/bin/cube/util/Array.class differ
index 21c8b7ada299da537c7e0a08822314d86aeeba39..c28b8b3e3f3b67678004c2ba6c7f0869614230aa 100644 (file)
Binary files a/resources/tools/fwstk/bin/cube/util/AsciiUtils.class and b/resources/tools/fwstk/bin/cube/util/AsciiUtils.class differ
index 16a9c9eb10844e05c5f85a623acd81f805ff86f7..6f4f3df53bdf00ca60e0b1a5eca412db6fe8f8f2 100644 (file)
Binary files a/resources/tools/fwstk/bin/cube/util/StringUtil.class and b/resources/tools/fwstk/bin/cube/util/StringUtil.class differ
index d7a9ba26fa0f299efabd27a5d74085416e3def5a..4f3447a129cf1a13cd94fd2e46612f8d48ae4e53 100644 (file)
Binary files a/resources/tools/fwstk/out/artifacts/fwstk_jar/fwstk.jar and b/resources/tools/fwstk/out/artifacts/fwstk_jar/fwstk.jar differ
diff --git a/src/Compiler/Compiler.php b/src/Compiler/Compiler.php
new file mode 100644 (file)
index 0000000..06478d3
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+
+namespace Fluidbook\Tools\Compiler;
+
+use Cubist\Util\Files\Files;
+use Cubist\Util\Files\VirtualDirectory;
+use Cubist\Util\PHP;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldBeUnique;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\Jobs\SyncJob;
+use Illuminate\Queue\SerializesModels;
+
+class Compiler implements ShouldQueue, ShouldBeUnique
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    /** @var VirtualDirectory */
+    protected $vdir;
+
+    /**
+     * @var string
+     */
+    protected $out;
+
+    /**
+     * @var stdClass
+     */
+    protected $config;
+
+    public function __construct()
+    {
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        $sync = ($this->job instanceof SyncJob);
+        if ($sync) {
+            PHP::neverStop(false);
+        }
+
+        start_measure('Process Fluidbook');
+        $this->processPages($sync);
+        $this->getTexts();
+        $this->getLinks();
+        $this->compileFluidbook();
+        stop_measure('Process Fluidbook');
+    }
+
+    public function processPages($sync = false)
+    {
+        start_measure('Process Pages');
+        $out = $this->getConvertPath();
+        Files::mkdir($out);
+        $this->in->processPages($out, $this->getProcessFiles(), $sync);
+        stop_measure('Process Pages');
+    }
+
+    public function getConvertPath()
+    {
+        return storage_path('fluidbook/convert/' . $this->in->getHash() . '/');
+    }
+
+    public function getTexts()
+    {
+        start_measure('Process texts');
+        $this->in->processTexts($this->getConvertPath());
+        start_measure('Process texts');
+    }
+
+
+}
diff --git a/src/Links/Link.php b/src/Links/Link.php
new file mode 100644 (file)
index 0000000..7950bc9
--- /dev/null
@@ -0,0 +1,675 @@
+<?php
+
+namespace Fluidbook\Tools\Links;
+
+class Link
+{
+
+    public $left;
+    public $top;
+    public $width;
+    public $height;
+    public $page;
+    public $type;
+    public $to;
+    public $image;
+    public $numerotation;
+    public $target;
+    public $interactive;
+    public $video_loop;
+    public $video_sound_on;
+    public $video_controls;
+    public $video_auto_start;
+    public $video_height;
+    public $video_width;
+    public $video_service;
+    public $hidelinksonplay;
+    public $rollover;
+    public $inline;
+    public $in_popup = false;
+    public $display_area;
+    public $read_mode;
+    public $group;
+    public $infobulle;
+    public $blendmode = "normal";
+    public $extra;
+    public $id;
+    public $rot;
+    public $class;
+    public $uid;
+    public $scorm;
+    public $hidden = false;
+    public $defaultZIndex = 70;
+    public $zindex = -1;
+    public $addzindex = 0;
+    public $rightClone = false;
+    public $iframeType = "none";
+    public $border = 0;
+    public $borderColor = '#ffffff';
+    public $maxWidth = 0;
+    public $wdir;
+    public $initialOrder = 0;
+    public $gamifyCoins = 0;
+    public $tooltipColor = null;
+    public $tooltipBackgroundColor = null;
+    protected $role = 'button';
+
+    protected $_init;
+
+    /**
+     *
+     * @var wsHTML5Compiler
+     */
+    public $compiler;
+
+    /**
+     *
+     * @param integer $id
+     * @param stdClass $init
+     * @param wsHTML5Compiler $compiler
+     * @return wsHTML5Link
+     */
+    public static function getInstance($id, $init, &$compiler)
+    {
+        $init = wsLinks::decryptLink($init);
+        $init = CubeIT_Util_Array::asArray($init);
+
+        $init['scorm'] = self::isScorm($init);
+        $init['to'] = self::replaceCustomURL($init['to']);
+
+        switch ($init['type']) {
+            case 1:
+            case 2:
+                return new webLink($id, $init, $compiler);
+            case 3:
+                return new mailLink($id, $init, $compiler);
+            case 5:
+                return new internalLink($id, $init, $compiler);
+            case 4:
+
+                $init['inline'] = self::normalizeInlineIntegration($init['inline']);
+                if ($init['inline'] === 'inline') {
+                    $init['inline'] = 'inline';
+                    return new videoLink($id, $init, $compiler);
+                } else if ($init['inline'] === 'popup') {
+                    $init['inline'] = 'popup';
+                    return new videoPopupLink($id, $init, $compiler);
+                } else if ($init['inline'] === 'background_texts') {
+                    $init['inline'] = 'background_texts';
+                    return new videoBackgroundLink($id, $init, $compiler);
+                }
+
+            case 7:
+                if ($compiler->book->parametres->basketManager === 'Puma') {
+                    return new pumaCartLink($id, $init, $compiler);
+                }
+                if ($compiler->book->parametres->basketManager === 'MIF') {
+                    return new cartLink($id, $init, $compiler);
+                }
+                switch ($compiler->book->parametres->customLinkClass) {
+                    case 'WescoLink':
+                        return new wescoLink($id, $init, $compiler);
+                    case 'HaguenauManifLink':
+                        return new haguenauManifLink($id, $init, $compiler);
+                    case 'FLFLink':
+                        return new flfLink($id, $init, $compiler);
+                    case 'InpesPopinLink':
+                        return new inpesPopinLink($id, $init, $compiler);
+                    case 'PierronLink':
+                        return new pierronLink($id, $init, $compiler);
+                    case 'WescoSalesLink':
+                        return new wescoSalesLink($id, $init, $compiler);
+                    case 'AtlanticDownloadLink':
+                        return new atlanticDownloadLink($id, $init, $compiler);
+                    case 'MiraklEaster2021':
+                        return new miraklEaster2021Link($id, $init, $compiler);
+                    default :
+                        return customLink::getCustomInstance($id, $init, $compiler);
+                }
+            case 8:
+            case 9:
+                return null;
+            case 10:
+                $init['inline'] = self::normalizeInlineIntegration($init['inline']);
+                if ($init['inline'] === 'popup') {
+                    return new webVideoPopupLink($id, $init, $compiler);
+                }
+                return new webVideoLink($id, $init, $compiler);
+            case 11:
+                return new actionLink($id, $init, $compiler);
+            case 12:
+                if ($compiler->book->parametres->basketManager === 'Puma' || $compiler->book->parametres->basketManager === 'MIF' || $compiler->book->parametres->basketManager === 'Flexipan') {
+                    return new zoomProductLink($id, $init, $compiler);
+                }
+                if ($compiler->book->parametres->product_zoom_references !== '') {
+                    return new zoomProductLink($id, $init, $compiler);
+                }
+                switch ($compiler->book->parametres->basketManager) {
+                    case 'GrandVision':
+                        return new grandVisionCartLink($id, $init, $compiler);
+                    case 'JoueclubWishlist':
+                        return new JoueclubWishlistLink($id, $init, $compiler);
+                    case 'Remarkable':
+                        return new remarkableCartLink($id, $init, $compiler);
+                    case 'ZoomProductLink':
+                        return new zoomProductLink($id, $init, $compiler);
+                    default :
+                        return new cartLink($id, $init, $compiler);
+                }
+            case 13: // zoom area
+                return new zoomLink($id, $init, $compiler);
+            case 14:
+                return new colorLink($id, $init, $compiler);
+            case 15:
+                if (stristr($init['to'], '.zip')) {
+                    return new inlineSlideshowLink($id, $init, $compiler);
+                }
+                return new imageLink($id, $init, $compiler);
+            case 16:
+                return new fileLink($id, $init, $compiler);
+            case 17:
+
+                $init['inline'] = self::normalizeInlineIntegration($init['inline']);
+                if ($init['inline'] === 'inline') {
+                    return new audioLink($id, $init, $compiler);
+                }
+                return new audioPopupLink($id, $init, $compiler);
+            case 18:
+                $init['inline'] = self::normalizeInlineIntegration($init['inline']);
+                if ($init['inline'] === 'inline') {
+                    return new tooltipLink($id, $init, $compiler);
+                }
+                return new textPopupLink($id, $init, $compiler);
+            case 19:
+                break;
+            case 20:
+                $compiler->addBookmarkGroup($init);
+                break;
+            case 21:
+            case 6:
+                return self::getMultimediaInstance($id, $init, $compiler);
+            case 23:
+                return new statsTagLink($id, $init, $compiler);
+            case 24:
+                return new phoneLink($id, $init, $compiler);
+            case 25:
+                $compiler->addAudiodescription($init);
+                break;
+            case 26:
+            case 40:
+                return new anchorLink($id, $init, $compiler);
+            case 27:
+                return new eventOverlayLink($id, $init, $compiler);
+            case 29:
+                return new facebookLikeLink($id, $init, $compiler);
+            case 30:
+                return new slideshowLink($id, $init, $compiler);
+            case 31:
+                $init['inline'] = self::normalizeInlineIntegration($init['inline']);
+                if ($init['inline'] === 'inline') {
+                    return new iframeLink($id, $init, $compiler);
+                }
+                return new iframePopupLink($id, $init, $compiler);
+            case 32:
+                return new showLinkLink($id, $init, $compiler);
+            case 33:
+                return new zoomhdLink($id, $init, $compiler);
+            case 34:
+                $compiler->addContentLock($init['page'], $init['to']);
+                break;
+            case 35:
+                return new textLink($id, $init, $compiler);
+            case 36:
+                return new articleLink($id, $init, $compiler);
+            case 37:
+                return new downloadPortionLink($id, $init, $compiler);
+            case 38:
+                if ($init['target'] != 'click') {
+                    $compiler->addTriggersLink($init['page'], $init['to']);
+                } else {
+                    return new triggerLink($id, $init, $compiler);
+                }
+                break;
+            case 39:
+                return new layerLink($id, $init, $compiler);
+            default:
+                return null;
+        }
+
+
+    }
+
+    public function getSurface()
+    {
+        return $this->width * $this->height;
+    }
+
+    public static function normalizeInlineIntegration($inline)
+    {
+        if ($inline == '1' || $inline === 'true') {
+            return 'inline';
+
+        } else if (!$inline || $inline === 'false') {
+            return 'popup';
+        }
+        return $inline;
+    }
+
+    public static function parseExtras($extras, $normalizeKey = false)
+    {
+        $extras = trim($extras);
+        if ($extras === '') {
+            return [];
+        }
+        $res = [];
+        $lines = CubeIT_Text::splitLines($extras);
+        foreach ($lines as $line) {
+            $e = explode('=', $line);
+            if (count($e) < 2) {
+                continue;
+            }
+            $v = trim($e[1]);
+            // Handle values surronded by quotes
+            if (preg_match('|^\"([^\"]+)\"$|', $v, $matches)) {
+                $v = $matches[1];
+            }
+            $k = trim($e[0]);
+            if ($normalizeKey) {
+                $k = mb_strtolower($k);
+            }
+            $res[$k] = $v;
+        }
+
+        return $res;
+    }
+
+    public static function parseAnimations($animations)
+    {
+        $anims = explode('---', $animations);
+        $res = [];
+
+        foreach ($anims as $animation) {
+            $animation = trim($animation);
+            if (!$animation) {
+                continue;
+            }
+            $extras = self::parseExtras($animation, true);
+            if (count($extras) > 0) {
+                if (!isset($extras['direction'])) {
+                    $extras['direction'] = 'right';
+                }
+                if ($extras['direction'] === 'top') {
+                    $extras['direction'] = 'up';
+                }
+                if ($extras['direction'] === 'bottom') {
+                    $extras['direction'] = 'down';
+                }
+            }
+            $res[] = $extras;
+        }
+        return $res;
+    }
+
+    public static function replaceCustomURL($url)
+    {
+        $url = trim($url);
+        if (strpos($url, 'custom:') === 0) {
+            $e = explode(':', $url, 2);
+            return customLink::_getURL($e[1]);
+        }
+
+        return $url;
+    }
+
+    public static function getMultimediaInstance($id, $init, &$compiler)
+    {
+        if ($init['alternative'] == '') {
+            return null;
+        }
+        $init['inline'] = self::normalizeInlineIntegration($init['inline']);
+
+        $ext = mb_strtolower(files::getExtension($init['alternative']));
+
+        if (in_array($ext, array('oam', 'zip', 'html')) || substr($init['alternative'], 0, 4) == 'http') {
+            if ($init['inline'] === 'inline') {
+                return new htmlMultimediaLink($id, $init, $compiler);
+            } else {
+                return new htmlMultimediaPopupLink($id, $init, $compiler);
+            }
+        } else if (in_array($ext, array('gif', 'jpeg', 'jpg', 'png', 'svg'))) {
+            if ($init['inline'] === 'inline') {
+                return new htmlMultimediaImage($id, $init, $compiler);
+            } else {
+                return new htmlMultimediaPopupImage($id, $init, $compiler);
+            }
+        }
+        return null;
+    }
+
+    public static function isScorm($linkData)
+    {
+        return (isset($linkData['scorm']) && $linkData['scorm']) || (self::_isScormLink($linkData['to']) || (isset($linkData['alternative']) && self::_isScormLink($linkData['alternative'])));
+    }
+
+    protected static function _isScormLink($url)
+    {
+        if (strpos($url, 'http://') >= 0 || strpos($url, 'https://') > 0) {
+            return false;
+        }
+        return stristr($url, 'scorm');
+    }
+
+    public function __construct($id, $init, &$compiler)
+    {
+        $this->_init = $init;
+        foreach ($init as $k => $v) {
+            if ($k == 'extra') {
+                if (CubeIT_Util_Json::isJson($v)) {
+                    $v = CubeIT_Util_Json::decode($v);
+                } else if (strpos($v, '=') !== false && strpos($v, '&') !== false) {
+                    $vv = $v;
+                    $v = [];
+                    parse_str($vv, $v);
+                    $v = CubeIT_Util_Object::asObject($v);
+                } else if (strpos($v, '=') !== false) {
+                    $extras = self::parseExtras($v);
+                    foreach ($extras as $extrak => $extrav) {
+                        $this->$extrak = $extrav;
+                    }
+                    continue;
+                }
+            }
+            $this->$k = $v;
+        }
+        if (!$this->video_width) {
+            $this->video_width = $this->width;
+        }
+        if (!$this->video_height) {
+            $this->video_height = $this->height;
+        }
+        if ($this->target == '') {
+            $this->target = '_blank';
+        }
+
+        $this->id = $id;
+        $this->compiler = $compiler;
+        $this->wdir = $this->compiler->wdir;
+        $this->init();
+    }
+
+    /**
+     * @param int $initialOrder
+     */
+    public function setInitialOrder(int $initialOrder): void
+    {
+        $this->initialOrder = $initialOrder;
+    }
+
+    /**
+     * @return int
+     */
+    public function getInitialOrder(): int
+    {
+        return $this->initialOrder;
+    }
+
+    public function getDepth()
+    {
+        if ($this->zindex == -1 || null === $this->zindex || !$this->zindex) {
+            return $this->defaultZIndex;
+        }
+        if ($this->zindex < 10) {
+            return $this->zindex + $this->defaultZIndex;
+        }
+        return $this->zindex;
+    }
+
+    public function getTooltipAttribute($t = null)
+    {
+        if (null === $t) {
+            $t = $this->getTooltip();
+        }
+        if ($t !== false) {
+            $escaped = htmlspecialchars($t, ENT_QUOTES);
+            $tooltip = ' data-tooltip="' . $escaped . '"';
+            $tooltip .= ' aria-label="' . $escaped . '"';
+            return $tooltip;
+        } else {
+            return '';
+        }
+    }
+
+    public function overlapDoublePage()
+    {
+        // $this->page is normally an integer but it can also be a string (eg. background / aftersearch)
+        if (!is_int($this->page)) return false;
+
+        return ($this->page % 2 == 0 && $this->left + $this->width > $this->compiler->width);
+    }
+
+    public function getRightClone()
+    {
+        $res = clone $this;
+        $res->page++;
+        $res->left -= $this->compiler->width;
+        $res->rightClone = true;
+        $res->id .= '_c';
+        $res->init();
+        return $res;
+    }
+
+    public function init()
+    {
+
+    }
+
+    public function getDefaultTooltip()
+    {
+        return false;
+    }
+
+    public function getTooltip()
+    {
+        if ($this->infobulle === null || !$this->infobulle) {
+            if ($this->getDefaultTooltip() === false) {
+                return;
+            }
+            return '~' . $this->getDefaultTooltip();
+        }
+        return $this->infobulle;
+    }
+
+    public function getHTMLContainer()
+    {
+        $addContent = $this->getAdditionnalContent();
+        return '<div class="' . $this->getHTMLContainerClass() . '" data-blendmode="' . $this->blendmode . '" data-hidden="' . $this->hidden . '" data-scorm="' . $this->scorm . '" data-id="' . $this->uid . '" id="l_' . $this->id . '"' . $addContent . '>' . $this->getHTMLContent() . '</div>';
+    }
+
+    public function getHTMLContainerClass()
+    {
+        $res = trim('link ' . $this->class);
+        if ((int)$this->page % 2 == 1) {
+            $res .= ' odd';
+        }
+        if ($this->rightClone) {
+            $res .= ' rightclone';
+        }
+
+        return $res;
+    }
+
+    public function getHTMLContent()
+    {
+        return '';
+    }
+
+    public function getAdditionnalContent()
+    {
+        $res = '';
+        if ($this->role !== '') {
+            $res .= ' role="' . $this->role . '"';
+        }
+        if ($this->maxWidth > 0) {
+            $res .= ' data-max-width="' . $this->maxWidth . '"';
+        }
+        if (!isset($this->popupClose)) {
+            $this->popupClose = 1;
+        }
+        $res .= ' data-popup-close="' . $this->popupClose . '"';
+        if ($this->tooltipBackgroundColor) {
+            $res .= 'data-tooltip-background="' . $this->tooltipBackgroundColor . '" ';
+        }
+        if ($this->tooltipColor) {
+            $res .= 'data-tooltip-color="' . $this->tooltipColor . '" ';
+        }
+
+        return $res;
+
+    }
+
+    public function getClasses()
+    {
+
+        $res = array();
+        if (isset($this->image_rollover) && $this->image_rollover != 'none') {
+            $res[] = 'image_rollover';
+        }
+        return $res;
+    }
+
+    public function copyExternalFile($file, $video = false)
+    {
+        $this->compiler->copyLinkFile($file, 'data/links/', $video);
+    }
+
+    public function copyExternalDir($dir, $dest = 'data/links')
+    {
+        $this->compiler->copyLinkDir($dir, $dest);
+    }
+
+    public function unzipFile($file, $moveAssets = false)
+    {
+        return $this->compiler->unzipFile($file, $moveAssets);
+    }
+
+    public function getCssScale()
+    {
+        if (is_int($this->page)) {
+            return $this->compiler->getLinkScale();
+        } else {
+            return 1;
+        }
+    }
+
+    public function getCSSZIndex()
+    {
+        $zindex = $this->getAddZIndex() + (($this->getDepth() + 1) * 10000) - min(9999, max(1, round(9999 * (($this->width * $this->height) / $this->compiler->getBookSurface()))));
+        return 'z-index:' . $zindex . ';';
+    }
+
+    public function getAddZIndex()
+    {
+        return $this->addzindex;
+    }
+
+    public function moveOnEvenPage()
+    {
+        return false;
+    }
+
+    public function getCSSContainer()
+    {
+        if ($this->moveOnEvenPage()) {
+            $this->page--;
+            $this->left += $this->compiler->width;
+        }
+
+        $css = '#l_' . $this->id . '{';
+        $css .= 'left:' . round($this->left * $this->getCssScale()) . 'px;top:' . round($this->top * $this->getCssScale()) . 'px;';
+        $css .= 'width:' . round($this->width * $this->getCssScale()) . 'px;height:' . round($this->height * $this->getCssScale()) . 'px;';
+        $css .= $this->getCSSZIndex();
+        $origin = false;
+        if ($this->rot) {
+            $css .= wsHTML5::writeCSSUA('transform', 'rotate(' . $this->rot . 'deg)');
+            $origin = true;
+        }
+        if (isset($this->skewX)) {
+            $css .= wsHTML5::writeCSSUA('transform', 'skewX(' . $this->skewX . 'deg)');
+            $origin = true;
+        }
+        if (isset($this->skew)) {
+            $css .= wsHTML5::writeCSSUA('transform', 'skew(' . $this->skew . ')');
+            $origin = true;
+        }
+
+        $css .= $this->getCSS();
+        $css .= '}';
+        return $css;
+    }
+
+    public function getCSS()
+    {
+        return '';
+    }
+
+    public function keep()
+    {
+        return false;
+    }
+
+    public static function getUniversalLocation($loc, $css = false)
+    {
+        $datas = parse_url($loc);
+
+        if ((isset($datas['scheme']) && !is_null($datas['scheme'])) || strpos($loc, '#') === 0) {
+
+            return $loc;
+        } else {
+            if ($css) {
+                return '../links/' . $loc;
+            } else {
+                return 'data/links/' . $loc;
+            }
+        }
+    }
+
+    public function getConfigZIP($d)
+    {
+        return $this->compiler->getConfigZIP($d);
+    }
+
+    public function getConfigHTML($d, $html)
+    {
+        $res = array('width' => $this->video_width, 'height' => $this->video_height);
+        $r = array('type' => 'html', 'html' => $html, 'inject' => array(), 'injectcss' => array(), 'injectjs' => array());
+
+        return array_merge($res, $r);
+    }
+
+    public function getConfigOAM($d)
+    {
+        $x = simplexml_load_string(file_get_contents($d . '/config.xml'));
+        $config = (string)$x->oamfile['src'];
+        $config = str_replace('/Assets', '', $d . '/' . $config);
+        $x = simplexml_load_string(file_get_contents($config), 'SimpleXMLElement', LIBXML_NOCDATA);
+        $c = CubeIT_Util_Xml::toObject($x);
+
+        $props = array('default-width' => 'width', 'default-height' => 'height', 'html-page' => 'html');
+
+
+        $res = array('type' => 'oam', 'inject' => array(), 'injectcss' => array(), 'injectjs' => array(), 'content' => trim($c->content), 'name' => $c->_name, 'assets' => array());
+        foreach ($c->properties->property as $p) {
+            if (isset($props[$p->_name])) {
+                $res[$props[$p->_name]] = $p->_defaultValue;
+            }
+        }
+        foreach ($c->require as $r) {
+            if ($r->_type == 'folder') {
+                continue;
+            }
+            $res['assets'][] = $r->_src;
+        }
+        return $res;
+    }
+
+}