Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/*
17
 * @package    atto_media
18
 * @copyright  2013 Damyon Wiese  <damyon@moodle.com>
19
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
20
 */
21
 
22
/**
23
 * @module moodle-atto_media-button
24
 */
25
 
26
/**
27
 * Atto media selection tool.
28
 *
29
 * @namespace M.atto_media
30
 * @class Button
31
 * @extends M.editor_atto.EditorPlugin
32
 */
33
 
34
var COMPONENTNAME = 'atto_media',
35
    MEDIA_TYPES = {LINK: 'LINK', VIDEO: 'VIDEO', AUDIO: 'AUDIO'},
36
    TRACK_KINDS = {
37
        SUBTITLES: 'SUBTITLES',
38
        CAPTIONS: 'CAPTIONS',
39
        DESCRIPTIONS: 'DESCRIPTIONS',
40
        CHAPTERS: 'CHAPTERS',
41
        METADATA: 'METADATA'
42
    },
43
    CSS = {
44
        SOURCE: 'atto_media_source',
45
        TRACK: 'atto_media_track',
46
        MEDIA_SOURCE: 'atto_media_media_source',
47
        LINK_SOURCE: 'atto_media_link_source',
48
        POSTER_SOURCE: 'atto_media_poster_source',
49
        TRACK_SOURCE: 'atto_media_track_source',
50
        DISPLAY_OPTIONS: 'atto_media_display_options',
51
        NAME_INPUT: 'atto_media_name_entry',
52
        TITLE_INPUT: 'atto_media_title_entry',
53
        URL_INPUT: 'atto_media_url_entry',
54
        POSTER_SIZE: 'atto_media_poster_size',
55
        LINK_SIZE: 'atto_media_link_size',
56
        WIDTH_INPUT: 'atto_media_width_entry',
57
        HEIGHT_INPUT: 'atto_media_height_entry',
58
        TRACK_KIND_INPUT: 'atto_media_track_kind_entry',
59
        TRACK_LABEL_INPUT: 'atto_media_track_label_entry',
60
        TRACK_LANG_INPUT: 'atto_media_track_lang_entry',
61
        TRACK_DEFAULT_SELECT: 'atto_media_track_default',
62
        MEDIA_CONTROLS_TOGGLE: 'atto_media_controls',
63
        MEDIA_AUTOPLAY_TOGGLE: 'atto_media_autoplay',
64
        MEDIA_MUTE_TOGGLE: 'atto_media_mute',
65
        MEDIA_LOOP_TOGGLE: 'atto_media_loop',
66
        ADVANCED_SETTINGS: 'atto_media_advancedsettings',
67
        LINK: MEDIA_TYPES.LINK.toLowerCase(),
68
        VIDEO: MEDIA_TYPES.VIDEO.toLowerCase(),
69
        AUDIO: MEDIA_TYPES.AUDIO.toLowerCase(),
70
        TRACK_SUBTITLES: TRACK_KINDS.SUBTITLES.toLowerCase(),
71
        TRACK_CAPTIONS: TRACK_KINDS.CAPTIONS.toLowerCase(),
72
        TRACK_DESCRIPTIONS: TRACK_KINDS.DESCRIPTIONS.toLowerCase(),
73
        TRACK_CHAPTERS: TRACK_KINDS.CHAPTERS.toLowerCase(),
74
        TRACK_METADATA: TRACK_KINDS.METADATA.toLowerCase()
75
    },
76
    SELECTORS = {
77
        SOURCE: '.' + CSS.SOURCE,
78
        TRACK: '.' + CSS.TRACK,
79
        MEDIA_SOURCE: '.' + CSS.MEDIA_SOURCE,
80
        POSTER_SOURCE: '.' + CSS.POSTER_SOURCE,
81
        TRACK_SOURCE: '.' + CSS.TRACK_SOURCE,
82
        DISPLAY_OPTIONS: '.' + CSS.DISPLAY_OPTIONS,
83
        NAME_INPUT: '.' + CSS.NAME_INPUT,
84
        TITLE_INPUT: '.' + CSS.TITLE_INPUT,
85
        URL_INPUT: '.' + CSS.URL_INPUT,
86
        POSTER_SIZE: '.' + CSS.POSTER_SIZE,
87
        LINK_SIZE: '.' + CSS.LINK_SIZE,
88
        WIDTH_INPUT: '.' + CSS.WIDTH_INPUT,
89
        HEIGHT_INPUT: '.' + CSS.HEIGHT_INPUT,
90
        TRACK_KIND_INPUT: '.' + CSS.TRACK_KIND_INPUT,
91
        TRACK_LABEL_INPUT: '.' + CSS.TRACK_LABEL_INPUT,
92
        TRACK_LANG_INPUT: '.' + CSS.TRACK_LANG_INPUT,
93
        TRACK_DEFAULT_SELECT: '.' + CSS.TRACK_DEFAULT_SELECT,
94
        MEDIA_CONTROLS_TOGGLE: '.' + CSS.MEDIA_CONTROLS_TOGGLE,
95
        MEDIA_AUTOPLAY_TOGGLE: '.' + CSS.MEDIA_AUTOPLAY_TOGGLE,
96
        MEDIA_MUTE_TOGGLE: '.' + CSS.MEDIA_MUTE_TOGGLE,
97
        MEDIA_LOOP_TOGGLE: '.' + CSS.MEDIA_LOOP_TOGGLE,
98
        ADVANCED_SETTINGS: '.' + CSS.ADVANCED_SETTINGS,
99
        LINK_TAB: 'li[data-medium-type="' + CSS.LINK + '"]',
100
        LINK_PANE: '.tab-pane[data-medium-type="' + CSS.LINK + '"]',
101
        VIDEO_TAB: 'li[data-medium-type="' + CSS.VIDEO + '"]',
102
        VIDEO_PANE: '.tab-pane[data-medium-type="' + CSS.VIDEO + '"]',
103
        AUDIO_TAB: 'li[data-medium-type="' + CSS.AUDIO + '"]',
104
        AUDIO_PANE: '.tab-pane[data-medium-type="' + CSS.AUDIO + '"]',
105
        TRACK_SUBTITLES_TAB: 'li[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]',
106
        TRACK_SUBTITLES_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_SUBTITLES + '"]',
107
        TRACK_CAPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]',
108
        TRACK_CAPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CAPTIONS + '"]',
109
        TRACK_DESCRIPTIONS_TAB: 'li[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]',
110
        TRACK_DESCRIPTIONS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_DESCRIPTIONS + '"]',
111
        TRACK_CHAPTERS_TAB: 'li[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]',
112
        TRACK_CHAPTERS_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_CHAPTERS + '"]',
113
        TRACK_METADATA_TAB: 'li[data-track-kind="' + CSS.TRACK_METADATA + '"]',
114
        TRACK_METADATA_PANE: '.tab-pane[data-track-kind="' + CSS.TRACK_METADATA + '"]'
