32 * Initialize component. |
25 * Initialize component. |
33 * |
26 * |
34 * @since 4.9.0 |
27 * @since 4.9.0 |
35 * |
28 * |
36 * @param {jQuery} form - Form element. |
29 * @param {jQuery} form - Form element. |
37 * @param {object} settings - Settings. |
30 * @param {Object} settings - Settings. |
38 * @param {object|boolean} settings.codeEditor - Code editor settings (or `false` if syntax highlighting is disabled). |
31 * @param {Object|boolean} settings.codeEditor - Code editor settings (or `false` if syntax highlighting is disabled). |
39 * @returns {void} |
32 * @return {void} |
40 */ |
33 */ |
41 component.init = function init( form, settings ) { |
34 component.init = function init( form, settings ) { |
42 |
35 |
43 component.form = form; |
36 component.form = form; |
44 if ( settings ) { |
37 if ( settings ) { |
73 |
66 |
74 $( component.initFileBrowser ); |
67 $( component.initFileBrowser ); |
75 |
68 |
76 $( window ).on( 'beforeunload', function() { |
69 $( window ).on( 'beforeunload', function() { |
77 if ( component.dirty ) { |
70 if ( component.dirty ) { |
78 return component.l10n.saveAlert; |
71 return __( 'The changes you made will be lost if you navigate away from this page.' ); |
79 } |
72 } |
80 return undefined; |
73 return undefined; |
81 } ); |
74 } ); |
82 |
75 |
83 component.docsLookUpList.on( 'change', function() { |
76 component.docsLookUpList.on( 'change', function() { |
92 |
85 |
93 /** |
86 /** |
94 * Set up and display the warning modal. |
87 * Set up and display the warning modal. |
95 * |
88 * |
96 * @since 4.9.0 |
89 * @since 4.9.0 |
97 * @returns {void} |
90 * @return {void} |
98 */ |
91 */ |
99 component.showWarning = function() { |
92 component.showWarning = function() { |
100 // Get the text within the modal. |
93 // Get the text within the modal. |
101 var rawMessage = component.warning.find( '.file-editor-warning-message' ).text(); |
94 var rawMessage = component.warning.find( '.file-editor-warning-message' ).text(); |
102 // Hide all the #wpwrap content from assistive technologies. |
95 // Hide all the #wpwrap content from assistive technologies. |
122 |
115 |
123 /** |
116 /** |
124 * Constrain tabbing within the warning modal. |
117 * Constrain tabbing within the warning modal. |
125 * |
118 * |
126 * @since 4.9.0 |
119 * @since 4.9.0 |
127 * @param {object} event jQuery event object. |
120 * @param {Object} event jQuery event object. |
128 * @returns {void} |
121 * @return {void} |
129 */ |
122 */ |
130 component.constrainTabbing = function( event ) { |
123 component.constrainTabbing = function( event ) { |
131 var firstTabbable, lastTabbable; |
124 var firstTabbable, lastTabbable; |
132 |
125 |
133 if ( 9 !== event.which ) { |
126 if ( 9 !== event.which ) { |
178 /** |
171 /** |
179 * Submit file via Ajax. |
172 * Submit file via Ajax. |
180 * |
173 * |
181 * @since 4.9.0 |
174 * @since 4.9.0 |
182 * @param {jQuery.Event} event - Event. |
175 * @param {jQuery.Event} event - Event. |
183 * @returns {void} |
176 * @return {void} |
184 */ |
177 */ |
185 component.submit = function( event ) { |
178 component.submit = function( event ) { |
186 var data = {}, request; |
179 var data = {}, request; |
187 event.preventDefault(); // Prevent form submission in favor of Ajax below. |
180 event.preventDefault(); // Prevent form submission in favor of Ajax below. |
188 $.each( component.form.serializeArray(), function() { |
181 $.each( component.form.serializeArray(), function() { |
259 /** |
252 /** |
260 * Add notice. |
253 * Add notice. |
261 * |
254 * |
262 * @since 4.9.0 |
255 * @since 4.9.0 |
263 * |
256 * |
264 * @param {object} notice - Notice. |
257 * @param {Object} notice - Notice. |
265 * @param {string} notice.code - Code. |
258 * @param {string} notice.code - Code. |
266 * @param {string} notice.type - Type. |
259 * @param {string} notice.type - Type. |
267 * @param {string} notice.message - Message. |
260 * @param {string} notice.message - Message. |
268 * @param {boolean} [notice.dismissible=false] - Dismissible. |
261 * @param {boolean} [notice.dismissible=false] - Dismissible. |
269 * @param {Function} [notice.onDismiss] - Callback for when a user dismisses the notice. |
262 * @param {Function} [notice.onDismiss] - Callback for when a user dismisses the notice. |
270 * @returns {jQuery} Notice element. |
263 * @return {jQuery} Notice element. |
271 */ |
264 */ |
272 component.addNotice = function( notice ) { |
265 component.addNotice = function( notice ) { |
273 var noticeElement; |
266 var noticeElement; |
274 |
267 |
275 if ( ! notice.code ) { |
268 if ( ! notice.code ) { |
301 * Remove notice. |
294 * Remove notice. |
302 * |
295 * |
303 * @since 4.9.0 |
296 * @since 4.9.0 |
304 * |
297 * |
305 * @param {string} code - Notice code. |
298 * @param {string} code - Notice code. |
306 * @returns {boolean} Whether a notice was removed. |
299 * @return {boolean} Whether a notice was removed. |
307 */ |
300 */ |
308 component.removeNotice = function( code ) { |
301 component.removeNotice = function( code ) { |
309 if ( component.noticeElements[ code ] ) { |
302 if ( component.noticeElements[ code ] ) { |
310 component.noticeElements[ code ].slideUp( 'fast', function() { |
303 component.noticeElements[ code ].slideUp( 'fast', function() { |
311 $( this ).remove(); |
304 $( this ).remove(); |
318 |
311 |
319 /** |
312 /** |
320 * Initialize code editor. |
313 * Initialize code editor. |
321 * |
314 * |
322 * @since 4.9.0 |
315 * @since 4.9.0 |
323 * @returns {void} |
316 * @return {void} |
324 */ |
317 */ |
325 component.initCodeEditor = function initCodeEditor() { |
318 component.initCodeEditor = function initCodeEditor() { |
326 var codeEditorSettings, editor; |
319 var codeEditorSettings, editor; |
327 |
320 |
328 codeEditorSettings = $.extend( {}, component.codeEditor ); |
321 codeEditorSettings = $.extend( {}, component.codeEditor ); |
330 /** |
323 /** |
331 * Handle tabbing to the field before the editor. |
324 * Handle tabbing to the field before the editor. |
332 * |
325 * |
333 * @since 4.9.0 |
326 * @since 4.9.0 |
334 * |
327 * |
335 * @returns {void} |
328 * @return {void} |
336 */ |
329 */ |
337 codeEditorSettings.onTabPrevious = function() { |
330 codeEditorSettings.onTabPrevious = function() { |
338 $( '#templateside' ).find( ':tabbable' ).last().focus(); |
331 $( '#templateside' ).find( ':tabbable' ).last().focus(); |
339 }; |
332 }; |
340 |
333 |
341 /** |
334 /** |
342 * Handle tabbing to the field after the editor. |
335 * Handle tabbing to the field after the editor. |
343 * |
336 * |
344 * @since 4.9.0 |
337 * @since 4.9.0 |
345 * |
338 * |
346 * @returns {void} |
339 * @return {void} |
347 */ |
340 */ |
348 codeEditorSettings.onTabNext = function() { |
341 codeEditorSettings.onTabNext = function() { |
349 $( '#template' ).find( ':tabbable:not(.CodeMirror-code)' ).first().focus(); |
342 $( '#template' ).find( ':tabbable:not(.CodeMirror-code)' ).first().focus(); |
350 }; |
343 }; |
351 |
344 |
353 * Handle change to the linting errors. |
346 * Handle change to the linting errors. |
354 * |
347 * |
355 * @since 4.9.0 |
348 * @since 4.9.0 |
356 * |
349 * |
357 * @param {Array} errors - List of linting errors. |
350 * @param {Array} errors - List of linting errors. |
358 * @returns {void} |
351 * @return {void} |
359 */ |
352 */ |
360 codeEditorSettings.onChangeLintingErrors = function( errors ) { |
353 codeEditorSettings.onChangeLintingErrors = function( errors ) { |
361 component.lintErrors = errors; |
354 component.lintErrors = errors; |
362 |
355 |
363 // Only disable the button in onUpdateErrorNotice when there are errors so users can still feel they can click the button. |
356 // Only disable the button in onUpdateErrorNotice when there are errors so users can still feel they can click the button. |
370 * Update error notice. |
363 * Update error notice. |
371 * |
364 * |
372 * @since 4.9.0 |
365 * @since 4.9.0 |
373 * |
366 * |
374 * @param {Array} errorAnnotations - Error annotations. |
367 * @param {Array} errorAnnotations - Error annotations. |
375 * @returns {void} |
368 * @return {void} |
376 */ |
369 */ |
377 codeEditorSettings.onUpdateErrorNotice = function onUpdateErrorNotice( errorAnnotations ) { |
370 codeEditorSettings.onUpdateErrorNotice = function onUpdateErrorNotice( errorAnnotations ) { |
378 var message, noticeElement; |
371 var noticeElement; |
379 |
372 |
380 component.submitButton.toggleClass( 'disabled', errorAnnotations.length > 0 ); |
373 component.submitButton.toggleClass( 'disabled', errorAnnotations.length > 0 ); |
381 |
374 |
382 if ( 0 !== errorAnnotations.length ) { |
375 if ( 0 !== errorAnnotations.length ) { |
383 if ( 1 === errorAnnotations.length ) { |
|
384 message = component.l10n.lintError.singular.replace( '%d', '1' ); |
|
385 } else { |
|
386 message = component.l10n.lintError.plural.replace( '%d', String( errorAnnotations.length ) ); |
|
387 } |
|
388 noticeElement = component.addNotice({ |
376 noticeElement = component.addNotice({ |
389 code: 'lint_errors', |
377 code: 'lint_errors', |
390 type: 'error', |
378 type: 'error', |
391 message: message, |
379 message: sprintf( |
|
380 /* translators: %s: Error count. */ |
|
381 _n( |
|
382 'There is %s error which must be fixed before you can update this file.', |
|
383 'There are %s errors which must be fixed before you can update this file.', |
|
384 errorAnnotations.length |
|
385 ), |
|
386 String( errorAnnotations.length ) |
|
387 ), |
392 dismissible: false |
388 dismissible: false |
393 }); |
389 }); |
394 noticeElement.find( 'input[type=checkbox]' ).on( 'click', function() { |
390 noticeElement.find( 'input[type=checkbox]' ).on( 'click', function() { |
395 codeEditorSettings.onChangeLintingErrors( [] ); |
391 codeEditorSettings.onChangeLintingErrors( [] ); |
396 component.removeNotice( 'lint_errors' ); |
392 component.removeNotice( 'lint_errors' ); |
489 * An element with the role=tree attribute |
485 * An element with the role=tree attribute |
490 */ |
486 */ |
491 |
487 |
492 var TreeitemLink = function (node, treeObj, group) { |
488 var TreeitemLink = function (node, treeObj, group) { |
493 |
489 |
494 // Check whether node is a DOM element |
490 // Check whether node is a DOM element. |
495 if (typeof node !== 'object') { |
491 if (typeof node !== 'object') { |
496 return; |
492 return; |
497 } |
493 } |
498 |
494 |
499 node.tabIndex = -1; |
495 node.tabIndex = -1; |
810 |
806 |
811 elem = elem.nextElementSibling; |
807 elem = elem.nextElementSibling; |
812 } |
808 } |
813 } |
809 } |
814 |
810 |
815 // initialize pop up menus |
811 // Initialize pop up menus. |
816 if (!this.domNode.getAttribute('role')) { |
812 if (!this.domNode.getAttribute('role')) { |
817 this.domNode.setAttribute('role', 'tree'); |
813 this.domNode.setAttribute('role', 'tree'); |
818 } |
814 } |
819 |
815 |
820 findTreeitems(this.domNode, this, false); |
816 findTreeitems(this.domNode, this, false); |
962 |
958 |
963 TreeLinks.prototype.setFocusByFirstCharacter = function (currentItem, _char) { |
959 TreeLinks.prototype.setFocusByFirstCharacter = function (currentItem, _char) { |
964 var start, index; |
960 var start, index; |
965 _char = _char.toLowerCase(); |
961 _char = _char.toLowerCase(); |
966 |
962 |
967 // Get start index for search based on position of currentItem |
963 // Get start index for search based on position of currentItem. |
968 start = this.treeitems.indexOf(currentItem) + 1; |
964 start = this.treeitems.indexOf(currentItem) + 1; |
969 if (start === this.treeitems.length) { |
965 if (start === this.treeitems.length) { |
970 start = 0; |
966 start = 0; |
971 } |
967 } |
972 |
968 |
973 // Check remaining slots in the menu |
969 // Check remaining slots in the menu. |
974 index = this.getIndexFirstChars(start, _char); |
970 index = this.getIndexFirstChars(start, _char); |
975 |
971 |
976 // If not found in remaining slots, check from beginning |
972 // If not found in remaining slots, check from beginning. |
977 if (index === -1) { |
973 if (index === -1) { |
978 index = this.getIndexFirstChars(0, _char); |
974 index = this.getIndexFirstChars(0, _char); |
979 } |
975 } |
980 |
976 |
981 // If match was found... |
977 // If match was found... |