Passed
Pull Request — master (#3)
by Jitendra
01:57
created

Yall::getTokenParsers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 2
b 0
f 1
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/*
4
 * This file is part of the TWIG-YALL package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\TwigYall;
13
14
use Twig\Extension\AbstractExtension;
15
use Twig\Markup;
16
use Twig\TwigFunction;
17
18
class Yall extends AbstractExtension
19
{
20
    /** @var array Configuration */
21
    protected $config = [];
22
23
    /**
24
     * Constructor
25
     *
26
     * @param array $config Optinal configuration
27
     */
28
    public function __construct(array $config = [])
29
    {
30
        $this->config = $config + [
31
            'polyfillJs'  => 'https://polyfill.io/%s/polyfill.min.js?features=IntersectionObserver',
32
            // @see: https://stackoverflow.com/a/15960901
33
            'placeholder' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAI=',
34
            'yallJs'      => 'https://unpkg.com/yall-js@%s/dist/yall.min.js',
35
            'lazyClass'   => 'lazy',
36
        ];
37
    }
38
39
    /**
40
     * Get twig functions defined by this extension.
41
     *
42
     * @return array
43
     */
44
    public function getFunctions(): array
45
    {
46
        return [
47
            new TwigFunction('lazify', [$this, 'lazify']),
48
            new TwigFunction('yallify', [$this, 'yallify']),
49
        ];
50
    }
51
52
    /**
53
     * Get token parsers defined by this extension.
54
     *
55
     * @return array
56
     */
57
    public function getTokenParsers(): array
58
    {
59
        return [new Parser($this->config['lazyClass'], $this->config['placeholder'])];
60
    }
61
62
    /**
63
     * Loads yall and polyfill scripts then triggers lazy loading.
64
     *
65
     * @param  string|null $yall     Yall version
66
     * @param  string|null $polyfill Polyfill version ('' = off)
67
     * @param  array       $options  Options for `yall({})` callback
68
     *
69
     * @return Markup
70
     */
71
    public function yallify(string $yall = null, string $polyfill = null, array $options = []): Markup
72
    {
73
        $yallJs   = \sprintf($this->config['yallJs'], $yall ?: '3.1.7');
74
        $options += ['lazyClass' => $this->config['lazyClass']];
75
        $jsonFlag = \JSON_UNESCAPED_SLASHES | \JSON_FORCE_OBJECT;
76
77
        $jsonOpts = \json_encode($options, $jsonFlag);
78
        $jsonOpts = \str_replace(['"<raw>', '</raw>"'], ['', ''], $jsonOpts);
79
80
        $markup = [
81
            $polyfill ?? 'v2'
82
                ? \sprintf('<script src="%s" async></script>', \sprintf($this->config['polyfillJs'], $polyfill ?? 'v2'))
83
                : '',
84
            \sprintf('<script src="%s" async></script>', $yallJs),
85
            '<script type="text/javascript">',
86
            'document.addEventListener("DOMContentLoaded", function() {',
87
            \sprintf('  window.setTimeout(function () { yall(%s); }, 99);', $jsonOpts),
88
            '});',
89
            '</script>',
90
        ];
91
92
        return new Markup(\implode("\n", $markup), 'UTF-8');
93
    }
94
95
    /**
96
     * Lazify resources.
97
     *
98
     * @param  string|string[] $src     The sources to lazy load
99
     * @param  string          $classes The optional element classes
100
     * @param  string          $dummy   The optional placeholder image
101
     *
102
     * @return Markup
103
     */
104
    public function lazify($src, string $classes = '', string $dummy = ''): Markup
105
    {
106
        $attr = 'src';
107
        if (\is_array($src)) {
108
            list($attr, $src) = $this->normalizeSrc($src);
109
        }
110
111
        $classes = \trim("$classes {$this->config['lazyClass']} yall");
112
        if ('srcset' !== $attr) {
113
            $dummy = \sprintf(' %s="%s"', $attr, $dummy ?: $this->config['placeholder']);
114
        }
115
116
        $markup = \sprintf('class="%s"%s data-%s="%s"', $classes, $dummy, $attr, $src);
117
118
        return new Markup($markup, 'UTF-8');
119
    }
120
121
    protected function normalizeSrc(array $src): array
122
    {
123
        if ($src['poster'] ?? false) {
124
            return ['poster', $src['poster']];
125
        }
126
127
        if ($src['srcset'] ?? false) {
128
            return ['srcset', $src['srcset']];
129
        }
130
131
        $srcset = $src;
132
        $src    = \array_shift($srcset);
133
134
        return ['src', $src . '" data-srcset="' . \implode(', ', $srcset)];
135
    }
136
}
137