forked from signalpoint/entityreference
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathentityreference.js
More file actions
395 lines (349 loc) · 14.6 KB
/
entityreference.js
File metadata and controls
395 lines (349 loc) · 14.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/**
* Implements hook_field_widget_form().
*/
function entityreference_field_widget_form(form, form_state, field, instance, langcode, items, delta, element) {
try {
// Build the widget based on the type (we only support auto complete for
// now).
switch (instance.widget.type) {
case 'entityreference_autocomplete':
case 'entityreference_autocomplete_tags':
case 'og_complex': // Adds support for the Organic Groups module.
// Set up the autocomplete.
var key_title = entity_primary_key_title(field.settings.target_type);
items[delta].type = 'autocomplete';
items[delta].delta = delta;
items[delta].remote = true;
items[delta].value = entity_primary_key(field.settings.target_type);
items[delta].label = key_title;
items[delta].filter = key_title;
items[delta].path = entityreference_autocomplete_path(field, items[delta]);
// Set any existing item values.
if (items[delta].item && items[delta].item.target_id) {
items[delta].default_value = items[delta].item.target_id;
items[delta].default_value_label = items[delta].item[key_title];
}
break;
default:
console.log('entityreference_field_widget_form - unknown widget type (' + instance.widget.type + ')');
break;
}
}
catch (error) { console.log('entityreference_field_widget_form - ' + error); }
}
/**
* Theme's an entity reference field.
*/
function theme_entityreference(variables) {
try {
// @TODO - this function name is misleading because its primarily used to
// provide the widget during node creation/editing, and not associated with
// the public display of the field, which is typically the case when using
// a theme('example', ...) call. The function name should be more of an
// extension of the field widget form function's name above.
var html = '';
var field_name = variables.field_info_field.field_name;
// We'll make the actual field hidden, and the widget will populate the
// hidden input later.
//html += '<input type="hidden" ' + drupalgap_attributes(variables.attributes) + '/>';
// We'll also add an empty div container where the widget will get rendered.
html += '<div id="' + variables.attributes.id + '_container"></div>';
// Determine the handler for the "Mode" that is set in the "Entity
// Selection" settings on this field.
var handler = variables.field_info_field.settings.handler;
switch (handler) {
// Views Entity Reference Display
case 'views':
case 'og': // Adds support for Organic Groups module.
// Since our View will need a corresponding Views JSON Display, which
// will return the same data as the Entity Reference Display that powers
// this field, we need to assume the path to retrieve the JSON data.
// We will use the machine name of the View, and use the View's Entity
// Reference Display, and prefix them with 'drupalgap/'. For example,
// If we had a view with a machine name of 'my_articles' and the machine
// name of the corresponding entity reference display on the view was
// 'entityreference_1', then the path we would retrieve the JSON data
// from in Drupal would be ?q=drupalgap/my_articles/entityreference_1
var path = entityreference_autocomplete_path(variables.field_info_field);
// Now that we've got the path to the Views JSON page display, we need
// to fetch that data and inject it into the widget on the pageshow
// event.
html += drupalgap_jqm_page_event_script_code({
page_id: drupalgap_get_page_id(),
jqm_page_event: 'pageshow',
jqm_page_event_callback: '_theme_entityreference_pageshow',
jqm_page_event_args: JSON.stringify({
id: variables.attributes.id,
path: path,
widget: variables.field_info_instance.widget,
field_name: field_name
})
});
break;
default:
console.log('WARNING: theme_entityreference - unsupported handler (' + handler + ')');
console.log('On your Drupal site, edit ' + field_name + ' and change the ' +
'"Entity Selection Mode" to Views, then follow the README for the ' +
'DrupalGap Entity Reference module to set up a View for this field.');
break;
}
return html;
}
catch (error) { console.log('theme_entityreference - ' + error); }
}
/**
*
*/
function _theme_entityreference_pageshow(options) {
try {
// We need a callback function to process this particular instance, so let's
// declare it first.
var _theme_entityreference_pageshow_success = function(entity) {
try {
// If we have an entity, it means we are editing it, so build an array
// of target ids, so we can easily reference them later.
var target_ids = [];
if (entity) {
// Handle multi lingual entities by determining the language code for
// the field.
var language = 'und';
if (typeof entity.language !== 'undefined' && entity.language != 'und') {
language = entity.language;
if (typeof entity[options.field_name][language] === 'undefined') { language = 'und'; }
}
// Skip the extraction of target ids from empty entity reference
// fields. Otherwise pull out the target ids.
if ($.isArray(entity[options.field_name]) && entity[options.field_name].length == 0) { }
else {
$.each(entity[options.field_name][language], function(delta, reference) {
target_ids.push(reference.target_id);
});
// Place the target ids onto the hidden input's value.
if (target_ids.length > 0) {
$('#' + options.id).val(target_ids.join(','));
}
}
}
// Depending on what module wants to handle this, build the widget
// accordingly.
switch (options.widget.module) {
// OPTIONS MODULE
case 'options':
views_datasource_get_view_result(options.path, {
success: function(results) {
if (results.view.count == 0) { return; }
//dpm(results);
var html = '';
// Now that we've got the results, let's render the widget.
// Check boxes/radio buttons.
if (options.widget.type == 'options_buttons') {
$.each(results[results.view.root], function(index, object) {
var referenced_entity = object[results.view.child];
var checkbox_id = options.id + '_' + referenced_entity.nid;
// Build the checkbox.
var checkbox = {
title: referenced_entity.title,
attributes: {
id: checkbox_id,
'class': options.field_name + ' entityreference',
value: referenced_entity.nid,
onclick: '_entityreference_onclick(this, \'' + options.id + '\', \'' + options.field_name + '\')'
}
};
// Check it?
if ($.inArray(referenced_entity.nid, target_ids) != -1) {
checkbox.attributes.checked = "";
}
// Build the label.
var label = { element:checkbox };
label.element.id = checkbox.attributes.id;
// Finally, theme the checkbox.
html += theme('checkbox', checkbox) + theme('form_element_label', label);
});
}
else {
console.log('WARNING: _theme_entityreference_pageshow - unsupported options widget type (' + options.widget.type + ')');
}
$('#' + options.id + '_container').html(html).trigger('create');
}
});
break;
// ENTITYREFERENCE MODULE
case 'entityreference':
case 'og': // Adds support for the Organic Groups module.
break;
default:
console.log('WARNING: _theme_entityreference_pageshow - unsupported widget module (' + options.widget.module + ')');
break;
}
}
catch (error) {
console.log('_theme_entityreference_pageshow_success - ' + error);
}
}
// If we're editing an entity, we need to load the entity object, then pass
// it along to our success handler declared earlier. If we're not editing,
// just go directly to the success handler with a null entity.
if (typeof parseInt(arg(1)) === 'number' && arg(2) == 'edit') {
entity_load(arg(0), arg(1), {
success: _theme_entityreference_pageshow_success
});
}
else { _theme_entityreference_pageshow_success(null); }
}
catch (error) { console.log('_theme_entityreference_pageshow - ' + error); }
}
/**
* Implements hook_field_formatter_view().
*/
function entityreference_field_formatter_view(entity_type, entity, field, instance, langcode, items, display) {
try {
//console.log(entity_type);
//console.log(entity);
//console.log(field);
//console.log(instance);
//console.log(display);
var element = {};
$.each(items, function(delta, item) {
//dpm(delta);
//console.log(item);
switch (display.type) {
// Label
case 'entityreference_label':
var text = item[entity_primary_key_title(item['entity_type'])];
if (display.settings.link == 1) { // Display as link.
element[delta] = {
theme: 'button_link',
text: text,
path: item['entity_type'] + '/' + item['target_id']
};
}
else { // Display as plain text.
element[delta] = { markup: '<div>' + text + '</div>' };
}
break;
// Entity id
case 'entityreference_entity_id':
element[delta] = { markup: '<div>' + item.target_id + '</div>' };
break;
// Rendered entity
case 'entityreference_entity_view':
drupalgap_entity_render_content(item.entity_type, item.entity);
element[delta] = { markup: item.entity.content };
break;
default:
console.log('entityreference_field_formatter_view - unsupported type: ' + display.type);
break;
}
});
return element;
}
catch (error) { console.log('entityreference_field_formatter_view - ' + error); }
}
/**
* Implements hook_assemble_form_state_into_field().
*/
function entityreference_assemble_form_state_into_field(entity_type, bundle,
form_state_value, field, instance, langcode, delta, field_key) {
try {
if (typeof form_state_value === 'undefined') { return null; }
var result = null;
switch (instance.widget.type) {
case 'entityreference_autocomplete':
case 'og_complex': // Adds support for the Organic Groups module.
field_key.value = 'target_id';
// @see http://drupal.stackexchange.com/a/40347/10645
if (!empty(form_state_value)) {
result = '... (' + form_state_value + ')';
}
break;
default:
// For the "check boxes / radio buttons" widget, we must pass something
// like this: field_name: { und: [123, 456] }
// @see http://drupal.stackexchange.com/q/42658/10645
result = [];
field_key.use_delta = false;
field_key.use_wrapper = false;
var ids = form_state_value.split(',');
$.each(ids, function(delta, id) { if (!empty(id)) { result.push(id); } });
break;
}
return result;
}
catch (error) { console.log('entityreference_assemble_form_state_into_field - ' + error); }
}
/**
*
*/
function _entityreference_onclick(input, input_id, field_name) {
try {
// For each checkbox that is checked for the entity reference field,
// build a comma separated string of the referenced entity ids, then place
// the string in the form element's hidden input value.
var ids = [];
var selector = '#' + drupalgap_get_page_id() + ' input.' + field_name + '.entityreference';
$(selector).each(function(index, object) {
if ($(object).is(':checked')) {
ids.push($(object).val());
}
});
var value = '';
if (ids.length != 0) { value = ids.join(','); }
$('#' + input_id).val(value);
}
catch (error) { console.log('_entityreference_onclick - ' + error); }
}
/**
*
*/
function entityreference_autocomplete_path(field) {
try {
switch (field.settings.handler) {
case 'views':
case 'og':
// We're using a view, so return the path to the Page display for the
// field.
return 'drupalgap/' +
field.settings.handler_settings.view.view_name + '/' +
field.settings.handler_settings.view.display_name;
break;
case 'base':
// If we were passed a form element item, set the autocomplete to custom
// so it uses the Index resource instead of Views JSON.
if (arguments[1]) { arguments[1].custom = true; }
// Since we're using the base handler, we'll use the Index resource for
// the entity type.
return 'drupalgap/' + field.settings.target_type + '.json';
break;
}
}
catch (error) { console.log('entityreference_autocomplete_path - ' + error); }
}
/**
* Implements hook_views_exposed_filter().
* @param {Object} form
* @param {Object} form_state
* @param {Object} element
* @param {Object} filter
* @param {Object} field
*/
function entityreference_views_exposed_filter(form, form_state, element, filter, field) {
try {
//console.log('element');
//console.log(element);
//console.log('filter');
//console.log(filter);
//console.log('field');
//console.log(field);
// Make a select list with the available value options.
element.type = 'select';
element.options = {};
for (var index in filter.value_options) {
if (!filter.value_options.hasOwnProperty(index)) { continue; }
element.options[index] = filter.value_options[index];
}
if (!empty(filter.value)) { element.value = filter.value[0]; }
return element;
}
catch (error) { console.log('entityreference_views_exposed_filter - ' + error); }
}