115
    },
116
    TEMPLATES = {
117
        ROOT: '' +
118
            '<form class="mform atto_form atto_media" id="{{elementid}}_atto_media_form">' +
119
                '<ul class="root nav nav-tabs mb-1" role="tablist">' +
120
                    '<li data-medium-type="{{CSS.LINK}}" class="nav-item">' +
121
                        '<a class="nav-link active" href="#{{elementid}}_{{CSS.LINK}}" role="tab" data-toggle="tab">' +
122
                            '{{get_string "link" component}}' +
123
                        '</a>' +
124
                    '</li>' +
125
                    '<li data-medium-type="{{CSS.VIDEO}}" class="nav-item">' +
126
                        '<a class="nav-link" href="#{{elementid}}_{{CSS.VIDEO}}" role="tab" data-toggle="tab">' +
127
                            '{{get_string "video" component}}' +
128
                        '</a>' +
129
                    '</li>' +
130
                    '<li data-medium-type="{{CSS.AUDIO}}" class="nav-item">' +
131
                        '<a class="nav-link" href="#{{elementid}}_{{CSS.AUDIO}}" role="tab" data-toggle="tab">' +
132
                            '{{get_string "audio" component}}' +
133
                        '</a>' +
134
                    '</li>' +
135
                '</ul>' +
136
                '<div class="root tab-content">' +
137
                    '<div data-medium-type="{{CSS.LINK}}" class="tab-pane active" id="{{elementid}}_{{CSS.LINK}}">' +
138
                        '{{> tab_panes.link}}' +
139
                    '</div>' +
140
                    '<div data-medium-type="{{CSS.VIDEO}}" class="tab-pane" id="{{elementid}}_{{CSS.VIDEO}}">' +
141
                        '{{> tab_panes.video}}' +
142
                    '</div>' +
143
                    '<div data-medium-type="{{CSS.AUDIO}}" class="tab-pane" id="{{elementid}}_{{CSS.AUDIO}}">' +
144
                        '{{> tab_panes.audio}}' +
145
                    '</div>' +
146
                '</div>' +
147
                '<div class="mdl-align">' +
148
                    '<br/>' +
149
                    '<button class="btn btn-secondary submit" type="submit">{{get_string "createmedia" component}}</button>' +
150
                '</div>' +
151
            '</form>',
152
        TAB_PANES: {
153
            LINK: '' +
154
                '{{renderPartial "form_components.source" context=this id=CSS.LINK_SOURCE}}' +
155
                '<label for="{{elementid}}_link_nameentry">{{get_string "entername" component}}</label>' +
156
                '<input class="form-control fullwidth {{CSS.NAME_INPUT}}" type="text" id="{{elementid}}_link_nameentry"' +
157
                        'size="32" required="true"/>',
158
            VIDEO: '' +
159
                '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="videosourcelabel"' +
160
                    ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' +
161
                '<fieldset class="collapsible collapsed" id="{{elementid}}_video-display-options">' +
162
                    '<input name="mform_isexpanded_{{elementid}}_video-display-options" type="hidden">' +
163
                    '{{renderPartial "form_components.section" context=this id="vdisplayoptions" name="displayoptions"}}' +
164
                    '<div id="vdisplayoptions" class="fcontainer collapseable collapse px-1">' +
165
                        '{{renderPartial "form_components.display_options" context=this id=CSS.VIDEO mediatype_video=true}}' +
166
                    '</div>' +
167
                '</fieldset>' +
168
                '<fieldset class="collapsible collapsed" id="{{elementid}}_video-advanced-settings">' +
169
                    '<input name="mform_isexpanded_{{elementid}}_video-advanced-settings" type="hidden">' +
170
                    '{{renderPartial "form_components.section" context=this id="vadvancedsettings" name="advancedsettings"}}' +
171
                    '<div id="vadvancedsettings" class="fcontainer collapseable collapse px-1">' +
172
                        '{{renderPartial "form_components.advanced_settings" context=this id=CSS.VIDEO}}' +
173
                    '</div>' +
174
                '</fieldset>' +
175
                '<fieldset class="collapsible collapsed" id="{{elementid}}_video-tracks">' +
176
                    '<input name="mform_isexpanded_{{elementid}}_video-tracks" type="hidden">' +
177
                    '{{renderPartial "form_components.section" context=this id="vtracks" name="tracks" help=helpStrings.tracks}}' +
178
                    '<div id="vtracks" class="fcontainer collapseable collapse px-1">' +
179
                        '{{renderPartial "form_components.track_tabs" context=this id=CSS.VIDEO}}' +
180
                    '</div>' +
181
                '</fieldset>',
182
            AUDIO: '' +
183
                '{{renderPartial "form_components.source" context=this id=CSS.MEDIA_SOURCE entersourcelabel="audiosourcelabel"' +
184
                    ' addcomponentlabel="addsource" multisource="true" addsourcehelp=helpStrings.addsource}}' +
185
                '<fieldset class="collapsible collapsed" id="{{elementid}}_audio-display-options">' +
186
                    '<input name="mform_isexpanded_{{elementid}}_audio-display-options" type="hidden">' +
187
                    '{{renderPartial "form_components.section" context=this id="adisplayoptions" name="displayoptions"}}' +
188
                    '<div id="adisplayoptions" class="fcontainer collapseable collapse px-1">' +
189
                        '{{renderPartial "form_components.display_options" context=this id=CSS.AUDIO}}' +
190
                    '</div>' +
191
                '</fieldset>' +
192
                '<fieldset class="collapsible collapsed" id="{{elementid}}_audio-advanced-settings">' +
193
                    '<input name="mform_isexpanded_{{elementid}}_audio-advanced-settings" type="hidden">' +
194
                    '{{renderPartial "form_components.section" context=this id="aadvancedsettings" name="advancedsettings"}}' +
195
                    '<div id="aadvancedsettings" class="fcontainer collapseable collapse px-1">' +
196
                        '{{renderPartial "form_components.advanced_settings" context=this id=CSS.AUDIO}}' +
197
                    '</div>' +
198
                '</fieldset>' +
199
                '<fieldset class="collapsible collapsed" id="{{elementid}}_audio-tracks">' +
200
                    '<input name="mform_isexpanded_{{elementid}}_audio-tracks" type="hidden">' +
201
                    '{{renderPartial "form_components.section" context=this id="atracks" name="tracks" help=helpStrings.tracks}}' +
202
                    '<div id="atracks" class="fcontainer collapseable collapse px-1">' +
203
                        '{{renderPartial "form_components.track_tabs" context=this id=CSS.AUDIO}}' +
204
                    '</div>' +
205
                '</fieldset>'
206
        },
207
        FORM_COMPONENTS: {
208
            SOURCE: '' +
209
                '<div class="{{CSS.SOURCE}} {{id}}">' +
210
                    '<div class="mb-1">' +
211
                        '<label for="url-input">' +
212
                        '{{#entersourcelabel}}{{get_string ../entersourcelabel ../component}}{{/entersourcelabel}}' +
213
                        '{{^entersourcelabel}}{{get_string "entersource" ../component}}{{/entersourcelabel}}' +
214
                        '</label>' +
215
                        '<div class="input-group input-append w-100">' +
216
                            '<input id="url-input" class="form-control {{CSS.URL_INPUT}}" type="url" size="32"/>' +
217
                            '<span class="input-group-append">' +
218
                                '<button class="btn btn-secondary openmediabrowser" type="button">' +
219
                                '{{get_string "browserepositories" component}}</button>' +
220
                            '</span>' +
221
                        '</div>' +
222
                    '</div>' +
223
                    '{{#multisource}}' +
224
                        '{{renderPartial "form_components.add_component" context=../this label=../addcomponentlabel ' +
225
                            ' help=../addsourcehelp}}' +
226
                    '{{/multisource}}' +
227
                '</div>',
228
            ADD_COMPONENT: '' +
229
                '<div>' +
230
                    '<a href="#" class="addcomponent">' +
231
                        '{{#label}}{{get_string ../label ../component}}{{/label}}' +
232
                        '{{^label}}{{get_string "add" ../component}}{{/label}}' +
233
                    '</a>' +
234
                    '{{#help}}{{{../help}}}{{/help}}' +
235
                '</div>',
236
            REMOVE_COMPONENT: '' +
237
                '<div>' +
238
                    '<a href="#" class="removecomponent">' +
239
                        '{{#label}}{{get_string ../label ../component}}{{/label}}' +
240
                        '{{^label}}{{get_string "remove" ../component}}{{/label}}' +
241
                    '</a>' +
242
                '</div>',
243
            DISPLAY_OPTIONS: '' +
244
                '<div class="{{CSS.DISPLAY_OPTIONS}}">' +
245
                    '<div class="mb-1">' +
246
                        '<label for="{{id}}_media-title-entry">{{get_string "entertitle" component}}</label>' +
247
                        '<input class="form-control fullwidth {{CSS.TITLE_INPUT}}" type="text" id="{{id}}_media-title-entry"' +
248
                            'size="32"/>' +
249
                    '</div>' +
250
                    '<div class="clearfix"></div>' +
251
                    '{{#mediatype_video}}' +
252
                    '<div class="mb-1">' +
253
                        '<label>{{get_string "size" component}}</label>' +
254
                        '<div class="d-flex flex-wrap align-items-center {{CSS.POSTER_SIZE}}">' +
255
                            '<label class="accesshide">{{get_string "videowidth" component}}</label>' +
256
                            '<input type="text" class="form-control mr-1 {{CSS.WIDTH_INPUT}} input-mini" size="4"/>' +
257
                            ' x ' +
258
                            '<label class="accesshide">{{get_string "videoheight" component}}</label>' +
259
                            '<input type="text" class="form-control ml-1 {{CSS.HEIGHT_INPUT}} input-mini" size="4"/>' +
260
                        '</div>' +
261
                    '</div>' +
262
                    '<div class="clearfix"></div>' +
263
                    '{{renderPartial "form_components.source" context=this id=CSS.POSTER_SOURCE entersourcelabel="poster"}}' +
264
                    '{{/mediatype_video}}' +
265
                '<div>',
266
            ADVANCED_SETTINGS: '' +
267
                '<div class="{{CSS.ADVANCED_SETTINGS}}">' +
268
                    '<div class="form-check">' +
269
                        '<input type="checkbox" checked="true" class="form-check-input {{CSS.MEDIA_CONTROLS_TOGGLE}}"' +
270
                        'id="{{id}}_media-controls-toggle"/>' +
271
                        '<label class="form-check-label" for="{{id}}_media-controls-toggle">' +
272
                        '{{get_string "controls" component}}' +
273
                        '</label>' +
274
                    '</div>' +
275
                    '<div class="form-check">' +
276
                        '<input type="checkbox" class="form-check-input {{CSS.MEDIA_AUTOPLAY_TOGGLE}}"' +
277
                        'id="{{id}}_media-autoplay-toggle"/>' +
278
                        '<label class="form-check-label" for="{{id}}_media-autoplay-toggle">' +
279
                        '{{get_string "autoplay" component}}' +
280
                        '</label>' +
281
                    '</div>' +
282
                    '<div class="form-check">' +
283
                        '<input type="checkbox" class="form-check-input {{CSS.MEDIA_MUTE_TOGGLE}}" ' +
284
                            'id="{{id}}_media-mute-toggle"/>' +
285
                        '<label class="form-check-label" for="{{id}}_media-mute-toggle">' +
286
                        '{{get_string "mute" component}}' +
287
                        '</label>' +
288
                    '</div>' +
289
                    '<div class="form-check">' +
290
                        '<input type="checkbox" class="form-check-input {{CSS.MEDIA_LOOP_TOGGLE}}" ' +
291
                            'id="{{id}}_media-loop-toggle"/>' +
292
                        '<label class="form-check-label" for="{{id}}_media-loop-toggle">' +
293
                        '{{get_string "loop" component}}' +
294
                        '</label>' +
295
                    '</div>' +
296
                '</div>',
297
            TRACK_TABS: '' +
298
                '<ul class="nav nav-tabs mb-3">' +
299
                    '<li data-track-kind="{{CSS.TRACK_SUBTITLES}}" class="nav-item">' +
300
                        '<a class="nav-link active" href="#{{elementid}}_{{id}}_{{CSS.TRACK_SUBTITLES}}"' +
301
                            ' role="tab" data-toggle="tab">' +
302
                            '{{get_string "subtitles" component}}' +
303
                        '</a>' +
304
                    '</li>' +
305
                    '<li data-track-kind="{{CSS.TRACK_CAPTIONS}}" class="nav-item">' +
306
                        '<a class="nav-link" href="#{{elementid}}_{{id}}_{{CSS.TRACK_CAPTIONS}}" role="tab" data-toggle="tab">' +
307
                            '{{get_string "captions" component}}' +
308
                        '</a>' +
309
                    '</li>' +
310
                    '<li data-track-kind="{{CSS.TRACK_DESCRIPTIONS}}"  class="nav-item">' +
311
                        '<a class="nav-link" href="#{{elementid}}_{{id}}_{{CSS.TRACK_DESCRIPTIONS}}"' +
312
                            ' role="tab" data-toggle="tab">' +
313
                            '{{get_string "descriptions" component}}' +
314
                        '</a>' +
315
                    '</li>' +
316
                    '<li data-track-kind="{{CSS.TRACK_CHAPTERS}}" class="nav-item">' +
317
                        '<a class="nav-link" href="#{{elementid}}_{{id}}_{{CSS.TRACK_CHAPTERS}}" role="tab" data-toggle="tab">' +
318
                            '{{get_string "chapters" component}}' +
319
                        '</a>' +
320
                    '</li>' +
321
                    '<li data-track-kind="{{CSS.TRACK_METADATA}}" class="nav-item">' +
322
                        '<a class="nav-link" href="#{{elementid}}_{{id}}_{{CSS.TRACK_METADATA}}" role="tab" data-toggle="tab">' +
323
                            '{{get_string "metadata" component}}' +
324
                        '</a>' +
325
                    '</li>' +
326
                '</ul>' +
327
                '<div class="tab-content">' +
328
                    '<div data-track-kind="{{CSS.TRACK_SUBTITLES}}" class="tab-pane active"' +
329
                        ' id="{{elementid}}_{{id}}_{{CSS.TRACK_SUBTITLES}}">' +
330
                        '<div class="trackhelp">{{{helpStrings.subtitles}}}</div>' +
331
                        '{{renderPartial "form_components.track" context=this sourcelabel="subtitlessourcelabel"' +
332
                            ' addcomponentlabel="addsubtitlestrack"}}' +
333
                    '</div>' +
334
                    '<div data-track-kind="{{CSS.TRACK_CAPTIONS}}" class="tab-pane"' +
335
                        ' id="{{elementid}}_{{id}}_{{CSS.TRACK_CAPTIONS}}">' +
336
                        '<div class="trackhelp">{{{helpStrings.captions}}}</div>' +
337
                        '{{renderPartial "form_components.track" context=this sourcelabel="captionssourcelabel"' +
338
                            ' addcomponentlabel="addcaptionstrack"}}' +
339
                    '</div>' +
340
                    '<div data-track-kind="{{CSS.TRACK_DESCRIPTIONS}}" class="tab-pane"' +
341
                        ' id="{{elementid}}_{{id}}_{{CSS.TRACK_DESCRIPTIONS}}">' +
342
                        '<div class="trackhelp">{{{helpStrings.descriptions}}}</div>' +
343
                        '{{renderPartial "form_components.track" context=this sourcelabel="descriptionssourcelabel"' +
344
                            ' addcomponentlabel="adddescriptionstrack"}}' +
345
                    '</div>' +
346
                    '<div data-track-kind="{{CSS.TRACK_CHAPTERS}}" class="tab-pane"' +
347
                        ' id="{{elementid}}_{{id}}_{{CSS.TRACK_CHAPTERS}}">' +
348
                        '<div class="trackhelp">{{{helpStrings.chapters}}}</div>' +
349
                        '{{renderPartial "form_components.track" context=this sourcelabel="chapterssourcelabel"' +
350
                            ' addcomponentlabel="addchapterstrack"}}' +
351
                    '</div>' +
352
                    '<div data-track-kind="{{CSS.TRACK_METADATA}}" class="tab-pane"' +
353
                        ' id="{{elementid}}_{{id}}_{{CSS.TRACK_METADATA}}">' +
354
                        '<div class="trackhelp">{{{helpStrings.metadata}}}</div>' +
355
                        '{{renderPartial "form_components.track" context=this sourcelabel="metadatasourcelabel"' +
356
                            ' addcomponentlabel="addmetadatatrack"}}' +
357
                    '</div>' +
358
                '</div>',
359
            TRACK: '' +
360
                '<div class="mb-1 {{CSS.TRACK}}">' +
361
                    '{{renderPartial "form_components.source" context=this id=CSS.TRACK_SOURCE entersourcelabel=sourcelabel}}' +
362
                    '<div class="mb-3">' +
363
                        '<label class="w-100" for="lang-input">{{get_string "srclang" component}}</label>' +
364
                        '<select id="lang-input" class="custom-select {{CSS.TRACK_LANG_INPUT}}">' +
365
                            '<optgroup label="{{get_string "languagesinstalled" component}}">' +
366
                                '{{#langsinstalled}}' +
367
                                    '<option value="{{code}}" {{#default}}selected="selected"{{/default}}>{{lang}}</option>' +
368
                                '{{/langsinstalled}}' +
369
                            '</optgroup>' +
370
                            '<optgroup label="{{get_string "languagesavailable" component}} ">' +
371
                                '{{#langsavailable}}<option value="{{code}}">{{lang}}</option>{{/langsavailable}}' +
372
                            '</optgroup>' +
373
                        '</select>' +
374
                    '</div>' +
375
                    '<div class="mb-3">' +
376
                        '<label class="w-100" for="track-input">{{get_string "label" component}}</label>' +
377
                        '<input id="track-input" class="form-control {{CSS.TRACK_LABEL_INPUT}}" type="text"/>' +
378
                    '</div>' +
379
                    '<div class="form-check">' +
380
                        '<input type="checkbox" class="form-check-input {{CSS.TRACK_DEFAULT_SELECT}}"/>' +
381
                        '<label class="form-check-label">{{get_string "default" component}}</label>' +
382
                    '</div>' +
383
                    '{{renderPartial "form_components.add_component" context=this label=addcomponentlabel}}' +
384
                '</div>',
385
            SECTION: '' +
386
                '<legend class="d-flex align-items-center px-1">' +
387
                    '<div class="position-relative d-flex ftoggler align-items-center position-relative mr-1">' +
388
                        '<a role="button" data-toggle="collapse" href="#{{id}}" aria-expanded="false"' +
389
                            'aria-controls="{{id}}"' +
390
                            'class="btn btn-icon mr-1 icons-collapse-expand stretched-link fheader collapsed">' +
391
                            '<span class="expanded-icon icon-no-margin p-2" title="{{get_string "collapse" "moodle"}}">' +
392
                                '<i class="icon fa fa-chevron-down fa-fw " aria-hidden="true"></i>' +
393
                            '</span>' +
394
                            '<span class="collapsed-icon icon-no-margin p-2" title="{{get_string "expand" "moodle"}}">' +
395
                                '<span class="dir-rtl-hide">' +
396
                                    '<i class="icon fa fa-chevron-right fa-fw " aria-hidden="true"></i>' +
397
                                '</span>' +
398
                                '<span class="dir-ltr-hide">' +
399
                                    '<i class="icon fa fa-chevron-left fa-fw " aria-hidden="true"></i>' +
400
                                '</span>' +
401
                            '</span>' +
402
                            '<span class="sr-only">{{get_string name component}}</span>' +
403
                        '</a>' +
404
                        '<h3 class="d-flex align-self-stretch align-items-center mb-0" aria-hidden="true">' +
405
                            '{{get_string name component}}' +
406
                        '</h3>' +
407
                        '</div>' +
408
                    '{{#help}}{{{../help}}}{{/help}}' +
409
                '</legend>'
410
        },
411
        HTML_MEDIA: {
412
            VIDEO: '' +
413
                '&nbsp;<video ' +
414
                    '{{#width}}width="{{../width}}" {{/width}}' +
415
                    '{{#height}}height="{{../height}}" {{/height}}' +
416
                    '{{#poster}}poster="{{../poster}}" {{/poster}}' +
417
                    '{{#showControls}}controls="true" {{/showControls}}' +
418
                    '{{#loop}}loop="true" {{/loop}}' +
419
                    '{{#muted}}muted="true" {{/muted}}' +
420
                    '{{#autoplay}}autoplay="true" {{/autoplay}}' +
421
                    '{{#title}}title="{{../title}}" {{/title}}' +
422
                '>' +
423
                    '{{#sources}}<source src="{{source}}">{{/sources}}' +
424
                    '{{#tracks}}' +
425
                        '<track src="{{track}}" kind="{{kind}}" srclang="{{srclang}}" label="{{label}}"' +
426
                            ' {{#defaultTrack}}default="true"{{/defaultTrack}}>' +
427
                    '{{/tracks}}' +
428
                    '{{#description}}{{../description}}{{/description}}' +
429
                '</video>&nbsp',
430
            AUDIO: '' +
431
                '&nbsp;<audio ' +
432
                    '{{#showControls}}controls="true" {{/showControls}}' +
433
                    '{{#loop}}loop="true" {{/loop}}' +
434
                    '{{#muted}}muted="true" {{/muted}}' +
435
                    '{{#autoplay}}autoplay="true" {{/autoplay}}' +
436
                    '{{#title}}title="{{../title}}" {{/title}}' +
437
                '>' +
438
                    '{{#sources}}<source src="{{source}}">{{/sources}}' +
439
                    '{{#tracks}}' +
440
                        '<track src="{{track}}" kind="{{kind}}" srclang="{{srclang}}" label="{{label}}"' +
441
                            ' {{#defaultTrack}}default="true"{{/defaultTrack}}>' +
442
                    '{{/tracks}}' +
443
                    '{{#description}}{{../description}}{{/description}}' +
444
                '</audio>&nbsp',
445
            LINK: '' +
446
                '<a href="{{url}}" ' +
447
                    '{{#width}}data-width="{{../width}}" {{/width}}' +
448
                    '{{#height}}data-height="{{../height}}"{{/height}}' +
449
                '>{{#name}}{{../name}}{{/name}}{{^name}}{{../url}}{{/name}}</a>'
450
         }
451
    };
