Completed
Pull Request — master (#1993)
by Marc
02:16
created

TextToSpeechWidget::init()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.6111
c 0
b 0
f 0
cc 5
nc 3
nop 0
1
<?php
2
3
namespace luya\texttospeech;
4
5
use luya\base\Widget;
6
use luya\helpers\Json;
7
use Yii;
8
use yii\base\InvalidConfigException;
9
10
/**
11
 * Text to Speech.
12
 *
13
 * Using the browsers text to speech option to return a websites text. Either be providing the text as string or read the text from a given css class selector.
14
 *
15
 * Example using a Selector:
16
 *
17
 * ```
18
 * <?php
19
 * TextToSpeechWidget::widget(['targetSelector' => '#content']);
20
 * ?>
21
 * <div id="content">
22
 *    Hello World, this is LUYA Text to Speech!
23
 * </div>
24
 * ```
25
 *
26
 * By default the Widget will generate a play, pause and stop icon at the location the widget is integrated.
27
 *
28
 * @author Martin Petrasch <[email protected]>
29
 * @author Basil Suter <[email protected]>
30
 * @since 1.1.0
31
 */
32
class TextToSpeechWidget extends Widget
33
{
34
    /**
35
     * @var string The jQuery selector which should be used to read the content from, examples:
36
     * - `.container`: All elements which class `.container` will be spoken.
37
     * - `#content`: The element with id `id="content"` only will be spoken.
38
     *
39
     * The input data will be wrapped with `$()`.
40
     */
41
    public $targetSelector;
42
43
    /**
44
     * @var string If enabled, the {{$targetSelector}} attribute has no effect and only the text from the property will be read - on start.
45
     */
46
    public $text;
47
48
    /**
49
     * @var string The selector for the play button.
50
     */
51
    public $playButtonSelector = '#play-button';
52
53
    /**
54
     * @var string The selector for the pause button.
55
     */
56
    public $pauseButtonSelector = '#pause-button';
57
58
    /**
59
     * @var string The selector for the stop button.
60
     */
61
    public $stopButtonSelector = '#stop-button';
62
63
    /**
64
     * @var string The class which will be assigned to the play button when playing sound.
65
     */
66
    public $playButtonActiveClass = 'playing';
67
68
    /**
69
     * @var string The class which will be assigned to the pause button when pause button is clicked.
70
     */
71
    public $pauseButtonActiveClass = 'paused';
72
73
    /**
74
     * @var string The class of the div in which the buttons are located, the button wrapper div class.
75
     */
76
    public $containerClass = 'text-to-speech-container';
77
78
    /**
79
     * @var string The class which each of the text-to-speech buttons recieves.
80
     */
81
    public $buttonClass = 'btn text-to-speech-button';
82
83
    /**
84
     * @var integer The size of the default buttons, in pixel.
85
     */
86
    public $buttonSize = 30;
87
88
    /**
89
     * @var array|boolean You can either disable the default buttons by setting buttons to false, or you can provide an array with button configurations, each element requires the following keys:
90
     * - label:
91
     * - id:
92
     * - content:
93
     */
94
    public $buttons;
95
96
    /**
97
     * @var string The SVG code for the play icon when using default buttons.
98
     */
99
    public $playSVG = '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve"><g><path d="M45.563,29.174l-22-15c-0.307-0.208-0.703-0.231-1.031-0.058C22.205,14.289,22,14.629,22,15v30c0,0.371,0.205,0.711,0.533,0.884C22.679,45.962,22.84,46,23,46c0.197,0,0.394-0.059,0.563-0.174l22-15C45.836,30.64,46,30.331,46,30S45.836,29.36,45.563,29.174z M24,43.107V16.893L43.225,30L24,43.107z"/><path d="M30,0C13.458,0,0,13.458,0,30s13.458,30,30,30s30-13.458,30-30S46.542,0,30,0z M30,58C14.561,58,2,45.439,2,30S14.561,2,30,2s28,12.561,28,28S45.439,58,30,58z"/></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>';
100
101
    /**
102
     * @var string The SVG code for the stop icon when using default buttons.
103
     */
104
    public $stopSVG = '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve"><path d="M30,0C13.458,0,0,13.458,0,30s13.458,30,30,30s30-13.458,30-30S46.542,0,30,0z M44,44H16V16h28V44z"/><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>';
105
106
    /**
107
     * @var string The SVG code for the pause icon when using default buttons.
108
     */
109
    public $pauseSVG = '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 202.205 202.205" style="enable-background:new 0 0 202.205 202.205;" xml:space="preserve"><g> <g> <path style="fill:#010002;" d="M23.483,202.205H85.83V0H23.483V202.205z M31.417,7.934h46.479v186.336H31.417V7.934z"/> <path style="fill:#010002;" d="M116.372,0v202.205h62.351V0H116.372z M170.788,194.271h-46.486V7.934h46.482v186.336H170.788z"/> </g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>';
110
    
111
    /**
112
     * {@inheritDoc}
113
     */
114
    public function init()
115
    {
116
        if (!$this->text && !$this->targetSelector) {
117
            throw new InvalidConfigException("Either text or targetSelector property must be configured.");
118
        }
119
        if ($this->buttons === null || $this->buttons === true) {
120
            $this->buttons[] = $this->createButton('Play', 'play-button', $this->playSVG);
121
            $this->buttons[] = $this->createButton('Pause', 'pause-button', $this->pauseSVG);
122
            $this->buttons[] = $this->createButton('Stop', 'stop-button', $this->stopSVG);
123
        }
124
    }
125
126
    /**
127
     * {@inheritDoc}
128
     */
129
    public function run()
130
    {
131
        TextToSpeechAsset::register($this->view);
132
133
        $config = Json::htmlEncode([
134
            'text' => $this->text ? $this->text : '', // must be an empty string as it will checked with .length
135
            'language' => Yii::$app->composition->langShortCode,
136
        ]);
137
138
        $this->view->registerJs("
139
            var tts = $.textToSpeech({$config});
140
            var playButton = $('{$this->playButtonSelector}');
141
            var pauseButton = $('{$this->pauseButtonSelector}');
142
            " . ($this->targetSelector ? "tts.setText($('{$this->targetSelector}').text());" : "") . "
143
            var applyPlayClasses = function () {
144
                playButton.addClass('{$this->playButtonActiveClass}');
145
                pauseButton.removeClass('{$this->pauseButtonActiveClass}');
146
            };
147
            var applyPauseClasses = function () {
148
                playButton.removeClass('{$this->playButtonActiveClass}');
149
                pauseButton.addClass('{$this->pauseButtonActiveClass}');
150
            };
151
            var cleanupClasses = function () {
152
                playButton.removeClass('{$this->playButtonActiveClass}');
153
                pauseButton.removeClass('{$this->pauseButtonActiveClass}');
154
            };
155
            $('document').on('textToSpeech:play', applyPlayClasses);
156
            $('document').on('textToSpeech:pause', applyPauseClasses);
157
            $('document').on('textToSpeech:resume', applyPlayClasses);
158
            $('document').on('textToSpeech:stop', cleanupClasses);
159
            playButton.on('click', function() { tts.play() });
160
            pauseButton.on('click', function() { tts.pause() });
161
            $('{$this->stopButtonSelector}').on('click', function() { tts.stop() });
162
        ");
163
164
        return $this->render('texttospeech', [
165
            'buttons' => $this->buttons,
166
            'id' => $this->getId(),
167
            'containerClass' => $this->containerClass,
168
            'buttonClass' => $this->buttonClass,
169
            'buttonSize' => $this->buttonSize,
170
        ]);
171
    }
172
173
    /**
174
     * Create a default button element.
175
     *
176
     * @param string $label
177
     * @param string $id
178
     * @param string $svg
179
     * @return array
180
     */
181
    protected function createButton($label, $id, $svg)
182
    {
183
        return [
184
            'label' => $label,
185
            'id' => $id,
186
            'content' => $svg,
187
        ];
188
    }
189
}
190