';
+
+
$fields = $this->get_fields_in_multifield( $multifield->group, $slug, $object_type );
// validate/weed out the fields that can't be part of mulitified
@@ -1110,20 +1124,37 @@ function _display_metadata_multifield( $slug, $multifield, $object_type, $object
foreach ( $_values as $grouping_of_values ) {
$grouping_count++;
$grouping_id = $slug . '-' . $grouping_count;
+
printf( '
';
}
@@ -1143,7 +1174,7 @@ function _display_metadata_field( $field_slug, $field, $object_type, $object_id,
$callback = $field->display_callback;
if ( $callback && is_callable( $callback ) ) {
- call_user_func( $callback, $field_slug, $field, $object_type, $object_id, $value );
+ call_user_func( $callback, $field_slug, $field, $object_type, $object_id, $field_id, $value );
return;
}
@@ -1182,6 +1213,7 @@ function _display_metadata_field( $field_slug, $field, $object_type, $object_id,
$container_class = sanitize_html_class( $field_slug );
$container_class .= ( $cloneable ) ? ' cloneable' : '';
foreach ( $value as $v ) :
+
$container_id = $field_slug . '-' . $count;
printf( '
', esc_attr( $container_class ), esc_attr( $container_id ) );
@@ -1249,12 +1281,18 @@ function _display_metadata_field( $field_slug, $field, $object_type, $object_id,
wp_editor( $v, $field_id, $wysiwyg_args );
break;
case 'upload' :
- $_attachment_id = $this->get_metadata_field_value( $field_slug . '_attachment_id', $field, $object_type, $object_id );
- $attachment_id = array_shift( array_values( $_attachment_id ) ); // get the first value in the array
- printf( '
', esc_attr( $field_id ), esc_attr( $v ), $readonly_str, $placeholder_str );
+ if( isset($field->multifield) && $field->multifield != '' ) {
+ printf( '
', esc_attr( $field_id ), esc_attr( $v['url'] ), $readonly_str, $placeholder_str );
+ printf( '
', esc_attr( str_replace('image]', 'image_attachment_id]', $field_id) ), esc_attr( $v['id'] ) );
+ } else {
+ $_attachment_id = $this->get_metadata_field_value( $field_slug . '_attachment_id', $field, $object_type, $object_id );
+ $_attachment_id_values = array_values( $_attachment_id );
+ $attachment_id = array_shift( $_attachment_id_values ); // get the first value in the array
+ printf( '
', esc_attr( $field_id ), esc_attr( $v ), $readonly_str, $placeholder_str );
+ printf( '
', esc_attr( $field_id . '_attachment_id' ), esc_attr( $attachment_id ) );
+ }
printf( '
', esc_attr( $field->upload_modal_title ), esc_attr( $field->upload_modal_button_text ), esc_attr( $field->upload_modal_title ) );
printf( '
', $field->upload_clear_button_text );
- printf( '
', esc_attr( $field_id . '_attachment_id' ), esc_attr( $attachment_id ) );
break;
case 'taxonomy_select' :
$terms = get_terms( $field->taxonomy, array( 'hide_empty' => false ) );
@@ -1282,6 +1320,12 @@ function _display_metadata_field( $field_slug, $field, $object_type, $object_id,
echo '';
}
break;
+ case 'sortable_select' :
+ $container_class = sanitize_html_class( $field_slug );
+ printf( '
', esc_attr( $container_class ), esc_attr( $field_id ) );
+ printf( '', esc_attr( $field_slug ), esc_attr( $field_id ), esc_attr( $v ), esc_attr( json_encode($field->values) ) );
+ echo '
';
+ break;
endswitch;
if ( $cloneable && $count > 1 )
diff --git a/js/custom-metadata-manager.js b/js/custom-metadata-manager.js
index f1b17b3..3375f89 100644
--- a/js/custom-metadata-manager.js
+++ b/js/custom-metadata-manager.js
@@ -4,12 +4,86 @@
var $custom_metadata_field = $( '.custom-metadata-field' ),
$custom_metadata_multifield = $( '.custom-metadata-multifield' );
+ var initMultiselectSortable = function() {
+ $('.select2-sortable').each(function() {
+ var select = $(this);
+ var values = $.makeArray(jQuery.parseJSON($(this).attr('data-possible-values')));
+ $(this).select2({
+ data: values,
+ multiple: true
+ });
+
+ $(this).select2("container").find("ul.select2-choices").sortable({
+ containment: 'parent',
+ start: function() { select.select2('onSortStart'); },
+ update: function() { select.select2('onSortEnd'); }
+ });
+ });
+ };
+
+ initMultiselectSortable();
+
var incrementor = function(v) {
return v.replace( /[0-9]+(?!.*[0-9])/ , function( match ) {
return parseInt(match, 10) + 1;
});
};
+ var destroy_date_pickers = function( ) {
+ var $datepickers = $( '.custom-metadata-field.datepicker input' ),
+ $datetimepickers = $( '.custom-metadata-field.datetimepicker input' ),
+ $timepickers = $( '.custom-metadata-field.timepicker input' );
+
+ $datepickers.each(function() {
+ var $this = $(this);
+ if( $this.hasClass('hasDatepicker') ) {
+ $this.datepicker( 'destroy' );
+ $this.removeClass('hasDatepicker');
+ }
+ });
+
+ $datetimepickers.each(function() {
+ var $this = $(this);
+ if( $this.hasClass('hasDatepicker') ) {
+ $this.datetimepicker( 'destroy' );
+ $this.removeClass('hasDatepicker');
+ }
+ });
+
+ $timepickers.each(function() {
+ var $this = $(this);
+ if( $this.hasClass('hasDatepicker') ) {
+ $this.timepicker( 'destroy' );
+ $this.removeClass('hasDatepicker');
+ }
+ });
+ };
+
+ var bind_date_pickers = function() {
+
+ var $datepickers = $( '.custom-metadata-field.datepicker input' ),
+ $datetimepickers = $( '.custom-metadata-field.datetimepicker input' ),
+ $timepickers = $( '.custom-metadata-field.timepicker input' );
+
+ // init the datepicker fields
+ $datepickers.datepicker({
+ changeMonth: true,
+ changeYear: true
+ });
+
+ // init the datetimepicker fields
+ $datetimepickers.datetimepicker({
+ changeMonth: true,
+ changeYear: true
+ });
+
+ // init the timepicker fields
+ $timepickers.timepicker({
+ changeMonth: true,
+ changeYear: true
+ });
+ };
+
// duplicating fields
$custom_metadata_field.on( 'click.custom_metadata', '.add-multiple', function(e){
e.preventDefault();
@@ -34,90 +108,27 @@
});
});
- // cloning multifields
- $custom_metadata_multifield.on( 'click.custom_metadata', '.custom-metadata-multifield-clone', function(e){
- e.preventDefault();
- var $this = $( this ),
- $parent = $this.parent().parent(),
- $slug = $parent.attr( 'data-slug' ),
- $last = $this.parent(),
- $clone = $last.clone();
-
- $clone.find( ':input:not(:button)' ).val('');
- $clone.insertAfter( $last ).hide();
-
- $groupings = $parent.find('.custom-metadata-multifield-grouping');
-
- $.each( $groupings, function( i, grouping ){
-
- var $grouping = $( grouping ),
- $fields = $grouping.find('.custom-metadata-field'),
- num = i + 1;
-
- $grouping.attr( 'id', $slug + '-' + num );
-
- $.each( $fields, function( j, field ){
- var $field = $( field ),
- $field_slug = $field.attr( 'data-slug' ),
- $label = $field.find( 'label' ),
- $div = $field.find( 'div' ),
- $field_inputs = $field.find( ':input:not(:button)' ),
- $field_id = $field_slug + '-' + num;
-
- $label.attr( 'for', $field_id );
- $div.attr( 'id', $field_id + '-1' ).attr( 'class', $field_id );
-
- $.each( $field_inputs, function( k, field_input ){
-
- var $field_input = $( field_input );
-
- if ( ! _.isEmpty( $field_input.attr( 'id' ) ) ) {
- $field_input.attr( 'id', $field_id );
- }
-
- if ( ! _.isEmpty( $field_input.attr( 'name' ) ) ) {
- $field_input.attr( 'name', $slug + '[' + i + '][' + $field_slug + ']');
- }
- });
-
- });
-
- });
-
- $clone.fadeIn();
-
- });
-
- // deleting multifields
- $custom_metadata_multifield.on( 'click.custom_metadata', '.custom-metadata-multifield-delete', function(e){
- e.preventDefault();
- var $this = $( this );
- $this.parent().fadeOut('normal', function(){
- $(this).remove();
- });
- });
-
// init upload fields
var custom_metadata_file_frame;
$custom_metadata_field.on( 'click.custom_metadata', '.custom-metadata-upload-button', function(e) {
e.preventDefault();
var $this = $(this),
- $this_field = $this.parent();
-
- // if the media frame already exists, reopen it.
- if ( custom_metadata_file_frame ) {
- custom_metadata_file_frame.open();
- return;
+ $this_field = $this.parent();
+
+ // if the media frame doesn't exist yet, create it
+ if ( ! custom_metadata_file_frame ) {
+ custom_metadata_file_frame = wp.media.frames.file_frame = wp.media({
+ title: $this.data( 'uploader-title' ),
+ button: {
+ text: $this.data( 'uploader-button-text' )
+ },
+ multiple: false
+ });
}
- custom_metadata_file_frame = wp.media.frames.file_frame = wp.media({
- title: $this.data( 'uploader-title' ),
- button: {
- text: $this.data( 'uploader-button-text' )
- },
- multiple: false
- });
+ // unbind prior events first
+ custom_metadata_file_frame.off( 'select' );
custom_metadata_file_frame.on( 'select', function() {
attachment = custom_metadata_file_frame.state().get( 'selection' ).first().toJSON();
@@ -138,6 +149,7 @@
// init link fields
var custom_metadata_link_selector_is_open = false;
var custom_metadata_link_selector_target = null;
+
$custom_metadata_field.on( 'click.custom_metadata', '.custom-metadata-link-button', function(e){
e.preventDefault();
custom_metadata_link_selector_is_open = true;
@@ -173,27 +185,131 @@
custom_metadata_link_selector_is_open = false;
});
- // init the datepicker fields
- $( '.custom-metadata-field.datepicker' ).find( 'input' ).datepicker({
- changeMonth: true,
- changeYear: true
+ // First initialization of datepickers
+ bind_date_pickers();
+
+ // select2
+ $custom_metadata_field.find( '.custom-metadata-select2' ).each(function(index) {
+ $(this).select2({ placeholder : $(this).attr('data-placeholder'), allowClear : true });
});
- // init the datetimepicker fields
- $( '.custom-metadata-field.datetimepicker' ).find( 'input' ).datetimepicker({
- changeMonth: true,
- changeYear: true
+
+ /* MULTIFIELDS */
+
+ // reset field names, container ids, etc
+ var multifield_after_change = function( $container ) {
+ var $slug = $container.attr( 'data-slug' ),
+ $groupings = $container.find('.custom-metadata-multifield-grouping');
+
+ $groupings = $container.find('.custom-metadata-multifield-grouping');
+
+ $.each( $groupings, function( i, grouping ){
+
+ var $grouping = $( grouping ),
+ $fields = $grouping.find('.custom-metadata-field'),
+ num = i + 1;
+
+ $grouping.attr( 'id', $slug + '-' + num );
+
+ $.each( $fields, function( j, field ){
+ var $field = $( field ),
+ $field_slug = $field.attr( 'data-slug' ),
+ $label = $field.find( 'label' ),
+ $div = $field.find( 'div' ),
+ $field_inputs = $field.find( ':input:not(:button)' ),
+ $field_id = $field_slug + '-' + num;
+
+ $label.attr( 'for', $field_id );
+ $div.attr( 'id', $field_id + '-1' ).attr( 'class', $field_id );
+
+ $.each( $field_inputs, function( k, field_input ){
+
+ var $field_input = $( field_input );
+
+ if ( ! _.isEmpty( $field_input.attr( 'id' ) ) ) {
+ $field_input.attr( 'id', $field_id );
+ }
+
+ if ( ! _.isEmpty( $field_input.attr( 'name' ) ) ) {
+ $field_input.attr( 'name', $slug + '[' + i + '][' + $field_slug + ']');
+ }
+ });
+
+ });
+
+ });
+ };
+
+ // Adds sortable functionality to multifields
+ $('.custom-metadata-multifield').sortable({
+ items: '.custom-metadata-multifield-grouping',
+ handle: '.sort-handle'
});
- // init the timepicker fields
- $( '.custom-metadata-field.timepicker' ).find( 'input' ).timepicker({
- changeMonth: true,
- changeYear: true
+ $('.custom-metadata-multifield').sortable().bind('sortupdate', function(e) {
+ multifield_after_change( $(this) );
});
- // select2
- $custom_metadata_field.find( '.custom-metadata-select2' ).each(function(index) {
- $(this).select2();
+ // adding multifields
+ $custom_metadata_multifield.on( 'click.custom_metadata', '.custom-metadata-multifield-add', function(e){
+ e.preventDefault();
+
+ destroy_date_pickers();
+
+ var $this = $( this ),
+ $container = $this.parents('.custom-metadata-multifield'),
+ $elements = $container.find('.custom-metadata-multifield-grouping'),
+ $element_to_clone = $elements.first(),
+ $clone = $element_to_clone.clone(true);
+
+ $clone.find( ':input:not(:button)' ).val('');
+ $clone.insertAfter( $elements.last() ).hide();
+
+ multifield_after_change( $container );
+ bind_date_pickers();
+
+ $clone.fadeIn();
+
+ });
+
+ // cloning multifields
+ $custom_metadata_multifield.on( 'click.custom_metadata', '.custom-metadata-multifield-clone', function(e){
+
+ e.preventDefault();
+
+ destroy_date_pickers();
+
+ var $this = $( this ),
+ $element_to_clone = $this.parents('.custom-metadata-multifield-grouping'),
+ $container = $this.parents('.custom-metadata-multifield'),
+ $clone = $element_to_clone.clone(true);
+
+ $clone.insertAfter( $element_to_clone ).hide();
+
+ multifield_after_change( $container );
+ bind_date_pickers();
+
+ $clone.fadeIn();
+
+ });
+
+ // deleting multifields
+ $custom_metadata_multifield.on( 'click.custom_metadata', '.custom-metadata-multifield-delete', function(e){
+ e.preventDefault();
+ destroy_date_pickers();
+ var $this = $( this ),
+ $element_to_delete = $this.parents('.custom-metadata-multifield-grouping'),
+ $container = $this.parents('.custom-metadata-multifield');
+
+ if( $container.find('.custom-metadata-multifield-grouping').length === 1 ) {
+ $element_to_delete.find( ':input:not(:button)' ).val('');
+ } else {
+ $element_to_delete.fadeOut('normal', function(){
+ $(this).remove();
+ multifield_after_change( $container );
+ });
+ }
+ bind_date_pickers();
});
});
diff --git a/js/jquery.sortable.js b/js/jquery.sortable.js
new file mode 100644
index 0000000..350d172
--- /dev/null
+++ b/js/jquery.sortable.js
@@ -0,0 +1,85 @@
+/*
+ * HTML5 Sortable jQuery Plugin
+ * http://farhadi.ir/projects/html5sortable
+ *
+ * Copyright 2012, Ali Farhadi
+ * Released under the MIT license.
+ */
+(function($) {
+var dragging, placeholders = $();
+$.fn.sortable = function(options) {
+ var method = String(options);
+ options = $.extend({
+ connectWith: false
+ }, options);
+ return this.each(function() {
+ if (/^enable|disable|destroy$/.test(method)) {
+ var items = $(this).children($(this).data('items')).attr('draggable', method == 'enable');
+ if (method == 'destroy') {
+ items.add(this).removeData('connectWith items')
+ .off('dragstart.h5s dragend.h5s selectstart.h5s dragover.h5s dragenter.h5s drop.h5s');
+ }
+ return;
+ }
+ var isHandle, index, items = $(this).children(options.items);
+ var placeholder = $('<' + (/^ul|ol$/i.test(this.tagName) ? 'li' : 'div') + ' class="sortable-placeholder">');
+ items.find(options.handle).mousedown(function() {
+ isHandle = true;
+ }).mouseup(function() {
+ isHandle = false;
+ });
+ $(this).data('items', options.items)
+ placeholders = placeholders.add(placeholder);
+ if (options.connectWith) {
+ $(options.connectWith).add(this).data('connectWith', options.connectWith);
+ }
+ items.attr('draggable', 'true').on('dragstart.h5s', function(e) {
+ if (options.handle && !isHandle) {
+ return false;
+ }
+ isHandle = false;
+ var dt = e.originalEvent.dataTransfer;
+ dt.effectAllowed = 'move';
+ dt.setData('Text', 'dummy');
+ index = (dragging = $(this)).addClass('sortable-dragging').index();
+ }).on('dragend.h5s', function() {
+ if (!dragging) {
+ return;
+ }
+ dragging.removeClass('sortable-dragging').show();
+ placeholders.detach();
+ if (index != dragging.index()) {
+ dragging.parent().trigger('sortupdate', {item: dragging});
+ }
+ dragging = null;
+ }).not('a[href], img').on('selectstart.h5s', function() {
+ this.dragDrop && this.dragDrop();
+ return false;
+ }).end().add([this, placeholder]).on('dragover.h5s dragenter.h5s drop.h5s', function(e) {
+ if (!items.is(dragging) && options.connectWith !== $(dragging).parent().data('connectWith')) {
+ return true;
+ }
+ if (e.type == 'drop') {
+ e.stopPropagation();
+ placeholders.filter(':visible').after(dragging);
+ dragging.trigger('dragend.h5s');
+ return false;
+ }
+ e.preventDefault();
+ e.originalEvent.dataTransfer.dropEffect = 'move';
+ if (items.is(this)) {
+ if (options.forcePlaceholderSize) {
+ placeholder.height(dragging.outerHeight());
+ }
+ dragging.hide();
+ $(this)[placeholder.index() < $(this).index() ? 'after' : 'before'](placeholder);
+ placeholders.not(placeholder).detach();
+ } else if (!placeholders.is(this) && !$(this).children(options.items).length) {
+ placeholders.detach();
+ $(this).append(placeholder);
+ }
+ return false;
+ });
+ });
+};
+})(jQuery);