452
 
453
Y.namespace('M.atto_media').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
454
 
455
    initializer: function() {
456
        if (this.get('host').canShowFilepicker('media')) {
457
            this.editor.delegate('dblclick', this._displayDialogue, 'video', this);
458
            this.editor.delegate('click', this._handleClick, 'video', this);
459
 
460
            // For some reason, clicking the video on Firefox does not trigger the click event, while in Chrome it does.
461
            // We also need to handle the play/pause instead.
462
            this._attachPlayPauseEvents();
463
            var changeHandler = this._attachPlayPauseEvents.bind(this);
464
            this.get('host').on('change', changeHandler, null);
465
 
466
            this.addButton({
467
                icon: 'e/insert_edit_video',
468
                callback: this._displayDialogue,
469
                tags: 'video, audio',
470
                tagMatchRequiresAll: false
471
            });
472
        }
473
    },
474
 
475
    /**
476
     * Attaches Play/Pause events to the video nodes.
477
     *
478
     * @private
479
     */
480
    _attachPlayPauseEvents: function() {
481
        if (this._handlePlayEndBound === undefined) {
482
            this._handlePlayEndBound = this._handlePlayEnd.bind(this);
483
        }
484
        var videos = this.editor.getDOMNode().querySelectorAll('video');
485
        videos.forEach(function(video) {
486
            // Prevent duplicated event listeners.
487
            video.removeEventListener('play', this._handlePlayEndBound);
488
            video.removeEventListener('pause', this._handlePlayEndBound);
489
            // Add event listeners.
490
            video.addEventListener('play', this._handlePlayEndBound);
491
            video.addEventListener('pause', this._handlePlayEndBound);
492
        }.bind(this));
493
    },
