Skip to content

Instantly share code, notes, and snippets.

@jasonbahl
Last active May 22, 2020 21:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonbahl/f416856945bb98bae512 to your computer and use it in GitHub Desktop.
Save jasonbahl/f416856945bb98bae512 to your computer and use it in GitHub Desktop.
ACF Widget Relationship Field - Input.js - ACF PRO Support for version 5.1.1+
(function ($) {
acf.fields.widget_relationship = acf.field.extend({
type: 'widget_field',
$el: null,
$input: null,
$filters: null,
$choices: null,
$values: null,
actions: {
'ready': 'initialize',
'append': 'initialize'
},
events: {
'keypress [data-filter]': 'submit_filter',
'change [data-filter]': 'change_filter',
'keyup [data-filter]': 'change_filter',
'click .choices .acf-rel-item': 'add_item',
'click [data-name="remove_item"]': 'remove_item'
},
focus: function(){
this.$el = this.$field.find('.acf-relationship');
this.$input = this.$el.find('.acf-hidden input');
this.$choices = this.$el.find('.choices'),
this.$values = this.$el.find('.values');
this.settings = acf.get_data( this.$el );
},
initialize: function(){
// reference
var self = this,
$field = this.$field,
$el = this.$el,
$input = this.$input;
// right sortable
this.$values.children('.list').sortable({
items: 'li',
forceHelperSize: true,
forcePlaceholderSize: true,
scroll: true,
update: function(){
$input.trigger('change');
}
});
this.$choices.children('.list').scrollTop(0).on('scroll', function(e){
// bail early if no more results
if( $el.hasClass('is-loading') || $el.hasClass('is-empty') ) {
return;
}
// Scrolled to bottom
if( $(this).scrollTop() + $(this).innerHeight() >= $(this).get(0).scrollHeight ) {
var paged = parseInt( $el.attr('data-paged') );
// update paged
$el.attr('data-paged', (paged + 1) );
// fetch
self.doFocus($field);
self.fetch();
}
});
// Fetch the Results
this.fetch();
},
fetch: function(){
var self = this,
$field = this.$field;
//console.log( 'Widget' );
//console.log( this );
this.$el.addClass('is-loading');
// vars
var data = acf.prepare_for_ajax({
action : 'acf/fields/widget_field/query',
field_key : acf.get_field_key( $field ),
nonce : acf.get('nonce'),
post_id : acf.get('post_id'),
});
// merge in wrap data
$.extend(data, acf.get_data( this.$el ));
// clear html if is new query
if( data.paged == 1 ) {
this.$choices.children('.list').html('')
}
// add message
this.$choices.children('.list').append('<p>' + acf._e('relationship', 'loading') + '...</p>');
// abort XHR if this field is already loading AJAX data
if( this.$el.data('xhr') ) {
this.$el.data('xhr').abort();
}
// get results
var xhr = $.ajax({
url : acf.get('ajaxurl'),
dataType : 'json',
type : 'get',
cache : true,
data : data,
success : function( json ){
// console.log( json );
self.doFocus($field);
self.render(json);
}
});
// update el data
this.$el.data('xhr', xhr);
},
render: function( json ) {
// remove loading class
this.$el.removeClass('is-loading is-empty');
// remove p tag
this.$choices.children('.list').children('p').remove();
// no results?
if( !json || !json.length ) {
// add class
this.$el.addClass('is-empty');
// add message
if( this.settings.paged == 1 ) {
this.$choices.children('.list').append('<p>' + acf._e('relationship', 'empty') + '</p>');
}
// return
return;
}
// get new results
var $new = $( this.walker(json) );
// apply .disabled to left li's
this.$values.find('.acf-rel-item').each(function(){
var id = $(this).attr('data-id');
$new.find('.acf-rel-item[data-id="' + id + '"]').addClass('disabled');
});
// underline search match
if( this.settings.s ) {
var s = this.settings.s;
$new.find('.acf-rel-item').each(function(){
// vars
var find = $(this).text(),
replace = find.replace( new RegExp('(' + s + ')', 'gi'), '<b>$1</b>');
$(this).html( $(this).html().replace(find, replace) );
});
}
// append
this.$choices.children('.list').append( $new );
// merge together groups
var label = '',
$list = null;
this.$choices.find('.acf-rel-label').each(function(){
if( $(this).text() == label ) {
$list.append( $(this).siblings('ul').html() );
$(this).parent().remove();
return;
}
// update vars
label = $(this).text();
$list = $(this).siblings('ul');
});
},
walker: function( data ){
// vars
var s = '';
// loop through data
if( $.isArray(data) ) {
for( var k in data ) {
s += this.walker( data[ k ] );
}
} else if( $.isPlainObject(data) ) {
// optgroup
if( data.children !== undefined ) {
s += '<li><span class="acf-rel-label">' + data.text + '</span><ul class="acf-bl">';
s += this.walker( data.children );
s += '</ul></li>';
} else {
s += '<li><span class="acf-rel-item" data-id="' + data.id + '">' + data.text + '</span></li>';
}
}
// return
return s;
},
submit_filter: function( e ){
// don't submit form
if( e.which == 13 ) {
e.preventDefault();
}
},
change_filter: function( e ){
// vars
var val = e.$el.val(),
filter = e.$el.attr('data-filter');
// Bail early if filter has not changed
if( this.$el.attr('data-' + filter) == val ) {
return;
}
// update attr
this.$el.attr('data-' + filter, val);
// reset paged
this.$el.attr('data-paged', 1);
// fetch
this.fetch();
},
add_item: function( e ){
// max posts
if( this.settings.max > 0 ) {
if( this.$values.find('.acf-rel-item').length >= this.settings.max ) {
alert( acf._e('relationship', 'max').replace('{max}', this.settings.max) );
return;
}
}
// can be added?
if( e.$el.hasClass('disabled') ) {
return false;
}
// disable
e.$el.addClass('disabled');
// template
var html = [
'<li>',
'<input type="hidden" name="' + this.$input.attr('name') + '[]" value="' + e.$el.attr('data-id') + '" />',
'<span data-id="' + e.$el.attr('data-id') + '" class="acf-rel-item">' + e.$el.html(),
'<a href="#" class="acf-icon small dark" data-name="remove_item"><i class="acf-sprite-remove"></i></a>',
'</span>',
'</li>'].join('');
// add new li
this.$values.children('.list').append( html )
// trigger change on new_li
this.$input.trigger('change');
// validation
acf.validation.remove_error( this.$field );
},
remove_item : function( e ){
// vars
var $span = e.$el.parent(),
id = $span.attr('data-id');
// remove
$span.parent('li').remove();
// show
this.$choices.find('.acf-rel-item[data-id="' + id + '"]').removeClass('disabled');
// trigger change on new_li
this.$input.trigger('change');
}
});
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment