PluginProbe
Virtue/Ascend/Pinnacle Toolkit / 3.4
Virtue/Ascend/Pinnacle Toolkit v3.4
4.9.12.2 trunk 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.7 All 48 releases
virtue-toolkit / cmb / js / cmb.js

cmb.js in Virtue/Ascend/Pinnacle Toolkit 3.4, at cmb/js/cmb.js

798 lines 23.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Controls the behaviours of custom metabox fields.
3 *
4 * @author Andrew Norcross
5 * @author Jared Atchison
6 * @author Bill Erickson
7 * @author Justin Sternberg
8 * @see https://github.com/webdevstudios/Custom-Metaboxes-and-Fields-for-WordPress
9 */
10
11 /**
12 * Custom jQuery for Custom Metaboxes and Fields
13 */
14 window.CMB = (function(window, document, $, undefined){
15 'use strict';
16
17 // localization strings
18 var l10n = window.cmb_l10;
19 var setTimeout = window.setTimeout;
20
21 // CMB functionality object
22 var cmb = {
23 formfield : '',
24 idNumber : false,
25 file_frames : {},
26 repeatEls : 'input:not([type="button"]),select,textarea,.cmb_media_status'
27 };
28
29 cmb.metabox = function() {
30 if ( cmb.$metabox ) {
31 return cmb.$metabox;
32 }
33 cmb.$metabox = $('table.cmb_metabox');
34 return cmb.$metabox;
35 };
36
37 cmb.init = function() {
38
39 var $metabox = cmb.metabox();
40 var $repeatGroup = $metabox.find('.repeatable-group');
41
42 // hide our spinner gif if we're on a MP6 dashboard
43 if ( l10n.new_admin_style ) {
44 $metabox.find('.cmb-spinner img').hide();
45 }
46
47 /**
48 * Initialize time/date/color pickers
49 */
50 cmb.initPickers( $metabox.find('input:text.cmb_timepicker'), $metabox.find('input:text.cmb_datepicker'), $metabox.find('input:text.cmb_colorpicker') );
51
52 // Wrap date picker in class to narrow the scope of jQuery UI CSS and prevent conflicts
53 $("#ui-datepicker-div").wrap('<div class="cmb_element" />');
54
55 // Insert toggle button into DOM wherever there is multicheck. credit: Genesis Framework
56 $( '<p><span class="button cmb-multicheck-toggle">' + l10n.check_toggle + '</span></p>' ).insertBefore( 'ul.cmb_checkbox_list' );
57
58 $metabox
59 .on( 'change', '.cmb_upload_file', function() {
60 cmb.formfield = $(this).attr('id');
61 $('#' + cmb.formfield + '_id').val('');
62 })
63 // Media/file management
64 .on( 'click', '.cmb-multicheck-toggle', cmb.toggleCheckBoxes )
65 .on( 'click', '.cmb_upload_button', cmb.handleMedia )
66 .on( 'click', '.cmb_remove_file_button', cmb.handleRemoveMedia )
67 // Repeatable content
68 .on( 'click', '.add-group-row', cmb.addGroupRow )
69 .on( 'click', '.add-row-button', cmb.addAjaxRow )
70 .on( 'click', '.remove-group-row', cmb.removeGroupRow )
71 .on( 'click', '.remove-row-button', cmb.removeAjaxRow )
72 // Ajax oEmbed display
73 .on( 'keyup paste focusout', '.cmb_oembed', cmb.maybeOembed )
74 // Reset titles when removing a row
75 .on( 'cmb_remove_row', '.repeatable-group', cmb.resetTitlesAndIterator );
76
77 if ( $repeatGroup.length ) {
78 $repeatGroup
79 .filter('.sortable').each( function() {
80 // Add sorting arrows
81 $(this).find( '.remove-group-row' ).before( '<a class="shift-rows move-up alignleft" href="#">'+ l10n.up_arrow +'</a> <a class="shift-rows move-down alignleft" href="#">'+ l10n.down_arrow +'</a>' );
82 })
83 .on( 'click', '.shift-rows', cmb.shiftRows )
84 .on( 'cmb_add_row', cmb.emptyValue );
85 }
86
87 // on pageload
88 setTimeout( cmb.resizeoEmbeds, 500);
89 // and on window resize
90 $(window).on( 'resize', cmb.resizeoEmbeds );
91
92 };
93
94 cmb.resetTitlesAndIterator = function() {
95 // Loop repeatable group tables
96 $( '.repeatable-group' ).each( function() {
97 var $table = $(this);
98 // Loop repeatable group table rows
99 $table.find( '.repeatable-grouping' ).each( function( rowindex ) {
100 var $row = $(this);
101 // Reset rows iterator
102 $row.data( 'iterator', rowindex );
103 // Reset rows title
104 $row.find( '.cmb-group-title h4' ).text( $table.find( '.add-group-row' ).data( 'grouptitle' ).replace( '{#}', ( rowindex + 1 ) ) );
105 });
106 });
107 };
108
109 cmb.toggleCheckBoxes = function( event ) {
110 event.preventDefault();
111 var $self = $(this);
112 var $multicheck = $self.parents( 'td' ).find( 'input[type=checkbox]' );
113
114 // If the button has already been clicked once...
115 if ( $self.data( 'checked' ) ) {
116 // clear the checkboxes and remove the flag
117 $multicheck.prop( 'checked', false );
118 $self.data( 'checked', false );
119 }
120 // Otherwise mark the checkboxes and add a flag
121 else {
122 $multicheck.prop( 'checked', true );
123 $self.data( 'checked', true );
124 }
125 };
126
127 cmb.handleMedia = function(event) {
128
129 if ( ! wp ) {
130 return;
131 }
132
133 event.preventDefault();
134
135 var $metabox = cmb.metabox();
136 var $self = $(this);
137 cmb.formfield = $self.prev('input').attr('id');
138 var $formfield = $('#'+cmb.formfield);
139 var formName = $formfield.attr('name');
140 var uploadStatus = true;
141 var attachment = true;
142 var isList = $self.hasClass( 'cmb_upload_list' );
143
144 // If this field's media frame already exists, reopen it.
145 if ( cmb.formfield in cmb.file_frames ) {
146 cmb.file_frames[cmb.formfield].open();
147 return;
148 }
149
150 // Create the media frame.
151 cmb.file_frames[cmb.formfield] = wp.media.frames.file_frame = wp.media({
152 title: $metabox.find('label[for=' + cmb.formfield + ']').text(),
153 button: {
154 text: l10n.upload_file
155 },
156 multiple: isList ? true : false
157 });
158
159 var handlers = {
160 list : function( selection ) {
161 // Get all of our selected files
162 attachment = selection.toJSON();
163
164 $formfield.val(attachment.url);
165 $('#'+ cmb.formfield +'_id').val(attachment.id);
166
167 // Setup our fileGroup array
168 var fileGroup = [];
169
170 // Loop through each attachment
171 $( attachment ).each( function() {
172 if ( this.type && this.type === 'image' ) {
173 // image preview
174 uploadStatus = '<li class="img_status">'+
175 '<img width="50" height="50" src="' + this.url + '" class="attachment-50x50" alt="'+ this.filename +'">'+
176 '<p><a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'['+ this.id +']">'+ l10n.remove_image +'</a></p>'+
177 '<input type="hidden" id="filelist-'+ this.id +'" name="'+ formName +'['+ this.id +']" value="' + this.url + '">'+
178 '</li>';
179
180 } else {
181 // Standard generic output if it's not an image.
182 uploadStatus = '<li>'+ l10n.file +' <strong>'+ this.filename +'</strong>&nbsp;&nbsp;&nbsp; (<a href="' + this.url + '" target="_blank" rel="external">'+ l10n.download +'</a> / <a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'['+ this.id +']">'+ l10n.remove_file +'</a>)'+
183 '<input type="hidden" id="filelist-'+ this.id +'" name="'+ formName +'['+ this.id +']" value="' + this.url + '">'+
184 '</li>';
185
186 }
187
188 // Add our file to our fileGroup array
189 fileGroup.push( uploadStatus );
190 });
191
192 // Append each item from our fileGroup array to .cmb_media_status
193 $( fileGroup ).each( function() {
194 $formfield.siblings('.cmb_media_status').slideDown().append(this);
195 });
196 },
197 single : function( selection ) {
198 // Only get one file from the uploader
199 attachment = selection.first().toJSON();
200
201 $formfield.val(attachment.url);
202 $('#'+ cmb.formfield +'_id').val(attachment.id);
203
204 if ( attachment.type && attachment.type === 'image' ) {
205 // image preview
206 uploadStatus = '<div class="img_status"><img style="max-width: 350px; width: 100%; height: auto;" src="' + attachment.url + '" alt="'+ attachment.filename +'" title="'+ attachment.filename +'" /><p><a href="#" class="cmb_remove_file_button" rel="' + cmb.formfield + '">'+ l10n.remove_image +'</a></p></div>';
207 } else {
208 // Standard generic output if it's not an image.
209 uploadStatus = l10n.file +' <strong>'+ attachment.filename +'</strong>&nbsp;&nbsp;&nbsp; (<a href="'+ attachment.url +'" target="_blank" rel="external">'+ l10n.download +'</a> / <a href="#" class="cmb_remove_file_button" rel="'+ cmb.formfield +'">'+ l10n.remove_file +'</a>)';
210 }
211
212 // add/display our output
213 $formfield.siblings('.cmb_media_status').slideDown().html(uploadStatus);
214 }
215 };
216
217 // When an file is selected, run a callback.
218 cmb.file_frames[cmb.formfield].on( 'select', function() {
219 var selection = cmb.file_frames[cmb.formfield].state().get('selection');
220 var type = isList ? 'list' : 'single';
221 handlers[type]( selection );
222 });
223
224 // Finally, open the modal
225 cmb.file_frames[cmb.formfield].open();
226 };
227
228 cmb.handleRemoveMedia = function( event ) {
229 event.preventDefault();
230 var $self = $(this);
231 if ( $self.is( '.attach_list .cmb_remove_file_button' ) ){
232 $self.parents('li').remove();
233 return false;
234 }
235 cmb.formfield = $self.attr('rel');
236 var $container = $self.parents('.img_status');
237
238 cmb.metabox().find('input#' + cmb.formfield).val('');
239 cmb.metabox().find('input#' + cmb.formfield + '_id').val('');
240 if ( ! $container.length ) {
241 $self.parents('.cmb_media_status').html('');
242 } else {
243 $container.html('');
244 }
245 return false;
246 };
247
248 // src: http://www.benalman.com/projects/jquery-replacetext-plugin/
249 $.fn.replaceText = function(b, a, c) {
250 return this.each(function() {
251 var f = this.firstChild, g, e, d = [];
252 if (f) {
253 do {
254 if (f.nodeType === 3) {
255 g = f.nodeValue;
256 e = g.replace(b, a);
257 if (e !== g) {
258 if (!c && /</.test(e)) {
259 $(f).before(e);
260 d.push(f);
261 } else {
262 f.nodeValue = e;
263 }
264 }
265 }
266 } while (f = f.nextSibling);
267 }
268 if ( d.length ) { $(d).remove(); }
269 });
270 };
271
272 $.fn.cleanRow = function( prevNum, group ) {
273 var $self = $(this);
274 var $inputs = $self.find('input:not([type="button"]), select, textarea, label');
275 if ( group ) {
276 // Remove extra ajaxed rows
277 $self.find('.cmb-repeat-table .repeat-row:not(:first-child)').remove();
278 }
279 cmb.$focus = false;
280 cmb.neweditor_id = [];
281
282 $inputs.filter(':checked').removeAttr( 'checked' );
283 $inputs.filter(':selected').removeAttr( 'selected' );
284
285 if ( $self.find('.cmb-group-title') ) {
286 $self.find( '.cmb-group-title h4' ).text( $self.data( 'title' ).replace( '{#}', ( cmb.idNumber + 1 ) ) );
287 }
288
289 $inputs.each( function(){
290 var $newInput = $(this);
291 var isEditor = $newInput.hasClass( 'wp-editor-area' );
292 var oldFor = $newInput.attr( 'for' );
293 // var $next = $newInput.next();
294 var attrs = {};
295 var newID, oldID;
296 if ( oldFor ) {
297 attrs = { 'for' : oldFor.replace( '_'+ prevNum, '_'+ cmb.idNumber ) };
298 } else {
299 var oldName = $newInput.attr( 'name' );
300 // Replace 'name' attribute key
301 var newName = oldName ? oldName.replace( '['+ prevNum +']', '['+ cmb.idNumber +']' ) : '';
302 oldID = $newInput.attr( 'id' );
303 newID = oldID ? oldID.replace( '_'+ prevNum, '_'+ cmb.idNumber ) : '';
304 attrs = {
305 id: newID,
306 name: newName,
307 // value: '',
308 'data-iterator': cmb.idNumber,
309 };
310 }
311
312 $newInput
313 .removeClass( 'hasDatepicker' )
314 .attr( attrs ).val('');
315
316 // wysiwyg field
317 if ( isEditor ) {
318 // Get new wysiwyg ID
319 newID = newID ? oldID.replace( 'zx'+ prevNum, 'zx'+ cmb.idNumber ) : '';
320 // Empty the contents
321 $newInput.html('');
322 // Get wysiwyg field
323 var $wysiwyg = $newInput.parents( '.cmb-type-wysiwyg' );
324 // Remove extra mce divs
325 $wysiwyg.find('.mce-tinymce:not(:first-child)').remove();
326 // Replace id instances
327 var html = $wysiwyg.html().replace( new RegExp( oldID, 'g' ), newID );
328 // Update field html
329 $wysiwyg.html( html );
330 // Save ids for later to re-init tinymce
331 cmb.neweditor_id.push( { 'id': newID, 'old': oldID } );
332 }
333
334 cmb.$focus = cmb.$focus ? cmb.$focus : $newInput;
335 });
336
337 return this;
338 };
339
340 $.fn.newRowHousekeeping = function() {
341 var $row = $(this);
342 var $colorPicker = $row.find( '.wp-picker-container' );
343 var $list = $row.find( '.cmb_media_status' );
344
345 if ( $colorPicker.length ) {
346 // Need to clean-up colorpicker before appending
347 $colorPicker.each( function() {
348 var $td = $(this).parent();
349 $td.html( $td.find( 'input:text.cmb_colorpicker' ).attr('style', '') );
350 });
351 }
352
353 // Need to clean-up colorpicker before appending
354 if ( $list.length ) {
355 $list.empty();
356 }
357
358 return this;
359 };
360
361 cmb.afterRowInsert = function( $row ) {
362 if ( cmb.$focus ) {
363 cmb.$focus.focus();
364 }
365
366 var _prop;
367
368 // Need to re-init wp_editor instances
369 if ( cmb.neweditor_id.length ) {
370 var i;
371 for ( i = cmb.neweditor_id.length - 1; i >= 0; i-- ) {
372 var id = cmb.neweditor_id[i].id;
373 var old = cmb.neweditor_id[i].old;
374
375 if ( typeof( tinyMCEPreInit.mceInit[ id ] ) === 'undefined' ) {
376 var newSettings = jQuery.extend( {}, tinyMCEPreInit.mceInit[ old ] );
377
378 for ( _prop in newSettings ) {
379 if ( 'string' === typeof( newSettings[_prop] ) ) {
380 newSettings[_prop] = newSettings[_prop].replace( new RegExp( old, 'g' ), id );
381 }
382 }
383 tinyMCEPreInit.mceInit[ id ] = newSettings;
384 }
385 if ( typeof( tinyMCEPreInit.qtInit[ id ] ) === 'undefined' ) {
386 var newQTS = jQuery.extend( {}, tinyMCEPreInit.qtInit[ old ] );
387 for ( _prop in newQTS ) {
388 if ( 'string' === typeof( newQTS[_prop] ) ) {
389 newQTS[_prop] = newQTS[_prop].replace( new RegExp( old, 'g' ), id );
390 }
391 }
392 tinyMCEPreInit.qtInit[ id ] = newQTS;
393 }
394 tinyMCE.init({
395 id : tinyMCEPreInit.mceInit[ id ],
396 });
397
398 }
399 }
400
401 // Init pickers from new row
402 cmb.initPickers( $row.find('input:text.cmb_timepicker'), $row.find('input:text.cmb_datepicker'), $row.find('input:text.cmb_colorpicker') );
403 };
404
405 cmb.updateNameAttr = function () {
406
407 var $this = $(this);
408 var name = $this.attr( 'name' ); // get current name
409
410 // No name? bail
411 if ( typeof name === 'undefined' ) {
412 return false;
413 }
414
415 var prevNum = parseInt( $this.parents( '.repeatable-grouping' ).data( 'iterator' ) );
416 var newNum = prevNum - 1; // Subtract 1 to get new iterator number
417
418 // Update field name attributes so data is not orphaned when a row is removed and post is saved
419 var $newName = name.replace( '[' + prevNum + ']', '[' + newNum + ']' );
420
421 // New name with replaced iterator
422 $this.attr( 'name', $newName );
423
424 };
425
426 cmb.emptyValue = function( event, row ) {
427 $('input:not([type="button"]), textarea', row).val('');
428 };
429
430 cmb.addGroupRow = function( event ) {
431
432 event.preventDefault();
433
434 var $self = $(this);
435 var $table = $('#'+ $self.data('selector'));
436 var $oldRow = $table.find('.repeatable-grouping').last();
437 var prevNum = parseInt( $oldRow.data('iterator') );
438 cmb.idNumber = prevNum + 1;
439 var $row = $oldRow.clone();
440
441 $row.data( 'title', $self.data( 'grouptitle' ) ).newRowHousekeeping().cleanRow( prevNum, true );
442
443 // console.log( '$row.html()', $row.html() );
444 var $newRow = $( '<tr class="repeatable-grouping" data-iterator="'+ cmb.idNumber +'">'+ $row.html() +'</tr>' );
445 $oldRow.after( $newRow );
446 // console.log( '$newRow.html()', $row.html() );
447
448 cmb.afterRowInsert( $newRow );
449
450 if ( $table.find('.repeatable-grouping').length <= 1 ) {
451 $table.find('.remove-group-row').prop('disabled', true);
452 } else {
453 $table.find('.remove-group-row').removeAttr( 'disabled' );
454 }
455
456 $table.trigger( 'cmb_add_row', $newRow );
457 };
458
459 cmb.addAjaxRow = function( event ) {
460
461 event.preventDefault();
462
463 var $self = $(this);
464 var tableselector = '#'+ $self.data('selector');
465 var $table = $(tableselector);
466 var $emptyrow = $table.find('.empty-row');
467 var prevNum = parseInt( $emptyrow.find('[data-iterator]').data('iterator') );
468 cmb.idNumber = prevNum + 1;
469 var $row = $emptyrow.clone();
470
471 $row.newRowHousekeeping().cleanRow( prevNum );
472
473 $emptyrow.removeClass('empty-row').addClass('repeat-row');
474 $emptyrow.after( $row );
475
476 cmb.afterRowInsert( $row );
477 $table.trigger( 'cmb_add_row', $row );
478 };
479
480 cmb.removeGroupRow = function( event ) {
481 event.preventDefault();
482 var $self = $(this);
483 var $table = $('#'+ $self.data('selector'));
484 var $parent = $self.parents('.repeatable-grouping');
485 var noRows = $table.find('.repeatable-grouping').length;
486
487 // when a group is removed loop through all next groups and update fields names
488 $parent.nextAll( '.repeatable-grouping' ).find( cmb.repeatEls ).each( cmb.updateNameAttr );
489
490 if ( noRows > 1 ) {
491 $parent.remove();
492 if ( noRows < 3 ) {
493 $table.find('.remove-group-row').prop('disabled', true);
494 } else {
495 $table.find('.remove-group-row').prop('disabled', false);
496 }
497 $table.trigger( 'cmb_remove_row' );
498 }
499 };
500
501 cmb.removeAjaxRow = function( event ) {
502 event.preventDefault();
503 var $self = $(this);
504 var $parent = $self.parents('tr');
505 var $table = $self.parents('.cmb-repeat-table');
506
507 // cmb.log( 'number of tbodys', $table.length );
508 // cmb.log( 'number of trs', $('tr', $table).length );
509 if ( $table.find('tr').length > 1 ) {
510 if ( $parent.hasClass('empty-row') ) {
511 $parent.prev().addClass( 'empty-row' ).removeClass('repeat-row');
512 }
513 $self.parents('.cmb-repeat-table tr').remove();
514 $table.trigger( 'cmb_remove_row' );
515 }
516 };
517
518 cmb.shiftRows = function( event ) {
519
520 event.preventDefault();
521
522 var $self = $(this);
523 var $parent = $self.parents( '.repeatable-grouping' );
524 var $goto = $self.hasClass( 'move-up' ) ? $parent.prev( '.repeatable-grouping' ) : $parent.next( '.repeatable-grouping' );
525
526 if ( ! $goto.length ) {
527 return;
528 }
529
530 var inputVals = [];
531 // Loop this items fields
532 $parent.find( cmb.repeatEls ).each( function() {
533 var $element = $(this);
534 var val;
535 if ( $element.hasClass('cmb_media_status') ) {
536 // special case for image previews
537 val = $element.html();
538 } else if ( 'checkbox' === $element.attr('type') ) {
539 val = $element.is(':checked');
540 cmb.log( 'checked', val );
541 } else if ( 'select' === $element.prop('tagName') ) {
542 val = $element.is(':selected');
543 cmb.log( 'checked', val );
544 } else {
545 val = $element.val();
546 }
547 // Get all the current values per element
548 inputVals.push( { val: val, $: $element } );
549 });
550 // And swap them all
551 $goto.find( cmb.repeatEls ).each( function( index ) {
552 var $element = $(this);
553 var val;
554
555 if ( $element.hasClass('cmb_media_status') ) {
556 // special case for image previews
557 val = $element.html();
558 $element.html( inputVals[ index ]['val'] );
559 inputVals[ index ]['$'].html( val );
560
561 }
562 // handle checkbox swapping
563 else if ( 'checkbox' === $element.attr('type') ) {
564 inputVals[ index ]['$'].prop( 'checked', $element.is(':checked') );
565 $element.prop( 'checked', inputVals[ index ]['val'] );
566 }
567 // handle select swapping
568 else if ( 'select' === $element.prop('tagName') ) {
569 inputVals[ index ]['$'].prop( 'selected', $element.is(':selected') );
570 $element.prop( 'selected', inputVals[ index ]['val'] );
571 }
572 // handle normal input swapping
573 else {
574 inputVals[ index ]['$'].val( $element.val() );
575 $element.val( inputVals[ index ]['val'] );
576 }
577 });
578 };
579
580 /**
581 * @todo make work, always
582 */
583 cmb.initPickers = function( $timePickers, $datePickers, $colorPickers ) {
584 // Initialize timepicker
585 cmb.initTimePickers( $timePickers );
586
587 // Initialize jQuery UI datepicker
588 cmb.initDatePickers( $datePickers );
589
590 // Initialize color picker
591 cmb.initColorPickers( $colorPickers );
592 };
593
594 cmb.initTimePickers = function( $selector ) {
595 if ( ! $selector.length ) {
596 return;
597 }
598
599 $selector.timePicker({
600 startTime: "00:00",
601 endTime: "23:59",
602 show24Hours: false,
603 separator: ':',
604 step: 30
605 });
606 };
607
608 cmb.initDatePickers = function( $selector ) {
609 if ( ! $selector.length ) {
610 return;
611 }
612
613 $selector.datepicker( "destroy" );
614 $selector.datepicker();
615 };
616
617 cmb.initColorPickers = function( $selector ) {
618 if ( ! $selector.length ) {
619 return;
620 }
621 if (typeof jQuery.wp === 'object' && typeof jQuery.wp.wpColorPicker === 'function') {
622
623 $selector.wpColorPicker();
624
625 } else {
626 $selector.each( function(i) {
627 $(this).after('<div id="picker-' + i + '" style="z-index: 1000; background: #EEE; border: 1px solid #CCC; position: absolute; display: block;"></div>');
628 $('#picker-' + i).hide().farbtastic($(this));
629 })
630 .focus( function() {
631 $(this).next().show();
632 })
633 .blur( function() {
634 $(this).next().hide();
635 });
636 }
637 };
638
639 cmb.maybeOembed = function( evt ) {
640 var $self = $(this);
641 var type = evt.type;
642
643 var m = {
644 focusout : function() {
645 setTimeout( function() {
646 // if it's been 2 seconds, hide our spinner
647 cmb.spinner( '.postbox table.cmb_metabox', true );
648 }, 2000);
649 },
650 keyup : function() {
651 var betw = function( min, max ) {
652 return ( evt.which <= max && evt.which >= min );
653 };
654 // Only Ajax on normal keystrokes
655 if ( betw( 48, 90 ) || betw( 96, 111 ) || betw( 8, 9 ) || evt.which === 187 || evt.which === 190 ) {
656 // fire our ajax function
657 cmb.doAjax( $self, evt);
658 }
659 },
660 paste : function() {
661 // paste event is fired before the value is filled, so wait a bit
662 setTimeout( function() { cmb.doAjax( $self ); }, 100);
663 }
664 };
665 m[type]();
666
667 };
668
669 /**
670 * Resize oEmbed videos to fit in their respective metaboxes
671 */
672 cmb.resizeoEmbeds = function() {
673 cmb.metabox().each( function() {
674 var $self = $(this);
675 var $tableWrap = $self.parents('.inside');
676 if ( ! $tableWrap.length ) {
677 return true; // continue
678 }
679
680 // Calculate new width
681 var newWidth = Math.round(($tableWrap.width() * 0.82)*0.97) - 30;
682 if ( newWidth > 639 ) {
683 return true; // continue
684 }
685
686 var $embeds = $self.find('.cmb-type-oembed .embed_status');
687 var $children = $embeds.children().not('.cmb_remove_wrapper');
688 if ( ! $children.length ) {
689 return true; // continue
690 }
691
692 $children.each( function() {
693 var $self = $(this);
694 var iwidth = $self.width();
695 var iheight = $self.height();
696 var _newWidth = newWidth;
697 if ( $self.parents( '.repeat-row' ).length ) {
698 // Make room for our repeatable "remove" button column
699 _newWidth = newWidth - 91;
700 }
701 // Calc new height
702 var newHeight = Math.round((_newWidth * iheight)/iwidth);
703 $self.width(_newWidth).height(newHeight);
704 });
705
706 });
707 };
708
709 /**
710 * Safely log things if query var is set
711 * @since 1.0.0
712 */
713 cmb.log = function() {
714 if ( l10n.script_debug && console && typeof console.log === 'function' ) {
715 console.log.apply(console, arguments);
716 }
717 };
718
719 cmb.spinner = function( $context, hide ) {
720 if ( hide ) {
721 $('.cmb-spinner', $context ).hide();
722 }
723 else {
724 $('.cmb-spinner', $context ).show();
725 }
726 };
727
728 // function for running our ajax
729 cmb.doAjax = function($obj) {
730 // get typed value
731 var oembed_url = $obj.val();
732 // only proceed if the field contains more than 6 characters
733 if ( oembed_url.length < 6 ) {
734 return;
735 }
736
737 // only proceed if the user has pasted, pressed a number, letter, or whitelisted characters
738
739 // get field id
740 var field_id = $obj.attr('id');
741 // get our inputs $context for pinpointing
742 var $context = $obj.parents('.cmb-repeat-table tr td');
743 $context = $context.length ? $context : $obj.parents('.cmb_metabox tr td');
744
745 var embed_container = $('.embed_status', $context);
746 var oembed_width = $obj.width();
747 var child_el = $(':first-child', embed_container);
748
749 // http://www.youtube.com/watch?v=dGG7aru2S6U
750 cmb.log( 'oembed_url', oembed_url, field_id );
751 oembed_width = ( embed_container.length && child_el.length ) ? child_el.width() : $obj.width();
752
753 // show our spinner
754 cmb.spinner( $context );
755 // clear out previous results
756 $('.embed_wrap', $context).html('');
757 // and run our ajax function
758 setTimeout( function() {
759 // if they haven't typed in 500 ms
760 if ( $('.cmb_oembed:focus').val() !== oembed_url ) {
761 return;
762 }
763 $.ajax({
764 type : 'post',
765 dataType : 'json',
766 url : l10n.ajaxurl,
767 data : {
768 'action': 'cmb_oembed_handler',
769 'oembed_url': oembed_url,
770 'oembed_width': oembed_width > 300 ? oembed_width : 300,
771 'field_id': field_id,
772 'object_id': $obj.data('objectid'),
773 'object_type': $obj.data('objecttype'),
774 'cmb_ajax_nonce': l10n.ajax_nonce
775 },
776 success: function(response) {
777 cmb.log( response );
778 // Make sure we have a response id
779 if ( typeof response.id === 'undefined' ) {
780 return;
781 }
782
783 // hide our spinner
784 cmb.spinner( $context, true );
785 // and populate our results from ajax response
786 $('.embed_wrap', $context).html(response.result);
787 }
788 });
789
790 }, 500);
791 };
792
793 $(document).ready(cmb.init);
794
795 return cmb;
796
797 })(window, document, jQuery);
798