494
 
495
    /**
496
     * Gets the root context for all templates, with extra supplied context.
497
     *
498
     * @method _getContext
499
     * @param  {Object} extra The extra context to add
500
     * @return {Object}
501
     * @private
502
     */
503
    _getContext: function(extra) {
504
        return Y.merge({
505
            elementid: this.get('host').get('elementid'),
506
            component: COMPONENTNAME,
507
            langsinstalled: this.get('langs').installed,
508
            langsavailable: this.get('langs').available,
509
            helpStrings: this.get('help'),
510
            CSS: CSS
511
        }, extra);
512
    },
513
 
514
    /**
515
     * Handles a click on a media element.
516
     *
517
     * @method _handleClick
518
     * @param  {EventFacade} e
519
     * @private
520
     */
521
    _handleClick: function(e) {
522
        var medium = e.target;
523
 
524
        var selection = this.get('host').getSelectionFromNode(medium);
525
        if (this.get('host').getSelection() !== selection) {
526
            this.get('host').setSelection(selection);
527
        }
528
    },
529
 
530
    /**
531
     * Handles a play/end on a media element.
532
     *
533
     * @method _handlePlayEnd
534
     * @param {Event} e
535
     * @private
536
     */
537
    _handlePlayEnd: function(e) {
538
        var medium = Y.one(e.target);
539
 
540
        var selection = this.get('host').getSelectionFromNode(medium);
541
        if (this.get('host').getSelection() !== selection) {
542
            this.get('host').setSelection(selection);
543
            this.get('host')._hasSelectionChanged(e);
544
        }
545
    },
