Last active
August 29, 2015 14:04
-
-
Save fabsor/0ad96f5b051036199300 to your computer and use it in GitHub Desktop.
Dynamic links and choosable add links for references dialog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/js/references-dialog.js b/js/references-dialog.js | |
index 0c23b31..ac88071 100644 | |
--- a/js/references-dialog.js | |
+++ b/js/references-dialog.js | |
@@ -1,52 +1,152 @@ | |
(function ($) { | |
- | |
var $window = $(window); | |
- | |
Drupal.behaviors.referencesDialog = { | |
- attach: function (context, settings) { | |
- // Add appropriate classes on all fields that should have it. This is | |
- // necessary since we don't actually know what markup we are dealing with. | |
- if (typeof settings.ReferencesDialog !== 'undefined') { | |
- $.each(settings.ReferencesDialog.fields, function (key, widget_settings) { | |
- $('.' + key + ' a.references-dialog-activate', context).click(function (e) { | |
- e.preventDefault(); | |
- Drupal.ReferencesDialog.open($(this).attr('href'), $(this).html()); | |
- Drupal.ReferencesDialog.entityIdReceived = function (entity_type, entity_id, label) { | |
- if (typeof widget_settings.format !== 'undefined') { | |
- var value = widget_settings.format | |
- .replace('$label', label) | |
- .replace('$entity_id', entity_id) | |
- .replace('$entity_type', entity_type); | |
- } | |
- // If we have a callback path, let's invoke that. | |
- if (typeof widget_settings.callback_path !== 'undefined') { | |
- var entity_info = { | |
- label: label, | |
- entity_id: entity_id, | |
- entity_type: entity_type | |
- }; | |
- Drupal.ReferencesDialog.invokeCallback(widget_settings.callback_path, entity_info, widget_settings.callback_settings); | |
- } | |
- // If we have a target, use that. | |
- else if (typeof widget_settings.target !== 'undefined') { | |
- var target = $('#' + widget_settings.target); | |
- target.val(value); | |
- target.change(); | |
+ | |
+ /** | |
+ * Manage edit links by doing access checks and adding edit links | |
+ * where appropriate. | |
+ * @param field_name the name of the field | |
+ * @param target the target jQuery element. | |
+ * @param the settings for the widget handling the field. | |
+ */ | |
+ editLinkController: function (field_name, settings) { | |
+ var _this = this; | |
+ var dialog_selector = '.dialog-links.' + field_name + ' > ul'; | |
+ return function () { | |
+ var val = $(this).val(); | |
+ var result = val.match(settings.match) | |
+ if (result && result[1]) { | |
+ var entity_id = result[1]; | |
+ var url = '$callback/$entity_type/$entity_id' | |
+ .replace('$callback', _this.settings.access_callback) | |
+ .replace('$entity_type', settings.entity_type) | |
+ .replace('$entity_id', entity_id) | |
+ $.get(url, function (data) { | |
+ if (data.access) { | |
+ // Add the edit link if it's not already outputted. | |
+ if ($(dialog_selector + ' .edit-dialog').size() === 0) { | |
+ $(dialog_selector) | |
+ .append('<li><a href="' + data.path + | |
+ '" class="edit-dialog references-dialog-activate">' + | |
+ Drupal.t('Edit') + '</a></li>'); | |
+ $(dialog_selector + ' .edit-dialog') | |
+ .click(_this.dialogController(field_name, settings)); | |
} | |
- // If we have none of the above, we just insert the value in the item | |
- // that invoked this. | |
else { | |
- var key_el = $('#' + key); | |
- key_el.val(value); | |
- key_el.change(); | |
+ $(dialog_selector + ' .edit-dialog').attr('href', data.path) | |
+ .show(); | |
} | |
} | |
- return false; | |
+ else { | |
+ $(dialog_selector + ' .edit-dialog').hide(); | |
+ } | |
}); | |
- }); | |
+ } | |
+ else { | |
+ $(dialog_selector + ' .edit-dialog').hide(); | |
+ } | |
+ }; | |
+ }, | |
+ | |
+ /** | |
+ * Get the target jQuery element. This will not work if the | |
+ * widget settings are fetched from a callback. | |
+ * @return | |
+ * The jquery element of the target, or null if the target | |
+ * is fetched with a callback. | |
+ */ | |
+ getTarget: function (field_name, settings) { | |
+ if (settings.target) { | |
+ return $('#' + widget_settings.target); | |
+ } | |
+ else if (!settings.callback_path){ | |
+ return $('#' + field_name); | |
} | |
+ }, | |
+ | |
+ /** | |
+ * Hides and shows the add links as needed. | |
+ */ | |
+ addLinkController: function (field_name) { | |
+ var dialog_selector = '.dialog-links.' + field_name + ' > ul'; | |
+ return function () { | |
+ // Hide the add dialog. | |
+ var val = $(this).val(); | |
+ if (val && val.length > 0) { | |
+ $(dialog_selector + ' .add-dialog').hide(); | |
+ } | |
+ else { | |
+ $(dialog_selector + ' .add-dialog').show(); | |
+ } | |
+ }; | |
+ }, | |
+ | |
+ /** | |
+ * Manage opening and return values from dialogs. | |
+ * @param field_name the name of the field | |
+ * param settings settings for the widget. | |
+ * @return a function that can be used in an event. | |
+ */ | |
+ dialogController: function (field_name, settings) { | |
+ var _this = this; | |
+ return function (e) { | |
+ e.preventDefault(); | |
+ Drupal.ReferencesDialog.open($(this).attr('href'), $(this).html()); | |
+ Drupal.ReferencesDialog.entityIdReceived = function (entity_type, entity_id, label) { | |
+ if (settings.format) { | |
+ var value = settings.format | |
+ .replace('$label', label) | |
+ .replace('$entity_id', entity_id) | |
+ .replace('$entity_type', entity_type); | |
+ } | |
+ var target = _this.getTarget(field_name, settings); | |
+ if (target) { | |
+ target.val(value); | |
+ target.change(); | |
+ } | |
+ // We can't get the target in the cases where | |
+ // we have a custom callback. | |
+ else { | |
+ var entity_info = { | |
+ label: label, | |
+ entity_id: entity_id, | |
+ entity_type: entity_type | |
+ }; | |
+ Drupal.ReferencesDialog | |
+ .invokeCallback(settings.callback_path, entity_info, | |
+ settings.callback_settings); | |
+ } | |
+ } | |
+ return false; | |
+ }; | |
+ }, | |
+ attach: function (context, settings) { | |
+ if (typeof settings.ReferencesDialog === 'undefined') { | |
+ return; | |
+ } | |
+ var _this = this; | |
+ this.settings = settings.ReferencesDialog; | |
+ this.context = context; | |
+ // Add appropriate classes on all fields that should have it. This is | |
+ // necessary since we don't actually know what markup we are dealing with. | |
+ $.each(this.settings.fields, function (key, widget_settings) { | |
+ var target = _this.getTarget(key, widget_settings); | |
+ // We can insert an edit link automatically if the widget provider | |
+ // supplied us with a match regexp and an entity type. | |
+ if (target && widget_settings.editable && widget_settings.match | |
+ && widget_settings.entity_type) { | |
+ var editController = _this.editLinkController(key, widget_settings); | |
+ var addController = _this.addLinkController(key); | |
+ addController.bind(target)(key); | |
+ target.change(addController); | |
+ target.blur(addController); | |
+ target.change(editController); | |
+ target.blur(editController); | |
+ } | |
+ // Attach a dialog controller to our links. | |
+ $('.' + key + ' a.references-dialog-activate', context).click(_this.dialogController(key, widget_settings)); | |
+ }); | |
} | |
- }; | |
+ } | |
/** | |
* Our dialog object. Can be used to open a dialog to anywhere. | |
diff --git a/references_dialog.api.php b/references_dialog.api.php | |
index 73835c6..60a451d 100644 | |
--- a/references_dialog.api.php | |
+++ b/references_dialog.api.php | |
@@ -17,6 +17,9 @@ | |
* An array keyed by the widget you want to attach links to. This array | |
* should contain the following keys: | |
* - 'element_type': The type of FAPI element the widget is. | |
+ * - 'entity_type': The type of entity that is being created by this widget. | |
+ * - 'type_callback': Specify a callback if the entity may vary. | |
+ * - 'match': A regular expreession that matches the id from a textarea. | |
* - 'format': The format in which the data should be inserted as a value | |
* into the form element. The following patterns are provided, $label, $entity_id and $entity_type. | |
* - operations: An array of available operations. | |
diff --git a/references_dialog.dialog_widgets.inc b/references_dialog.dialog_widgets.inc | |
index 02efc48..150aa34 100644 | |
--- a/references_dialog.dialog_widgets.inc | |
+++ b/references_dialog.dialog_widgets.inc | |
@@ -15,6 +15,7 @@ function references_dialog_references_dialog_widgets() { | |
'dialog_form' => 'node_reference_dialog_form', | |
'entity_type' => 'node', | |
'format' => '$label [nid: $entity_id]', | |
+ 'match' => 'nid:\s?([1-9][0-9]*)', | |
'views_query' => 'references_dialog_node_reference_views_query', | |
'operations' => array( | |
'search' => array( | |
@@ -27,6 +28,7 @@ function references_dialog_references_dialog_widgets() { | |
), | |
'add' => array( | |
'function' => 'references_dialog_node_reference_add_link', | |
+ 'settings_form' => 'references_dialog_node_reference_settings', | |
'title' => t('Add dialog'), | |
), | |
), | |
@@ -35,6 +37,7 @@ function references_dialog_references_dialog_widgets() { | |
'element_type' => 'textfield', | |
'entity_type' => 'user', | |
'format' => '$label [uid: $entity_id]', | |
+ 'match' => 'uid:\s?([1-9][0-9]*)', | |
'operations' => array( | |
'search' => array( | |
'function' => 'references_dialog_get_field_search_links', | |
@@ -56,6 +59,7 @@ function references_dialog_references_dialog_widgets() { | |
'views_query' => 'references_dialog_entityreference_views_query', | |
'type_callback' => 'references_dialog_entityreference_get_type', | |
'format' => '$label ($entity_id)', | |
+ 'match' => '\(([1-9][0-9]*)\)', | |
'operations' => array( | |
'edit' => array( | |
'function' => 'references_dialog_entityreference_edit_link', | |
@@ -95,6 +99,29 @@ function references_dialog_references_dialog_widgets() { | |
); | |
} | |
+function references_dialog_node_reference_settings($form, $operation_settings, $widget, $field, $instance) { | |
+ $types = array(); | |
+ foreach ($field['settings']['referenceable_types'] as $type => $enabled) { | |
+ if (!empty($enabled)) { | |
+ $types[$type] = $enabled; | |
+ } | |
+ } | |
+ $form['types'] = array( | |
+ '#title' => t('Show links for:'), | |
+ '#type' => 'checkboxes', | |
+ '#options' => $types, | |
+ '#default_value' => !empty($operation_settings['links']) ? $operation_settings['links'] : array(), | |
+ '#states' => array( | |
+ 'visible' => array( | |
+ 'input[name="instance[widget][settings][references_dialog_add][enabled]"]' => array('checked' => TRUE), | |
+ ), | |
+ ), | |
+ ); | |
+ return $form; | |
+} | |
+ | |
+ | |
+ | |
/** | |
* Edit link callback for node references. | |
*/ | |
@@ -127,14 +154,15 @@ function references_dialog_node_reference_edit_link($element, $widget_settings, | |
/** | |
* Add link callback for node references. | |
*/ | |
-function references_dialog_node_reference_add_link($element, $widget_settings, $field, $instance) { | |
- // Hide add link for non-empty default value. | |
- if (!empty($element['#default_value']) || !empty($element['#value'])) { | |
- return array(); | |
- } | |
- | |
+function references_dialog_node_reference_add_link($element, $widget_settings, $field, $instance, $operation_settings) { | |
$add_links = array(); | |
- foreach ($field['settings']['referenceable_types'] as $type => $active) { | |
+ if (isset($operation_settings['types'])) { | |
+ $types = $operation_settings['types']; | |
+ } | |
+ else { | |
+ $types = $field['settings']['referenceable_types']; | |
+ } | |
+ foreach ($types as $type => $active) { | |
if ($active !== 0) { | |
$node_type = node_type_load($type); | |
if (node_access('create', $node_type->type)) { | |
@@ -197,11 +225,6 @@ function references_dialog_user_reference_edit_link($element, $widget_settings, | |
* Add link callback for user references. | |
*/ | |
function references_dialog_user_reference_add_link($element, $widget_settings, $field, $instance) { | |
- // Hide add link for non-empty default value. | |
- if (!empty($element['#default_value']) || !empty($element['#value'])) { | |
- return array(); | |
- } | |
- | |
$user_links = array(); | |
// Check permissions for adding users. | |
if (user_access('administer users')) { | |
@@ -243,11 +266,6 @@ function references_dialog_entityreference_edit_link($element, $widget_settings, | |
* Add link callback for entity references. | |
*/ | |
function references_dialog_entityreference_add_link($element, $widget_settings, $field, $instance) { | |
- // Hide add link for non-empty default value. | |
- if (!empty($element['#default_value']) || !empty($element['#value'])) { | |
- return array(); | |
- } | |
- | |
$add_links = array(); | |
$entity_type = $field['settings']['target_type']; | |
$entity_info = entity_get_info($entity_type); | |
diff --git a/references_dialog.module b/references_dialog.module | |
index 26b203e..ffb9734 100644 | |
--- a/references_dialog.module | |
+++ b/references_dialog.module | |
@@ -22,7 +22,17 @@ function references_dialog_element_info() { | |
*/ | |
function references_dialog_attached() { | |
return array( | |
- 'js' => array(drupal_get_path('module', 'references_dialog') . '/js/references-dialog.js'), | |
+ 'js' => array( | |
+ drupal_get_path('module', 'references_dialog') . '/js/references-dialog.js', | |
+ array( | |
+ 'data' => array( | |
+ 'ReferencesDialog' => array( | |
+ 'access_callback' => url('references-dialog/access'), | |
+ ), | |
+ ), | |
+ 'type' => 'setting', | |
+ ), | |
+ ), | |
'css' => array(drupal_get_path('module', 'references_dialog') . '/css/references-dialog-admin.css'), | |
'library' => array(array('system', 'ui.dialog')), | |
); | |
@@ -56,9 +66,25 @@ function references_dialog_menu() { | |
'access callback' => 'references_dialog_redirect_access', | |
'access arguments' => array(2, 3), | |
); | |
+ // Determine if we have access to create or update entities | |
+ // of a particular type. | |
+ $items['references-dialog/access/%/%'] = array( | |
+ 'page callback' => 'references_dialog_entity_access', | |
+ 'page arguments' => array(2,3), | |
+ 'access callback' => TRUE, | |
+ ); | |
return $items; | |
} | |
+function references_dialog_entity_access($entity_type, $entity) { | |
+ $entity = entity_load_single($entity_type, $entity); | |
+ return drupal_json_output(array( | |
+ 'access' => !empty($entity) && entity_access('update', $entity_type, $entity), | |
+ 'path' => url(references_dialog_get_admin_path($entity_type, 'edit', NULL, $entity)), | |
+ ) | |
+ ); | |
+} | |
+ | |
/** | |
* Implements hook_admin_paths(). | |
*/ | |
@@ -136,8 +162,14 @@ function references_dialog_get_applicable_views() { | |
function references_dialog_field_widget_info_alter(array &$info) { | |
foreach (references_dialog_widgets() as $widget_name => $widget_info) { | |
if (isset($info[$widget_name]['settings'])) { | |
- foreach (array_keys($widget_info['operations']) as $operation) { | |
- $info[$widget_name]['settings']['references_dialog_' . $operation] = 0; | |
+ foreach ($widget_info['operations'] as $operation => $operation_settings) { | |
+ $info[$widget_name]['settings']['references_dialog_' . $operation] = array( | |
+ 'enabled' => FALSE, | |
+ ); | |
+ // Add any default settings provided by the operation. | |
+ if (!empty($operation_settings['settings'])) { | |
+ $info[$widget_name]['settings']['references_dialog_' . $operation] + $operation_settings['settings']; | |
+ } | |
// Add search view setting if we have search. | |
if ($operation == 'search') { | |
$info[$widget_name]['settings']['references_dialog_search_view'] = ''; | |
@@ -270,15 +302,25 @@ function references_dialog_settings_form($field, $instance) { | |
$dialog_widget = references_dialog_widget_load($widget['type']); | |
// Add our own additions. | |
foreach ($dialog_widget['operations'] as $operation => $dialog_settings) { | |
- $form['references_dialog_' . $operation] = array( | |
+ $form['references_dialog_' . $operation] = array('#tree' => TRUE); | |
+ $form['references_dialog_' . $operation]['enabled'] = array( | |
'#type' => 'checkbox', | |
'#title' => check_plain($dialog_settings['title']), | |
- '#default_value' => isset($settings['references_dialog_' . $operation]) ? $settings['references_dialog_' . $operation] : FALSE, | |
+ '#default_value' => _references_dialog_operation_enabled($operation, $settings), | |
); | |
} | |
+ if (!empty($dialog_settings['settings_form']) && function_exists($dialog_settings['settings_form'])) { | |
+ $form['references_dialog_' . $operation] = $dialog_settings['settings_form']($form['references_dialog_' . $operation], $settings['references_dialog_' . $operation], $dialog_widget, $field, $instance); | |
+ } | |
return $form; | |
} | |
+function _references_dialog_operation_enabled($operation, $settings) { | |
+ return isset($settings['references_dialog_' . $operation]) && | |
+ (is_array($settings['references_dialog_' . $operation]) && $settings['references_dialog_' . $operation]['enabled'] || | |
+ (!is_array($settings['references_dialog_' . $operation]) && $settings['references_dialog_' . $operation])); | |
+} | |
+ | |
/** | |
* Menu access checker for references_dialog | |
*/ | |
@@ -308,21 +350,35 @@ function references_dialog_process_widget(&$element) { | |
// Attach javascript and CSS needed. | |
$attached = references_dialog_attached(); | |
$element['#attached']['js'][] = $attached['js'][0]; | |
- $element['#attached']['js'][] = references_dialog_js_settings($element['#id'], array('format' => $dialog_widget['format'])); | |
+ $element['#attached']['js'][] = $attached['js'][1]; | |
+ | |
+ $js_settings = array( | |
+ 'format' => $dialog_widget['format'], | |
+ 'match' => !empty($dialog_widget['match']) ? $dialog_widget['match'] : NULL, | |
+ ); | |
+ if (isset($dialog_widget['entity_type'])) { | |
+ $js_settings['entity_type'] = $dialog_widget['entity_type']; | |
+ } | |
+ elseif (isset($dialog_widget['type_callback'])) { | |
+ $js_settings['entity_type'] = $dialog_widget['type_callback']($instance, $field); | |
+ } | |
$element['#attached']['css'][] = $attached['css'][0]; | |
$element['#attached']['library'][] = $attached['library'][0]; | |
- | |
$link_options = array('attributes' => array('class' => array('references-dialog-activate'))); | |
$dialog_links = array(); | |
foreach ($dialog_widget['operations'] as $operation => $settings) { | |
- if (isset($widget_settings['references_dialog_' . $operation]) && $widget_settings['references_dialog_' . $operation]) { | |
- $links = $settings['function']($element, $widget_settings, $field, $instance); | |
+ if (_references_dialog_operation_enabled($operation, $widget_settings)) { | |
+ if ($operation == 'edit') { | |
+ $js_settings['editable'] = TRUE; | |
+ } | |
+ $links = $settings['function']($element, $widget_settings, $field, $instance, $widget_settings['references_dialog_' . $operation]); | |
foreach ($links as $link) { | |
$link['attributes']['class'][] = $operation . '-dialog'; | |
$dialog_links[] = references_dialog_link($link); | |
} | |
} | |
} | |
+ $element['#attached']['js'][] = references_dialog_js_settings($element['#id'], $js_settings); | |
if (count($dialog_links)) { | |
// We add a div directly into the markup here since we really need it in order | |
// to make sure the javascript works. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment