Merge "Add phpdoc for some ApiQueryInfo properties"
[lhc/web/wiklou.git] / resources / src / mediawiki / mediawiki.ForeignStructuredUpload.BookletLayout.js
1 /*global moment */
2 ( function ( $, mw ) {
3
4 /**
5 * mw.ForeignStructuredUpload.BookletLayout encapsulates the process
6 * of uploading a file to MediaWiki using the mw.ForeignStructuredUpload model.
7 *
8 * var uploadDialog = new mw.Upload.Dialog( {
9 * bookletClass: mw.ForeignStructuredUpload.BookletLayout,
10 * booklet: {
11 * target: 'local'
12 * }
13 * } );
14 * var windowManager = new OO.ui.WindowManager();
15 * $( 'body' ).append( windowManager.$element );
16 * windowManager.addWindows( [ uploadDialog ] );
17 *
18 * @class mw.ForeignStructuredUpload.BookletLayout
19 * @uses mw.ForeignStructuredUpload
20 * @extends mw.Upload.BookletLayout
21 * @cfg {string} [target] Used to choose the target repository.
22 * If nothing is passed, the {@link mw.ForeignUpload#property-target default} is used.
23 */
24 mw.ForeignStructuredUpload.BookletLayout = function ( config ) {
25 config = config || {};
26 // Parent constructor
27 mw.ForeignStructuredUpload.BookletLayout.parent.call( this, config );
28
29 this.target = config.target;
30 };
31
32 /* Setup */
33
34 OO.inheritClass( mw.ForeignStructuredUpload.BookletLayout, mw.Upload.BookletLayout );
35
36 /* Uploading */
37
38 /**
39 * @inheritdoc
40 */
41 mw.ForeignStructuredUpload.BookletLayout.prototype.initialize = function () {
42 var booklet = this;
43 return mw.ForeignStructuredUpload.BookletLayout.parent.prototype.initialize.call( this ).then(
44 function () {
45 // Point the CategorySelector to the right wiki
46 return booklet.upload.getApi().then(
47 function ( api ) {
48 // If this is a ForeignApi, it will have a apiUrl, otherwise we don't need to do anything
49 if ( api.apiUrl ) {
50 // Can't reuse the same object, CategorySelector calls #abort on its mw.Api instance
51 booklet.categoriesWidget.api = new mw.ForeignApi( api.apiUrl );
52 }
53 return $.Deferred().resolve();
54 },
55 function () {
56 return $.Deferred().resolve();
57 }
58 );
59 },
60 function () {
61 return $.Deferred().resolve();
62 }
63 );
64 };
65
66 /**
67 * Returns a {@link mw.ForeignStructuredUpload mw.ForeignStructuredUpload}
68 * with the {@link #cfg-target target} specified in config.
69 *
70 * @protected
71 * @return {mw.Upload}
72 */
73 mw.ForeignStructuredUpload.BookletLayout.prototype.createUpload = function () {
74 return new mw.ForeignStructuredUpload( this.target );
75 };
76
77 /* Form renderers */
78
79 /**
80 * @inheritdoc
81 */
82 mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm = function () {
83 var
84 query = /[?&]uploadbucket=(\d)/.exec( location.search ),
85 isTestEnabled = !!mw.config.get( 'wgForeignUploadTestEnabled' ),
86 defaultBucket = mw.config.get( 'wgForeignUploadTestDefault' ) || 1,
87 userId = mw.config.get( 'wgUserId' );
88
89 if ( query && query[ 1 ] ) {
90 // Testing and debugging
91 this.shouldRecordBucket = false;
92 this.bucket = Number( query[ 1 ] );
93 } else if ( !userId || !isTestEnabled ) {
94 // a) Anonymous user. This can actually happen, because our software sucks.
95 // b) Test is not enabled on this wiki.
96 // In either case, display the old interface and don't record bucket on uploads.
97 this.shouldRecordBucket = false;
98 this.bucket = defaultBucket;
99 } else {
100 // Regular logged in user on a wiki where the test is running
101 this.shouldRecordBucket = true;
102 this.bucket = ( userId % 4 ) + 1; // 1, 2, 3, 4
103 }
104
105 return this[ 'renderUploadForm' + this.bucket ]();
106 };
107
108 /**
109 * Test option 1, the original one. See T120867.
110 */
111 mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm1 = function () {
112 var fieldset, $ownWorkMessage, $notOwnWorkMessage,
113 onUploadFormChange,
114 ownWorkMessage, notOwnWorkMessage, notOwnWorkLocal,
115 validTargets = mw.config.get( 'wgForeignUploadTargets' ),
116 target = this.target || validTargets[ 0 ] || 'local',
117 layout = this;
118
119 // Temporary override to make my life easier during A/B test
120 target = 'shared';
121
122 // foreign-structured-upload-form-label-own-work-message-local
123 // foreign-structured-upload-form-label-own-work-message-shared
124 ownWorkMessage = mw.message( 'foreign-structured-upload-form-label-own-work-message-' + target );
125 // foreign-structured-upload-form-label-not-own-work-message-local
126 // foreign-structured-upload-form-label-not-own-work-message-shared
127 notOwnWorkMessage = mw.message( 'foreign-structured-upload-form-label-not-own-work-message-' + target );
128 // foreign-structured-upload-form-label-not-own-work-local-local
129 // foreign-structured-upload-form-label-not-own-work-local-shared
130 notOwnWorkLocal = mw.message( 'foreign-structured-upload-form-label-not-own-work-local-' + target );
131
132 if ( !ownWorkMessage.exists() ) {
133 ownWorkMessage = mw.message( 'foreign-structured-upload-form-label-own-work-message-default' );
134 }
135 if ( !notOwnWorkMessage.exists() ) {
136 notOwnWorkMessage = mw.message( 'foreign-structured-upload-form-label-not-own-work-message-default' );
137 }
138 if ( !notOwnWorkLocal.exists() ) {
139 notOwnWorkLocal = mw.message( 'foreign-structured-upload-form-label-not-own-work-local-default' );
140 }
141
142 $ownWorkMessage = $( '<p>' ).append( ownWorkMessage.parseDom() )
143 .addClass( 'mw-foreignStructuredUpload-bookletLayout-license' );
144 $notOwnWorkMessage = $( '<div>' ).append(
145 $( '<p>' ).append( notOwnWorkMessage.parseDom() ),
146 $( '<p>' ).append( notOwnWorkLocal.parseDom() )
147 );
148 $ownWorkMessage.add( $notOwnWorkMessage ).find( 'a' )
149 .attr( 'target', '_blank' )
150 .on( 'click', function ( e ) {
151 // Some stupid code is trying to prevent default on all clicks, which causes the links to
152 // not be openable, don't let it
153 e.stopPropagation();
154 } );
155
156 this.selectFileWidget = new OO.ui.SelectFileWidget();
157 this.messageLabel = new OO.ui.LabelWidget( {
158 label: $notOwnWorkMessage
159 } );
160 this.ownWorkCheckbox = new OO.ui.CheckboxInputWidget().on( 'change', function ( on ) {
161 layout.messageLabel.toggle( !on );
162 } );
163
164 fieldset = new OO.ui.FieldsetLayout();
165 fieldset.addItems( [
166 new OO.ui.FieldLayout( this.selectFileWidget, {
167 align: 'top',
168 label: mw.msg( 'upload-form-label-select-file' )
169 } ),
170 new OO.ui.FieldLayout( this.ownWorkCheckbox, {
171 align: 'inline',
172 label: $( '<div>' ).append(
173 $( '<p>' ).text( mw.msg( 'foreign-structured-upload-form-label-own-work' ) ),
174 $ownWorkMessage
175 )
176 } ),
177 new OO.ui.FieldLayout( this.messageLabel, {
178 align: 'top'
179 } )
180 ] );
181 this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
182
183 onUploadFormChange = function () {
184 var file = this.selectFileWidget.getValue(),
185 ownWork = this.ownWorkCheckbox.isSelected(),
186 valid = !!file && ownWork;
187 this.emit( 'uploadValid', valid );
188 };
189
190 // Validation
191 this.selectFileWidget.on( 'change', onUploadFormChange.bind( this ) );
192 this.ownWorkCheckbox.on( 'change', onUploadFormChange.bind( this ) );
193
194 this.selectFileWidget.on( 'change', function () {
195 var file = layout.getFile();
196
197 // Set the date to lastModified once we have the file
198 if ( layout.getDateFromLastModified( file ) !== undefined ) {
199 layout.dateWidget.setValue( layout.getDateFromLastModified( file ) );
200 }
201
202 // Check if we have EXIF data and set to that where available
203 layout.getDateFromExif( file ).done( function ( date ) {
204 layout.dateWidget.setValue( date );
205 } );
206 } );
207
208 return this.uploadForm;
209 };
210
211 /**
212 * Test option 2, idea A from T121021. See T120867.
213 */
214 mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm2 = function () {
215 var fieldset, checkboxes, fields, onUploadFormChange;
216
217 this.selectFileWidget = new OO.ui.SelectFileWidget();
218 this.licenseCheckboxes = checkboxes = [
219 new OO.ui.CheckboxInputWidget(),
220 new OO.ui.CheckboxInputWidget(),
221 new OO.ui.CheckboxInputWidget(),
222 new OO.ui.CheckboxInputWidget()
223 ];
224
225 fields = [
226 new OO.ui.FieldLayout( this.selectFileWidget, {
227 align: 'top',
228 label: mw.msg( 'upload-form-label-select-file' )
229 } ),
230 new OO.ui.FieldLayout( new OO.ui.LabelWidget( {
231 label: mw.message( 'foreign-structured-upload-form-2-label-intro' ).parseDom()
232 } ), {
233 align: 'top'
234 } ),
235 new OO.ui.FieldLayout( checkboxes[ 0 ], {
236 align: 'inline',
237 classes: [
238 'mw-foreignStructuredUpload-bookletLayout-withicon',
239 'mw-foreignStructuredUpload-bookletLayout-ownwork'
240 ],
241 label: mw.message( 'foreign-structured-upload-form-2-label-ownwork' ).parseDom()
242 } ),
243 new OO.ui.FieldLayout( checkboxes[ 1 ], {
244 align: 'inline',
245 classes: [
246 'mw-foreignStructuredUpload-bookletLayout-withicon',
247 'mw-foreignStructuredUpload-bookletLayout-noderiv'
248 ],
249 label: mw.message( 'foreign-structured-upload-form-2-label-noderiv' ).parseDom()
250 } ),
251 new OO.ui.FieldLayout( checkboxes[ 2 ], {
252 align: 'inline',
253 classes: [
254 'mw-foreignStructuredUpload-bookletLayout-withicon',
255 'mw-foreignStructuredUpload-bookletLayout-useful'
256 ],
257 label: mw.message( 'foreign-structured-upload-form-2-label-useful' ).parseDom()
258 } ),
259 new OO.ui.FieldLayout( checkboxes[ 3 ], {
260 align: 'inline',
261 classes: [
262 'mw-foreignStructuredUpload-bookletLayout-withicon',
263 'mw-foreignStructuredUpload-bookletLayout-ccbysa'
264 ],
265 label: mw.message( 'foreign-structured-upload-form-2-label-ccbysa' ).parseDom()
266 } ),
267 new OO.ui.FieldLayout( new OO.ui.LabelWidget( {
268 label: $()
269 .add( $( '<p>' ).msg( 'foreign-structured-upload-form-2-label-alternative' ) )
270 .add( $( '<p>' ).msg( 'foreign-structured-upload-form-2-label-termsofuse' )
271 .addClass( 'mw-foreignStructuredUpload-bookletLayout-license' ) )
272 } ), {
273 align: 'top'
274 } )
275 ];
276
277 fieldset = new OO.ui.FieldsetLayout( { items: fields } );
278 this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
279
280 this.uploadForm.$element.find( 'a' )
281 .attr( 'target', '_blank' )
282 .on( 'click', function ( e ) {
283 // Some stupid code is trying to prevent default on all clicks, which causes the links to
284 // not be openable, don't let it
285 e.stopPropagation();
286 } );
287
288 onUploadFormChange = function () {
289 var file = this.selectFileWidget.getValue(),
290 checks = checkboxes.every( function ( checkbox ) {
291 return checkbox.isSelected();
292 } ),
293 valid = !!file && checks;
294 this.emit( 'uploadValid', valid );
295 };
296
297 // Validation
298 this.selectFileWidget.on( 'change', onUploadFormChange.bind( this ) );
299 checkboxes[ 0 ].on( 'change', onUploadFormChange.bind( this ) );
300 checkboxes[ 1 ].on( 'change', onUploadFormChange.bind( this ) );
301 checkboxes[ 2 ].on( 'change', onUploadFormChange.bind( this ) );
302 checkboxes[ 3 ].on( 'change', onUploadFormChange.bind( this ) );
303
304 return this.uploadForm;
305 };
306
307 /**
308 * Test option 3, idea D from T121021. See T120867.
309 */
310 mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm3 = function () {
311 var ownWorkCheckbox, fieldset, yesMsg, noMsg, selects, selectFields,
312 alternativeField, fields, onUploadFormChange;
313
314 this.selectFileWidget = new OO.ui.SelectFileWidget();
315 this.ownWorkCheckbox = ownWorkCheckbox = new OO.ui.CheckboxInputWidget();
316
317 yesMsg = mw.message( 'foreign-structured-upload-form-3-label-yes' ).text();
318 noMsg = mw.message( 'foreign-structured-upload-form-3-label-no' ).text();
319 selects = [
320 new OO.ui.RadioSelectWidget( {
321 items: [
322 new OO.ui.RadioOptionWidget( { data: false, label: yesMsg } ),
323 new OO.ui.RadioOptionWidget( { data: true, label: noMsg } )
324 ]
325 } ),
326 new OO.ui.RadioSelectWidget( {
327 items: [
328 new OO.ui.RadioOptionWidget( { data: true, label: yesMsg } ),
329 new OO.ui.RadioOptionWidget( { data: false, label: noMsg } )
330 ]
331 } ),
332 new OO.ui.RadioSelectWidget( {
333 items: [
334 new OO.ui.RadioOptionWidget( { data: false, label: yesMsg } ),
335 new OO.ui.RadioOptionWidget( { data: true, label: noMsg } )
336 ]
337 } )
338 ];
339
340 this.licenseSelectFields = selectFields = [
341 new OO.ui.FieldLayout( selects[ 0 ], {
342 align: 'top',
343 classes: [ 'mw-foreignStructuredUpload-bookletLayout-question' ],
344 label: mw.message( 'foreign-structured-upload-form-3-label-question-website' ).parseDom()
345 } ),
346 new OO.ui.FieldLayout( selects[ 1 ], {
347 align: 'top',
348 classes: [ 'mw-foreignStructuredUpload-bookletLayout-question' ],
349 label: mw.message( 'foreign-structured-upload-form-3-label-question-ownwork' ).parseDom()
350 } ).toggle( false ),
351 new OO.ui.FieldLayout( selects[ 2 ], {
352 align: 'top',
353 classes: [ 'mw-foreignStructuredUpload-bookletLayout-question' ],
354 label: mw.message( 'foreign-structured-upload-form-3-label-question-noderiv' ).parseDom()
355 } ).toggle( false )
356 ];
357
358 alternativeField = new OO.ui.FieldLayout( new OO.ui.LabelWidget( {
359 label: mw.message( 'foreign-structured-upload-form-3-label-alternative' ).parseDom()
360 } ), {
361 align: 'top'
362 } ).toggle( false );
363
364 // Choosing the right answer to each question shows the next question.
365 // Switching to wrong answer hides all subsequent questions.
366 selects.forEach( function ( select, i ) {
367 select.on( 'choose', function ( selectedOption ) {
368 var isRightAnswer = !!selectedOption.getData();
369 alternativeField.toggle( !isRightAnswer );
370 if ( i + 1 === selectFields.length ) {
371 // Last question
372 return;
373 }
374 if ( isRightAnswer ) {
375 selectFields[ i + 1 ].toggle( true );
376 } else {
377 selectFields.slice( i + 1 ).forEach( function ( field ) {
378 field.fieldWidget.selectItem( null );
379 field.toggle( false );
380 } );
381 }
382 } );
383 } );
384
385 fields = [
386 new OO.ui.FieldLayout( this.selectFileWidget, {
387 align: 'top',
388 label: mw.msg( 'upload-form-label-select-file' )
389 } ),
390 selectFields[ 0 ],
391 selectFields[ 1 ],
392 selectFields[ 2 ],
393 alternativeField,
394 new OO.ui.FieldLayout( ownWorkCheckbox, {
395 classes: [ 'mw-foreignStructuredUpload-bookletLayout-checkbox' ],
396 align: 'inline',
397 label: mw.message( 'foreign-structured-upload-form-label-own-work-message-shared' ).parseDom()
398 } )
399 ];
400
401 // Must be done late, after it's been associated with the FieldLayout
402 ownWorkCheckbox.setDisabled( true );
403
404 fieldset = new OO.ui.FieldsetLayout( { items: fields } );
405 this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
406
407 this.uploadForm.$element.find( 'a' )
408 .attr( 'target', '_blank' )
409 .on( 'click', function ( e ) {
410 // Some stupid code is trying to prevent default on all clicks, which causes the links to
411 // not be openable, don't let it
412 e.stopPropagation();
413 } );
414
415 onUploadFormChange = function () {
416 var file = this.selectFileWidget.getValue(),
417 checkbox = ownWorkCheckbox.isSelected(),
418 rightAnswers = selects.every( function ( select ) {
419 return select.getSelectedItem() && !!select.getSelectedItem().getData();
420 } ),
421 valid = !!file && checkbox && rightAnswers;
422 ownWorkCheckbox.setDisabled( !rightAnswers );
423 if ( !rightAnswers ) {
424 ownWorkCheckbox.setSelected( false );
425 }
426 this.emit( 'uploadValid', valid );
427 };
428
429 // Validation
430 this.selectFileWidget.on( 'change', onUploadFormChange.bind( this ) );
431 this.ownWorkCheckbox.on( 'change', onUploadFormChange.bind( this ) );
432 selects[ 0 ].on( 'choose', onUploadFormChange.bind( this ) );
433 selects[ 1 ].on( 'choose', onUploadFormChange.bind( this ) );
434 selects[ 2 ].on( 'choose', onUploadFormChange.bind( this ) );
435
436 return this.uploadForm;
437 };
438
439 /**
440 * Test option 4, idea E from T121021. See T120867.
441 */
442 mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm4 = function () {
443 var fieldset, $guide;
444 this.renderUploadForm1();
445 fieldset = this.uploadForm.getItems()[ 0 ];
446
447 $guide = mw.template.get( 'mediawiki.ForeignStructuredUpload.BookletLayout', 'guide.html' ).render();
448 $guide.find( '.mw-foreignStructuredUpload-bookletLayout-guide-text-wrapper-good span' )
449 .msg( 'foreign-structured-upload-form-4-label-good' );
450 $guide.find( '.mw-foreignStructuredUpload-bookletLayout-guide-text-wrapper-bad span' )
451 .msg( 'foreign-structured-upload-form-4-label-bad' );
452
453 // Note the index, we insert after the SelectFileWidget field
454 fieldset.addItems( [
455 new OO.ui.FieldLayout( new OO.ui.Widget( {
456 $content: $guide
457 } ), {
458 align: 'top'
459 } )
460 ], 1 );
461
462 // Hook for custom styles
463 fieldset.getItems()[ 2 ].$element.addClass( 'mw-foreignStructuredUpload-bookletLayout-guide-checkbox' );
464
465 // Streamline: remove mention of local Special:Upload
466 fieldset.getItems()[ 3 ].$element.find( 'p' ).last().remove();
467
468 return this.uploadForm;
469 };
470
471 /**
472 * @inheritdoc
473 */
474 mw.ForeignStructuredUpload.BookletLayout.prototype.onUploadFormChange = function () {};
475
476 /**
477 * @inheritdoc
478 */
479 mw.ForeignStructuredUpload.BookletLayout.prototype.renderInfoForm = function () {
480 var fieldset;
481
482 this.filenameWidget = new OO.ui.TextInputWidget( {
483 required: true,
484 validate: /.+/
485 } );
486 this.descriptionWidget = new OO.ui.TextInputWidget( {
487 required: true,
488 validate: /\S+/,
489 multiline: true,
490 autosize: true
491 } );
492 this.categoriesWidget = new mw.widgets.CategorySelector( {
493 // Can't be done here because we don't know the target wiki yet... done in #initialize.
494 // api: new mw.ForeignApi( ... ),
495 $overlay: this.$overlay
496 } );
497 this.dateWidget = new mw.widgets.DateInputWidget( {
498 $overlay: this.$overlay,
499 required: true,
500 mustBeBefore: moment().add( 1, 'day' ).locale( 'en' ).format( 'YYYY-MM-DD' ) // Tomorrow
501 } );
502
503 fieldset = new OO.ui.FieldsetLayout( {
504 label: mw.msg( 'upload-form-label-infoform-title' )
505 } );
506 fieldset.addItems( [
507 new OO.ui.FieldLayout( this.filenameWidget, {
508 label: mw.msg( 'upload-form-label-infoform-name' ),
509 align: 'top',
510 help: mw.msg( 'upload-form-label-infoform-name-tooltip' )
511 } ),
512 new OO.ui.FieldLayout( this.descriptionWidget, {
513 label: mw.msg( 'upload-form-label-infoform-description' ),
514 align: 'top',
515 help: mw.msg( 'upload-form-label-infoform-description-tooltip' )
516 } ),
517 new OO.ui.FieldLayout( this.categoriesWidget, {
518 label: mw.msg( 'foreign-structured-upload-form-label-infoform-categories' ),
519 align: 'top'
520 } ),
521 new OO.ui.FieldLayout( this.dateWidget, {
522 label: mw.msg( 'foreign-structured-upload-form-label-infoform-date' ),
523 align: 'top'
524 } )
525 ] );
526 this.infoForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
527
528 // Validation
529 this.filenameWidget.on( 'change', this.onInfoFormChange.bind( this ) );
530 this.descriptionWidget.on( 'change', this.onInfoFormChange.bind( this ) );
531 this.dateWidget.on( 'change', this.onInfoFormChange.bind( this ) );
532
533 return this.infoForm;
534 };
535
536 /**
537 * @inheritdoc
538 */
539 mw.ForeignStructuredUpload.BookletLayout.prototype.onInfoFormChange = function () {
540 var layout = this;
541 $.when(
542 this.filenameWidget.getValidity(),
543 this.descriptionWidget.getValidity(),
544 this.dateWidget.getValidity()
545 ).done( function () {
546 layout.emit( 'infoValid', true );
547 } ).fail( function () {
548 layout.emit( 'infoValid', false );
549 } );
550 };
551
552 /* Getters */
553
554 /**
555 * @inheritdoc
556 */
557 mw.ForeignStructuredUpload.BookletLayout.prototype.getText = function () {
558 var language = mw.config.get( 'wgContentLanguage' );
559 this.upload.clearDescriptions();
560 this.upload.addDescription( language, this.descriptionWidget.getValue() );
561 this.upload.setDate( this.dateWidget.getValue() );
562 this.upload.clearCategories();
563 this.upload.addCategories( this.categoriesWidget.getItemsData() );
564 return this.upload.getText();
565 };
566
567 /**
568 * Get original date from EXIF data
569 *
570 * @param {Object} file
571 * @return {jQuery.Promise} Promise resolved with the EXIF date
572 */
573 mw.ForeignStructuredUpload.BookletLayout.prototype.getDateFromExif = function ( file ) {
574 var fileReader,
575 deferred = $.Deferred();
576
577 if ( file && file.type === 'image/jpeg' ) {
578 fileReader = new FileReader();
579 fileReader.onload = function () {
580 var fileStr, arr, i, metadata;
581
582 if ( typeof fileReader.result === 'string' ) {
583 fileStr = fileReader.result;
584 } else {
585 // Array buffer; convert to binary string for the library.
586 arr = new Uint8Array( fileReader.result );
587 fileStr = '';
588 for ( i = 0; i < arr.byteLength; i++ ) {
589 fileStr += String.fromCharCode( arr[ i ] );
590 }
591 }
592
593 try {
594 metadata = mw.libs.jpegmeta( this.result, file.name );
595 } catch ( e ) {
596 metadata = null;
597 }
598
599 if ( metadata !== null && metadata.exif !== undefined && metadata.exif.DateTimeOriginal ) {
600 deferred.resolve( moment( metadata.exif.DateTimeOriginal, 'YYYY:MM:DD' ).format( 'YYYY-MM-DD' ) );
601 } else {
602 deferred.reject();
603 }
604 };
605
606 if ( 'readAsBinaryString' in fileReader ) {
607 fileReader.readAsBinaryString( file );
608 } else if ( 'readAsArrayBuffer' in fileReader ) {
609 fileReader.readAsArrayBuffer( file );
610 } else {
611 // We should never get here
612 deferred.reject();
613 throw new Error( 'Cannot read thumbnail as binary string or array buffer.' );
614 }
615 }
616
617 return deferred.promise();
618 };
619
620 /**
621 * Get last modified date from file
622 *
623 * @param {Object} file
624 * @return {Object} Last modified date from file
625 */
626 mw.ForeignStructuredUpload.BookletLayout.prototype.getDateFromLastModified = function ( file ) {
627 if ( file && file.lastModified ) {
628 return moment( file.lastModified ).format( 'YYYY-MM-DD' );
629 }
630 };
631
632 /* Setters */
633
634 /**
635 * @inheritdoc
636 */
637 mw.ForeignStructuredUpload.BookletLayout.prototype.clear = function () {
638 mw.ForeignStructuredUpload.BookletLayout.parent.prototype.clear.call( this );
639
640 if ( this.ownWorkCheckbox ) {
641 this.ownWorkCheckbox.setSelected( false );
642 }
643 if ( this.licenseCheckboxes ) {
644 this.licenseCheckboxes.forEach( function ( checkbox ) {
645 checkbox.setSelected( false );
646 } );
647 }
648 if ( this.licenseSelectFields ) {
649 this.licenseSelectFields.forEach( function ( field, i ) {
650 field.fieldWidget.selectItem( null );
651 if ( i !== 0 ) {
652 field.toggle( false );
653 }
654 } );
655 }
656
657 this.categoriesWidget.setItemsFromData( [] );
658 this.dateWidget.setValue( '' ).setValidityFlag( true );
659 };
660
661 }( jQuery, mediaWiki ) );