546
 
547
    /**
548
     * Display the media editing tool.
549
     *
550
     * @method _displayDialogue
551
     * @private
552
     */
553
    _displayDialogue: function() {
554
        if (this.get('host').getSelection() === false) {
555
            return;
556
        }
557
 
558
        if (!('renderPartial' in Y.Handlebars.helpers)) {
559
            (function smashPartials(chain, obj) {
560
                Y.each(obj, function(value, index) {
561
                    chain.push(index);
562
                    if (typeof value !== "object") {
563
                        Y.Handlebars.registerPartial(chain.join('.').toLowerCase(), value);
564
                    } else {
565
                        smashPartials(chain, value);
566
                    }
567
                    chain.pop();
568
                });
569
            })([], TEMPLATES);
570
 
571
            Y.Handlebars.registerHelper('renderPartial', function(partialName, options) {
572
                if (!partialName) {
573
                    return '';
574
                }
575
 
576
                var partial = Y.Handlebars.partials[partialName];
577
                var parentContext = options.hash.context ? Y.clone(options.hash.context) : {};
578
                var context = Y.merge(parentContext, options.hash);
579
                delete context.context;
580
 
581
                if (!partial) {
582
                    return '';
583
                }
584
                return new Y.Handlebars.SafeString(Y.Handlebars.compile(partial)(context));
585
            });
586
        }
587
 
588
        var dialogue = this.getDialogue({
589
            headerContent: M.util.get_string('createmedia', COMPONENTNAME),
590
            focusAfterHide: true,
591
            width: 660,
592
            focusOnShowSelector: SELECTORS.URL_INPUT
593
        });
594
 
595
        // Set the dialogue content, and then show the dialogue.
596
        dialogue.set('bodyContent', this._getDialogueContent(this.get('host').getSelection())).show();
597
        M.form.shortforms({formid: this.get('host').get('elementid') + '_atto_media_form'});
598
    },
