380 lines
7.9 KiB
JavaScript
380 lines
7.9 KiB
JavaScript
(function($, undefined){
|
|
|
|
var Field = acf.Field.extend({
|
|
|
|
type: 'relationship',
|
|
|
|
events: {
|
|
'keypress [data-filter]': 'onKeypressFilter',
|
|
'change [data-filter]': 'onChangeFilter',
|
|
'keyup [data-filter]': 'onChangeFilter',
|
|
'click .choices-list .acf-rel-item': 'onClickAdd',
|
|
'click [data-name="remove_item"]': 'onClickRemove',
|
|
'mouseover': 'onHover'
|
|
},
|
|
|
|
$control: function(){
|
|
return this.$('.acf-relationship');
|
|
},
|
|
|
|
$list: function( list ) {
|
|
return this.$('.' + list + '-list');
|
|
},
|
|
|
|
$listItems: function( list ) {
|
|
return this.$list( list ).find('.acf-rel-item');
|
|
},
|
|
|
|
$listItem: function( list, id ) {
|
|
return this.$list( list ).find('.acf-rel-item[data-id="' + id + '"]');
|
|
},
|
|
|
|
getValue: function(){
|
|
var val = [];
|
|
this.$listItems('values').each(function(){
|
|
val.push( $(this).data('id') );
|
|
});
|
|
return val.length ? val : false;
|
|
},
|
|
|
|
newChoice: function( props ){
|
|
return [
|
|
'<li>',
|
|
'<span data-id="' + props.id + '" class="acf-rel-item">' + props.text + '</span>',
|
|
'</li>'
|
|
].join('');
|
|
},
|
|
|
|
newValue: function( props ){
|
|
return [
|
|
'<li>',
|
|
'<input type="hidden" name="' + this.getInputName() + '[]" value="' + props.id + '" />',
|
|
'<span data-id="' + props.id + '" class="acf-rel-item">' + props.text,
|
|
'<a href="#" class="acf-icon -minus small dark" data-name="remove_item"></a>',
|
|
'</span>',
|
|
'</li>'
|
|
].join('');
|
|
},
|
|
|
|
addSortable: function( self ){
|
|
|
|
// sortable
|
|
this.$list('values').sortable({
|
|
items: 'li',
|
|
forceHelperSize: true,
|
|
forcePlaceholderSize: true,
|
|
scroll: true,
|
|
update: function(){
|
|
self.$input().trigger('change');
|
|
}
|
|
});
|
|
},
|
|
|
|
initialize: function(){
|
|
|
|
// scroll
|
|
var onScroll = this.proxy(function(e){
|
|
|
|
// bail early if no more results
|
|
if( this.get('loading') || !this.get('more') ) {
|
|
return;
|
|
}
|
|
|
|
// Scrolled to bottom
|
|
var $list = this.$list('choices');
|
|
var scrollTop = Math.ceil( $list.scrollTop() );
|
|
var scrollHeight = Math.ceil( $list[0].scrollHeight );
|
|
var innerHeight = Math.ceil( $list.innerHeight() );
|
|
var paged = this.get('paged') || 1;
|
|
if( (scrollTop + innerHeight) >= scrollHeight ) {
|
|
|
|
// update paged
|
|
this.set('paged', (paged+1));
|
|
|
|
// fetch
|
|
this.fetch();
|
|
}
|
|
|
|
});
|
|
|
|
this.$list('choices').scrollTop(0).on('scroll', onScroll);
|
|
|
|
// fetch
|
|
this.fetch();
|
|
},
|
|
|
|
onHover: function( e ){
|
|
|
|
// only once
|
|
$().off(e);
|
|
|
|
// add sortable
|
|
this.addSortable( this );
|
|
},
|
|
|
|
onKeypressFilter: function( e, $el ){
|
|
|
|
// don't submit form
|
|
if( e.which == 13 ) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
|
|
onChangeFilter: function( e, $el ){
|
|
|
|
// vars
|
|
var val = $el.val();
|
|
var filter = $el.data('filter');
|
|
|
|
// Bail early if filter has not changed
|
|
if( this.get(filter) === val ) {
|
|
return;
|
|
}
|
|
|
|
// update attr
|
|
this.set(filter, val);
|
|
|
|
// reset paged
|
|
this.set('paged', 1);
|
|
|
|
// fetch
|
|
if( $el.is('select') ) {
|
|
this.fetch();
|
|
|
|
// search must go through timeout
|
|
} else {
|
|
this.maybeFetch();
|
|
}
|
|
},
|
|
|
|
onClickAdd: function( e, $el ){
|
|
|
|
// vars
|
|
var val = this.val();
|
|
var max = parseInt( this.get('max') );
|
|
|
|
// can be added?
|
|
if( $el.hasClass('disabled') ) {
|
|
return false;
|
|
}
|
|
|
|
// validate
|
|
if( max > 0 && val && val.length >= max ) {
|
|
|
|
// add notice
|
|
this.showNotice({
|
|
text: acf.__('Maximum values reached ( {max} values )').replace('{max}', max),
|
|
type: 'warning'
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// disable
|
|
$el.addClass('disabled');
|
|
|
|
// add
|
|
var html = this.newValue({
|
|
id: $el.data('id'),
|
|
text: $el.html()
|
|
});
|
|
this.$list('values').append( html )
|
|
|
|
// trigger change
|
|
this.$input().trigger('change');
|
|
},
|
|
|
|
onClickRemove: function( e, $el ){
|
|
|
|
// Prevent default here because generic handler wont be triggered.
|
|
e.preventDefault();
|
|
|
|
// vars
|
|
var $span = $el.parent();
|
|
var $li = $span.parent();
|
|
var id = $span.data('id');
|
|
|
|
// remove value
|
|
$li.remove();
|
|
|
|
// show choice
|
|
this.$listItem('choices', id).removeClass('disabled');
|
|
|
|
// trigger change
|
|
this.$input().trigger('change');
|
|
},
|
|
|
|
maybeFetch: function(){
|
|
|
|
// vars
|
|
var timeout = this.get('timeout');
|
|
|
|
// abort timeout
|
|
if( timeout ) {
|
|
clearTimeout( timeout );
|
|
}
|
|
|
|
// fetch
|
|
timeout = this.setTimeout(this.fetch, 300);
|
|
this.set('timeout', timeout);
|
|
},
|
|
|
|
getAjaxData: function(){
|
|
|
|
// load data based on element attributes
|
|
var ajaxData = this.$control().data();
|
|
for( var name in ajaxData ) {
|
|
ajaxData[ name ] = this.get( name );
|
|
}
|
|
|
|
// extra
|
|
ajaxData.action = 'acf/fields/relationship/query';
|
|
ajaxData.field_key = this.get('key');
|
|
|
|
// Filter.
|
|
ajaxData = acf.applyFilters( 'relationship_ajax_data', ajaxData, this );
|
|
|
|
// return
|
|
return ajaxData;
|
|
},
|
|
|
|
fetch: function(){
|
|
|
|
// abort XHR if this field is already loading AJAX data
|
|
var xhr = this.get('xhr');
|
|
if( xhr ) {
|
|
xhr.abort();
|
|
}
|
|
|
|
// add to this.o
|
|
var ajaxData = this.getAjaxData();
|
|
|
|
// clear html if is new query
|
|
var $choiceslist = this.$list( 'choices' );
|
|
if( ajaxData.paged == 1 ) {
|
|
$choiceslist.html('');
|
|
}
|
|
|
|
// loading
|
|
var $loading = $('<li><i class="acf-loading"></i> ' + acf.__('Loading') + '</li>');
|
|
$choiceslist.append($loading);
|
|
this.set('loading', true);
|
|
|
|
// callback
|
|
var onComplete = function(){
|
|
this.set('loading', false);
|
|
$loading.remove();
|
|
};
|
|
|
|
var onSuccess = function( json ){
|
|
|
|
// no results
|
|
if( !json || !json.results || !json.results.length ) {
|
|
|
|
// prevent pagination
|
|
this.set('more', false);
|
|
|
|
// add message
|
|
if( this.get('paged') == 1 ) {
|
|
this.$list('choices').append('<li>' + acf.__('No matches found') + '</li>');
|
|
}
|
|
|
|
// return
|
|
return;
|
|
}
|
|
|
|
// set more (allows pagination scroll)
|
|
this.set('more', json.more );
|
|
|
|
// get new results
|
|
var html = this.walkChoices(json.results);
|
|
var $html = $( html );
|
|
|
|
// apply .disabled to left li's
|
|
var val = this.val();
|
|
if( val && val.length ) {
|
|
val.map(function( id ){
|
|
$html.find('.acf-rel-item[data-id="' + id + '"]').addClass('disabled');
|
|
});
|
|
}
|
|
|
|
// append
|
|
$choiceslist.append( $html );
|
|
|
|
// merge together groups
|
|
var $prevLabel = false;
|
|
var $prevList = false;
|
|
|
|
$choiceslist.find('.acf-rel-label').each(function(){
|
|
|
|
var $label = $(this);
|
|
var $list = $label.siblings('ul');
|
|
|
|
if( $prevLabel && $prevLabel.text() == $label.text() ) {
|
|
$prevList.append( $list.children() );
|
|
$(this).parent().remove();
|
|
return;
|
|
}
|
|
|
|
// update vars
|
|
$prevLabel = $label;
|
|
$prevList = $list;
|
|
});
|
|
};
|
|
|
|
// get results
|
|
var xhr = $.ajax({
|
|
url: acf.get('ajaxurl'),
|
|
dataType: 'json',
|
|
type: 'post',
|
|
data: acf.prepareForAjax(ajaxData),
|
|
context: this,
|
|
success: onSuccess,
|
|
complete: onComplete
|
|
});
|
|
|
|
// set
|
|
this.set('xhr', xhr);
|
|
},
|
|
|
|
walkChoices: function( data ){
|
|
|
|
// walker
|
|
var walk = function( data ){
|
|
|
|
// vars
|
|
var html = '';
|
|
|
|
// is array
|
|
if( $.isArray(data) ) {
|
|
data.map(function(item){
|
|
html += walk( item );
|
|
});
|
|
|
|
// is item
|
|
} else if( $.isPlainObject(data) ) {
|
|
|
|
// group
|
|
if( data.children !== undefined ) {
|
|
|
|
html += '<li><span class="acf-rel-label">' + data.text + '</span><ul class="acf-bl">';
|
|
html += walk( data.children );
|
|
html += '</ul></li>';
|
|
|
|
// single
|
|
} else {
|
|
html += '<li><span class="acf-rel-item" data-id="' + data.id + '">' + data.text + '</span></li>';
|
|
}
|
|
}
|
|
|
|
// return
|
|
return html;
|
|
};
|
|
|
|
return walk( data );
|
|
}
|
|
|
|
});
|
|
|
|
acf.registerFieldType( Field );
|
|
|
|
})(jQuery); |