599
 
600
    /**
601
     * Returns the dialogue content for the tool.
602
     *
603
     * @method _getDialogueContent
604
     * @param  {WrappedRange[]} selection Current editor selection
605
     * @return {Y.Node}
606
     * @private
607
     */
608
    _getDialogueContent: function(selection) {
609
        var content = Y.Node.create(
610
            Y.Handlebars.compile(TEMPLATES.ROOT)(this._getContext())
611
        );
612
 
613
        var medium = this.get('host').getSelectedNodes().filter('video,audio').shift();
614
        var mediumProperties = medium ? this._getMediumProperties(medium) : false;
615
        return this._attachEvents(this._applyMediumProperties(content, mediumProperties), selection);
616
    },
617
 
618
    /**
619
     * Attaches required events to the content node.
620
     *
621
     * @method _attachEvents
622
     * @param  {Y.Node}         content The content to which events will be attached
623
     * @param  {WrappedRange[]} selection Current editor selection
624
     * @return {Y.Node}
625
     * @private
626
     */
627
    _attachEvents: function(content, selection) {
628
        // Delegate add component link for media source fields.
629
        content.delegate('click', function(e) {
630
            e.preventDefault();
631
            this._addMediaSourceComponent(e.currentTarget);
632
        }, SELECTORS.MEDIA_SOURCE + ' .addcomponent', this);
633
 
634
        // Delegate add component link for track fields.
635
        content.delegate('click', function(e) {
636
            e.preventDefault();
637
            this._addTrackComponent(e.currentTarget);
638
        }, SELECTORS.TRACK + ' .addcomponent', this);
639
 
640
        // Only allow one track per tab to be selected as "default".
641
        content.delegate('click', function(e) {
642
            var element = e.currentTarget;
643
            if (element.get('checked')) {
644
                var getKind = function(el) {
645
                    return this._getTrackTypeFromTabPane(el.ancestor('.tab-pane'));
646
                }.bind(this);
647
 
648
                element.ancestor('.root.tab-content').all(SELECTORS.TRACK_DEFAULT_SELECT).each(function(select) {
649
                    if (select !== element && getKind(element) === getKind(select)) {
650
                        select.set('checked', false);
651
                    }
652
                });
653
            }
654
        }, SELECTORS.TRACK_DEFAULT_SELECT, this);
655
 
656
        // Set up filepicker click event.
657
        content.delegate('click', function(e) {
658
            var element = e.currentTarget;
659
            var fptype = (element.ancestor(SELECTORS.POSTER_SOURCE) && 'image') ||
660
                    (element.ancestor(SELECTORS.TRACK_SOURCE) && 'subtitle') ||
661
                    'media';
662
            e.preventDefault();
663
            this.get('host').showFilepicker(fptype, this._getFilepickerCallback(element, fptype), this);
664
        }, '.openmediabrowser', this);
665
 
666
        // This is a nasty hack. Basically we are using BS4 markup for the tabs
667
        // but it isn't completely backwards compatible with BS2. The main problem is
668
        // that the "active" class goes on a different node. So the idea is to put it
669
        // the node for BS4, and then use CSS to make it look right in BS2. However,
670
        // once another tab is clicked, everything sorts itself out, more or less. Except
671
        // that the original "active" tab hasn't had the BS4 "active" class removed
672
        // (so the styles will still apply to it). So we need to remove the "active"
673
        // class on the BS4 node so that BS2 is happy.
674
        //
675
        // This doesn't upset BS4 since it removes this class anyway when clicking on
676
        // another tab.
677
        content.all('.nav-item').on('click', function(elem) {
678
            elem.currentTarget.get('parentNode').all('.active').removeClass('active');
679
        });
680
 
681
        content.one('.submit').on('click', function(e) {
682
            e.preventDefault();
683
            var mediaHTML = this._getMediaHTML(e.currentTarget.ancestor('.atto_form')),
684
                host = this.get('host');
685
            this.getDialogue({
686
                focusAfterHide: null
687
            }).hide();
688
            if (mediaHTML) {
689
                host.setSelection(selection);
690
                host.insertContentAtFocusPoint(mediaHTML);
691
                this.markUpdated();
692
            }
693
        }, this);
694
 
695
        return content;
696
    },
697
 
698
    /**
699
     * Applies medium properties to the content node.
700
     *
701
     * @method _applyMediumProperties
702
     * @param  {Y.Node} content The content to apply the properties to
703
     * @param  {object} properties The medium properties to apply
704
     * @return {Y.Node}
705
     * @private
706
     */
707
    _applyMediumProperties: function(content, properties) {
708
        if (!properties) {
709
            return content;
710
        }
711
 
712
        var applyTrackProperties = function(track, properties) {
713
            track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.src);
714
            track.one(SELECTORS.TRACK_LANG_INPUT).set('value', properties.srclang);
715
            track.one(SELECTORS.TRACK_LABEL_INPUT).set('value', properties.label);
716
            track.one(SELECTORS.TRACK_DEFAULT_SELECT).set('checked', properties.defaultTrack);
717
        };
718
 
719
        var tabPane = content.one('.root.tab-content > .tab-pane#' + this.get('host').get('elementid') +
720
                              '_' + properties.type.toLowerCase());
721
 
722
        // Populate sources.
723
        tabPane.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).set('value', properties.sources[0]);
724
        Y.Array.each(properties.sources.slice(1), function(source) {
725
            this._addMediaSourceComponent(tabPane.one(SELECTORS.MEDIA_SOURCE + ' .addcomponent'), function(newComponent) {
726
                newComponent.one(SELECTORS.URL_INPUT).set('value', source);
727
            });
728
        }, this);
729
 
730
        // Populate tracks.
731
        Y.Object.each(properties.tracks, function(value, key) {
732
            var trackData = value.length ? value : [{src: '', srclang: '', label: '', defaultTrack: false}];
733
            var paneSelector = SELECTORS['TRACK_' + key.toUpperCase() + '_PANE'];
734
 
735
            applyTrackProperties(tabPane.one(paneSelector + ' ' + SELECTORS.TRACK), trackData[0]);
736
            Y.Array.each(trackData.slice(1), function(track) {
737
                this._addTrackComponent(
738
                    tabPane.one(paneSelector + ' ' + SELECTORS.TRACK + ' .addcomponent'), function(newComponent) {
739
                    applyTrackProperties(newComponent, track);
740
                });
741
            }, this);
742
        }, this);
743
 
744
        // Populate values.
745
        tabPane.one(SELECTORS.TITLE_INPUT).set('value', properties.title);
746
        tabPane.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).set('checked', properties.controls);
747
        tabPane.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).set('checked', properties.autoplay);
748
        tabPane.one(SELECTORS.MEDIA_MUTE_TOGGLE).set('checked', properties.muted);
749
        tabPane.one(SELECTORS.MEDIA_LOOP_TOGGLE).set('checked', properties.loop);
750
 
751
        // Determine medium type.
752
        var mediumType = this._getMediumTypeFromTabPane(tabPane);
753
 
754
        if (mediumType === 'video') {
755
            // Populate values unique for video.
756
            tabPane.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).setAttribute('value', properties.poster);
757
            tabPane.one(SELECTORS.WIDTH_INPUT).set('value', properties.width);
758
            tabPane.one(SELECTORS.HEIGHT_INPUT).set('value', properties.height);
759
        }
760
 
761
        // Switch to the correct tab.
762
        // Remove active class from all tabs + tab panes.
763
        tabPane.siblings('.active').removeClass('active');
764
        content.all('.root.nav-tabs .nav-item a').removeClass('active');
765
 
766
        // Add active class to the desired tab and tab pane.
767
        tabPane.addClass('active');
768
        content.one(SELECTORS[mediumType.toUpperCase() + '_TAB'] + ' a').addClass('active');
769
 
770
        return content;
771
    },
772
 
773
    /**
774
     * Extracts medium properties.
775
     *
776
     * @method _getMediumProperties
777
     * @param  {Y.Node} medium The medium node from which to extract
778
     * @return {Object}
779
     * @private
780
     */
781
    _getMediumProperties: function(medium) {
782
        var boolAttr = function(elem, attr) {
783
            // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes.
784
            // So in order to check if attr="true", we need to check if the attribute exists and if the value is empty or true.
785
            return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === ''));
786
        };
787
 
788
        var tracks = {
789
            subtitles: [],
790
            captions: [],
791
            descriptions: [],
792
            chapters: [],
793
            metadata: []
794
        };
795
 
796
        medium.all('track').each(function(track) {
797
            tracks[track.getAttribute('kind')].push({
798
                src: track.getAttribute('src'),
799
                srclang: track.getAttribute('srclang'),
800
                label: track.getAttribute('label'),
801
                defaultTrack: boolAttr(track, 'default')
802
            });
803
        });
804
 
805
        return {
806
            type: medium.test('video') ? MEDIA_TYPES.VIDEO : MEDIA_TYPES.AUDIO,
807
            sources: medium.all('source').get('src'),
808
            poster: medium.getAttribute('poster'),
809
            title: medium.getAttribute('title'),
810
            width: medium.getAttribute('width'),
811
            height: medium.getAttribute('height'),
812
            autoplay: boolAttr(medium, 'autoplay'),
813
            loop: boolAttr(medium, 'loop'),
814
            muted: boolAttr(medium, 'muted'),
815
            controls: boolAttr(medium, 'controls'),
816
            tracks: tracks
817
        };
818
    },
819
 
820
    /**
821
     * Adds a track form component.
822
     *
823
     * @method _addTrackComponent
824
     * @param  {Y.Node}   element    The element which was used to trigger this function
825
     * @param  {Function} [callback] Function to be called when the new component is added
826
     *     @param {Y.Node}    callback.newComponent The compiled component
827
     * @private
828
     */
829
    _addTrackComponent: function(element, callback) {
830
        var trackType = this._getTrackTypeFromTabPane(element.ancestor('.tab-pane'));
831
        var context = this._getContext({
832
            sourcelabel: trackType + 'sourcelabel',
833
            addcomponentlabel: 'add' + trackType + 'track'
834
        });
835
 
836
        this._addComponent(element, TEMPLATES.FORM_COMPONENTS.TRACK, SELECTORS.TRACK, context, callback);
837
    },
838
 
839
    /**
840
     * Adds a media source form component.
841
     *
842
     * @method _addMediaSourceComponent
843
     * @param  {Y.Node}   element    The element which was used to trigger this function
844
     * @param  {Function} [callback] Function to be called when the new component is added
845
     *     @param {Y.Node}    callback.newComponent The compiled component
846
     * @private
847
     */
848
    _addMediaSourceComponent: function(element, callback) {
849
        var mediumType = this._getMediumTypeFromTabPane(element.ancestor('.tab-pane'));
850
        var context = this._getContext({
851
            multisource: true,
852
            id: CSS.MEDIA_SOURCE,
853
            entersourcelabel: mediumType + 'sourcelabel',
854
            addcomponentlabel: 'addsource',
855
            addsourcehelp: this.get('help').addsource
856
        });
857
        this._addComponent(element, TEMPLATES.FORM_COMPONENTS.SOURCE, SELECTORS.MEDIA_SOURCE, context, callback);
858
    },
859
 
860
    /**
861
     * Adds an arbitrary form component.
862
     *
863
     * This function Compiles and adds the provided component in the supplied 'ancestor' container.
864
     * It will also add links to add/remove the relevant components, attaching the
865
     * necessary events.
866
     *
867
     * @method _addComponent
868
     * @param  {Y.Node}   element    The element which was used to trigger this function
869
     * @param  {String}   component  The component to compile and add
870
     * @param  {String}   ancestor   A selector used to find an ancestor of 'component', to which
871
     *                               the compiled component will be appended
872
     * @param  {Object}   context    The context with which to render the component
873
     * @param  {Function} [callback] Function to be called when the new component is added
874
     *     @param {Y.Node}    callback.newComponent The compiled component
875
     * @private
876
     */
877
    _addComponent: function(element, component, ancestor, context, callback) {
878
        var currentComponent = element.ancestor(ancestor),
879
            newComponent = Y.Node.create(Y.Handlebars.compile(component)(context)),
880
            removeNodeContext = this._getContext(context);
881
 
882
        removeNodeContext.label = "remove";
883
        var removeNode = Y.Node.create(Y.Handlebars.compile(TEMPLATES.FORM_COMPONENTS.REMOVE_COMPONENT)(removeNodeContext));
884
 
885
        removeNode.one('.removecomponent').on('click', function(e) {
886
            e.preventDefault();
887
            currentComponent.remove(true);
888
        });
889
 
890
        currentComponent.insert(newComponent, 'after');
891
        element.ancestor().insert(removeNode, 'after');
892
        element.ancestor().remove(true);
893
 
894
        if (callback) {
895
            callback.call(this, newComponent);
896
        }
897
    },
898
 
899
    /**
900
     * Returns the callback for the file picker to call after a file has been selected.
901
     *
902
     * @method _getFilepickerCallback
903
     * @param  {Y.Node} element The element which triggered the callback
904
     * @param  {String} fptype  The file pickertype (as would be passed to `showFilePicker`)
905
     * @return {Function} The function to be used as a callback when the file picker returns the file
906
     * @private
907
     */
908
    _getFilepickerCallback: function(element, fptype) {
909
        return function(params) {
910
            if (params.url !== '') {
911
                var tabPane = element.ancestor('.tab-pane');
912
                element.ancestor(SELECTORS.SOURCE).one(SELECTORS.URL_INPUT).set('value', params.url);
913
 
914
                // Links (and only links) have a name field.
915
                if (tabPane.get('id') === this.get('host').get('elementid') + '_' + CSS.LINK) {
916
                    tabPane.one(SELECTORS.NAME_INPUT).set('value', params.file);
917
                }
918
 
919
                if (fptype === 'subtitle') {
920
                    var subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0];
921
                    var langObj = this.get('langs').available.reduce(function(carry, lang) {
922
                        return lang.code === subtitleLang ? lang : carry;
923
                    }, false);
924
                    if (langObj) {
925
                        element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LABEL_INPUT).set('value',
926
                                langObj.lang.substr(0, langObj.lang.lastIndexOf(' ')));
927
                        element.ancestor(SELECTORS.TRACK).one(SELECTORS.TRACK_LANG_INPUT).set('value', langObj.code);
928
                    }
929
                }
930
            }
931
        };
932
    },
933
 
934
    /**
935
     * Given a "medium" tab pane, returns what kind of medium it contains.
936
     *
937
     * @method _getMediumTypeFromTabPane
938
     * @param  {Y.Node} tabPane The tab pane
939
     * @return {String} The type of medium in the pane
940
     */
941
    _getMediumTypeFromTabPane: function(tabPane) {
942
        return tabPane.getAttribute('data-medium-type');
943
    },
944
 
945
    /**
946
     * Given a "track" tab pane, returns what kind of track it contains.
947
     *
948
     * @method _getTrackTypeFromTabPane
949
     * @param  {Y.Node} tabPane The tab pane
950
     * @return {String} The type of track in the pane
951
     */
952
    _getTrackTypeFromTabPane: function(tabPane) {
953
        return tabPane.getAttribute('data-track-kind');
954
    },
955
 
956
    /**
957
     * Returns the HTML to be inserted to the text area.
958
     *
959
     * @method _getMediaHTML
960
     * @param  {Y.Node} form The form from which to extract data
961
     * @return {String} The compiled markup
962
     * @private
963
     */
964
    _getMediaHTML: function(form) {
965
        var mediumType = this._getMediumTypeFromTabPane(form.one('.root.tab-content > .tab-pane.active'));
966
        var tabContent = form.one(SELECTORS[mediumType.toUpperCase() + '_PANE']);
967
 
968
        return this['_getMediaHTML' + mediumType[0].toUpperCase() + mediumType.substr(1)](tabContent);
969
    },
970
 
971
    /**
972
     * Returns the HTML to be inserted to the text area for the link tab.
973
     *
974
     * @method _getMediaHTMLLink
975
     * @param  {Y.Node} tab The tab from which to extract data
976
     * @return {String} The compiled markup
977
     * @private
978
     */
979
    _getMediaHTMLLink: function(tab) {
980
        var context = {
981
            url: tab.one(SELECTORS.URL_INPUT).get('value'),
982
            name: tab.one(SELECTORS.NAME_INPUT).get('value') || false
983
        };
984
 
985
        return context.url ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.LINK)(context) : '';
986
    },
987
 
988
    /**
989
     * Returns the HTML to be inserted to the text area for the video tab.
990
     *
991
     * @method _getMediaHTMLVideo
992
     * @param  {Y.Node} tab The tab from which to extract data
993
     * @return {String} The compiled markup
994
     * @private
995
     */
996
    _getMediaHTMLVideo: function(tab) {
997
        var context = this._getContextForMediaHTML(tab);
998
        context.width = tab.one(SELECTORS.WIDTH_INPUT).get('value') || false;
999
        context.height = tab.one(SELECTORS.HEIGHT_INPUT).get('value') || false;
1000
        context.poster = tab.one(SELECTORS.POSTER_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false;
1001
 
1002
        return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.VIDEO)(context) : '';
1003
    },
1004
 
1005
    /**
1006
     * Returns the HTML to be inserted to the text area for the audio tab.
1007
     *
1008
     * @method _getMediaHTMLAudio
1009
     * @param  {Y.Node} tab The tab from which to extract data
1010
     * @return {String} The compiled markup
1011
     * @private
1012
     */
1013
    _getMediaHTMLAudio: function(tab) {
1014
        var context = this._getContextForMediaHTML(tab);
1015
 
1016
        return context.sources.length ? Y.Handlebars.compile(TEMPLATES.HTML_MEDIA.AUDIO)(context) : '';
1017
    },
1018
 
1019
    /**
1020
     * Returns the context with which to render a media template.
1021
     *
1022
     * @method _getContextForMediaHTML
1023
     * @param  {Y.Node} tab The tab from which to extract data
1024
     * @return {Object}
1025
     * @private
1026
     */
1027
    _getContextForMediaHTML: function(tab) {
1028
        var tracks = [];
1029
 
1030
        tab.all(SELECTORS.TRACK).each(function(track) {
1031
            tracks.push({
1032
                track: track.one(SELECTORS.TRACK_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value'),
1033
                kind: this._getTrackTypeFromTabPane(track.ancestor('.tab-pane')),
1034
                label: track.one(SELECTORS.TRACK_LABEL_INPUT).get('value') ||
1035
                    track.one(SELECTORS.TRACK_LANG_INPUT).get('value'),
1036
                srclang: track.one(SELECTORS.TRACK_LANG_INPUT).get('value'),
1037
                defaultTrack: track.one(SELECTORS.TRACK_DEFAULT_SELECT).get('checked') ? "true" : null
1038
            });
1039
        }, this);
1040
 
1041
        return {
1042
            sources: tab.all(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value').filter(function(source) {
1043
                return !!source;
1044
            }).map(function(source) {
1045
                return {source: source};
1046
            }),
1047
            description: tab.one(SELECTORS.MEDIA_SOURCE + ' ' + SELECTORS.URL_INPUT).get('value') || false,
1048
            tracks: tracks.filter(function(track) {
1049
                return !!track.track;
1050
            }),
1051
            showControls: tab.one(SELECTORS.MEDIA_CONTROLS_TOGGLE).get('checked'),
1052
            autoplay: tab.one(SELECTORS.MEDIA_AUTOPLAY_TOGGLE).get('checked'),
1053
            muted: tab.one(SELECTORS.MEDIA_MUTE_TOGGLE).get('checked'),
1054
            loop: tab.one(SELECTORS.MEDIA_LOOP_TOGGLE).get('checked'),
1055
            title: tab.one(SELECTORS.TITLE_INPUT).get('value') || false
1056
        };
1057
    }
1058
}, {
1059
    ATTRS: {
1060
        langs: {},
1061
        help: {}
1062
    }
1063
});