Newer
Older
Alex Barth
committed
Alex Barth
committed
* Contains all page callbacks, forms and theming functions for Feeds
* administrative pages.
twistor
committed
* Introductory help for admin/structure/feeds/%feeds_importer page
Alex Barth
committed
function feeds_ui_edit_help() {
return t('
<p>
You can create as many Feeds importer configurations as you would like to. Each can have a distinct purpose like letting your users aggregate RSS feeds or importing a CSV file for content migration. Here are a couple of things that are important to understand in order to get started with Feeds:
</p>
<ul>
<li>
Every importer configuration consists of basic settings, a fetcher, a parser and a processor and their settings.
</li>
<li>
The <strong>basic settings</strong> define the general behavior of the importer. <strong>Fetchers</strong> are responsible for loading data, <strong>parsers</strong> for organizing it and <strong>processors</strong> for "doing stuff" with it, usually storing it.
</li>
<li>
In Basic settings, you can <strong>attach an importer configuration to a content type</strong>. This is useful when many imports of a kind should be created, for example in an RSS aggregation scenario. If you don\'t attach a configuration to a content type, you can use it on the !import page.
</li>
<li>
Imports can be <strong>scheduled periodically</strong> - see the periodic import select box in the Basic settings.
Alex Barth
committed
</li>
<li>
Processors can have <strong>mappings</strong> in addition to settings. Mappings allow you to define what elements of a data feed should be mapped to what content fields on a granular level. For instance, you can specify that a feed item\'s author should be mapped to a node\'s body.
Alex Barth
committed
</li>
</ul>
', array('!import' => l(t('Import'), 'import')));
}
/**
* Help text for mapping.
*/
function feeds_ui_mapping_help() {
return t('
<p>
Define which elements of a single item of a feed (= <em>Sources</em>) map to which content pieces in Drupal (= <em>Targets</em>). Make sure that at least one definition has a <em>Unique target</em>. A unique target means that a value for a target can only occur once. E. g. only one item with the URL <em>http://example.com/content/1</em> can exist.
Alex Barth
committed
</p>
');
/**
* Build overview of available configurations.
*/
joelpittet
committed
function feeds_ui_overview_form($form, array &$form_state) {
$form = $form['enabled'] = $form['disabled'] = array();
$form['#header'] = array(
t('Name'),
t('Description'),
t('Attached to'),
t('Status'),
t('Operations'),
t('Enabled'),
);
foreach (feeds_importer_load_all(TRUE) as $importer) {
$importer_form['name']['#markup'] = check_plain($importer->config['name']);
$importer_form['description']['#markup'] = check_plain($importer->config['description']);
Alex Barth
committed
if (empty($importer->config['content_type'])) {
Alex Barth
committed
else {
$importer_form['attached']['#markup'] = l(node_type_get_name($importer->config['content_type']), 'node/add/' . str_replace('_', '-', $importer->config['content_type']));
$importer_form['attached']['#markup'] = check_plain(node_type_get_name($importer->config['content_type']));
Alex Barth
committed
}
Alex Barth
committed
if ($importer->export_type == EXPORT_IN_CODE) {
$status = t('Default');
$edit = t('Override');
$delete = '';
}
elseif ($importer->export_type == EXPORT_IN_DATABASE) {
Alex Barth
committed
$status = t('Normal');
$edit = t('Edit');
$delete = t('Delete');
}
elseif ($importer->export_type == (EXPORT_IN_CODE | EXPORT_IN_DATABASE)) {
Alex Barth
committed
$status = t('Overridden');
$edit = t('Edit');
$delete = t('Revert');
}
Alex Barth
committed
);
Chris Leppanen
committed
$importer_form['operations'] = array(
'#markup' =>
l($edit, 'admin/structure/feeds/' . $importer->id) . ' | ' .
l(t('Export'), 'admin/structure/feeds/' . $importer->id . '/export') . ' | ' .
l(t('Clone'), 'admin/structure/feeds/' . $importer->id . '/clone') .
(empty($delete) ? '' : ' | ' . l($delete, 'admin/structure/feeds/' . $importer->id . '/delete')),
);
$importer_form[$importer->id] = array(
'#type' => 'checkbox',
'#default_value' => !$importer->disabled,
);
if ($importer->disabled) {
$form['disabled'][$importer->id] = $importer_form;
}
else {
$form['enabled'][$importer->id] = $importer_form;
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
return $form;
}
/**
* Submit handler for feeds_ui_overview_form().
*/
function feeds_ui_overview_form_submit($form, &$form_state) {
$disabled = array();
foreach (feeds_importer_load_all(TRUE) as $importer) {
$disabled[$importer->id] = !$form_state['values'][$importer->id];
}
variable_set('default_feeds_importer', $disabled);
feeds_cache_clear();
}
/**
* Create a new configuration.
Alex Barth
committed
*
* @param $form_state
* Form API form state array.
* @param $from_importer
* FeedsImporter object. If given, form will create a new importer as a copy
* of $from_importer.
function feeds_ui_create_form($form, &$form_state, $from_importer = NULL) {
Alex Barth
committed
$form['#from_importer'] = $from_importer;
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
'#description' => t('A natural name for this configuration. Example: RSS Feed. You can always change this name later.'),
'#required' => TRUE,
Alex Barth
committed
'#maxlength' => 128,
'#type' => 'machine_name',
Alex Barth
committed
'#maxlength' => 128,
'#machine_name' => array(
'exists' => 'feeds_ui_importer_machine_name_exists',
),
Alex Barth
committed
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#description' => t('A description of this configuration.'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Create'),
);
return $form;
}
/**
* Validation callback for the importer machine name field.
*/
function feeds_ui_importer_machine_name_exists($id) {
if ($id == 'create') {
// Create is a reserved path for the add importer form.
return TRUE;
}
ctools_include('export');
if (ctools_export_load_object('feeds_importer', 'conditions', array('id' => $id))) {
return TRUE;
}
}
Alex Barth
committed
/**
* Validation handler for feeds_build_create_form().
*/
Alex Barth
committed
function feeds_ui_create_form_validate($form, &$form_state) {
Dave Reid
committed
if (!empty($form_state['values']['id'])) {
$importer = feeds_importer($form_state['values']['id']);
$importer->configFormValidate($form_state['values']);
}
Alex Barth
committed
}
/**
* Submit handler for feeds_build_create_form().
*/
Alex Barth
committed
function feeds_ui_create_form_submit($form, &$form_state) {
// Create feed.
$importer = feeds_importer($form_state['values']['id']);
// If from_importer is given, copy its configuration.
if (!empty($form['#from_importer'])) {
$importer->copy($form['#from_importer']);
}
// In any case, we want to set this configuration's title and description.
$importer->addConfig($form_state['values']);
$importer->save();
// Set a message and redirect to settings form.
if (empty($form['#from_importer'])) {
drupal_set_message(t('Your configuration has been created with default settings. If they do not fit your use case you can adjust them here.'));
}
else {
drupal_set_message(t('A clone of the @name configuration has been created.', array('@name' => $form['#from_importer']->config['name'])));
Alex Barth
committed
}
twistor
committed
$form_state['redirect'] = 'admin/structure/feeds/' . $importer->id;
feeds_cache_clear();
Alex Barth
committed
* Delete configuration form.
function feeds_ui_delete_form($form, &$form_state, $importer) {
$form['#importer'] = $importer->id;
if ($importer->export_type & EXPORT_IN_CODE) {
$title = t('Would you really like to revert the importer @importer?', array('@importer' => $importer->config['name']));
$button_label = t('Revert');
}
else {
$title = t('Would you really like to delete the importer @importer?', array('@importer' => $importer->config['name']));
$button_label = t('Delete');
}
return confirm_form(
$form,
$title,
'admin/structure/feeds',
t('This action cannot be undone.'),
$button_label
);
Alex Barth
committed
/**
Alex Barth
committed
* Submit handler for feeds_ui_delete_form().
Alex Barth
committed
*/
Alex Barth
committed
function feeds_ui_delete_form_submit($form, &$form_state) {
$form_state['redirect'] = 'admin/structure/feeds';
Alex Barth
committed
// Remove importer.
feeds_importer($form['#importer'])->delete();
Alex Barth
committed
// Clear cache, deleting a configuration may have an affect on menu tree.
feeds_cache_clear();
Alex Barth
committed
}
Alex Barth
committed
* Export a feed configuration.
function feeds_ui_export_form($form, &$form_state, $importer) {
Alex Barth
committed
$code = feeds_export($importer->id);
$form['export'] = array(
'#title' => t('Export feed configuration'),
'#type' => 'textarea',
'#value' => $code,
'#rows' => substr_count($code, "\n"),
);
return $form;
Alex Barth
committed
/**
* Edit feed configuration.
*/
Chris Leppanen
committed
function feeds_ui_edit_page(FeedsImporter $importer, $active = 'help', $plugin_key = '') {
Alex Barth
committed
// Get plugins and configuration.
Alex Barth
committed
$plugins = FeedsPlugin::all();
Chris Leppanen
committed
Alex Barth
committed
$config = $importer->config;
// Base path for changing the active container.
twistor
committed
$path = 'admin/structure/feeds/' . $importer->id;
Alex Barth
committed
$active_container = array(
'class' => array('active-container'),
Alex Barth
committed
'actions' => array(l(t('Help'), $path)),
);
switch ($active) {
case 'help':
$active_container['title'] = t('Getting started');
$active_container['body'] = '<div class="help feeds-admin-ui">' . feeds_ui_edit_help() . '</div>';
Alex Barth
committed
unset($active_container['actions']);
break;
Chris Leppanen
committed
Alex Barth
committed
case 'fetcher':
case 'parser':
case 'processor':
$active_container['title'] = t('Select a !plugin_type', array('!plugin_type' => $active));
$active_container['body'] = drupal_get_form('feeds_ui_plugin_form', $importer, $active);
break;
Chris Leppanen
committed
Alex Barth
committed
case 'settings':
drupal_add_js(drupal_get_path('module', 'ctools') . '/js/dependent.js');
Alex Barth
committed
if (empty($plugin_key)) {
$active_container['title'] = t('Basic settings');
$active_container['body'] = feeds_get_form($importer, 'configForm');
Alex Barth
committed
}
Alex Barth
committed
// feeds_plugin() returns a correct result because feed has been
Alex Barth
committed
// instantiated previously.
Alex Barth
committed
elseif (in_array($plugin_key, array_keys($plugins)) && $plugin = feeds_plugin($plugin_key, $importer->id)) {
Alex Barth
committed
$active_container['title'] = t('Settings for !plugin', array('!plugin' => $plugins[$plugin_key]['name']));
$active_container['body'] = feeds_get_form($plugin, 'configForm');
Alex Barth
committed
}
break;
Chris Leppanen
committed
Alex Barth
committed
case 'mapping':
$processor_name = isset($plugins[$config['processor']['plugin_key']]['name']) ? $plugins[$config['processor']['plugin_key']]['name'] : $plugins['FeedsMissingPlugin']['name'];
$active_container['title'] = t('Mapping for @processor', array('@processor' => $processor_name));
Alex Barth
committed
$active_container['body'] = drupal_get_form('feeds_ui_mapping_form', $importer);
break;
}
// Build config info.
$config_info = $info = array();
$info['class'] = array('config-set');
Alex Barth
committed
// Basic information.
$items = array();
$items[] = t('Attached to: @type', array('@type' => $importer->config['content_type'] ? node_type_get_name($importer->config['content_type']) : t('[none]')));
Alex Barth
committed
if ($importer->config['import_period'] == FEEDS_SCHEDULE_NEVER) {
Alex Barth
committed
}
elseif ($importer->config['import_period'] == 0) {
$import_period = t('as often as possible');
}
else {
$import_period = t('every !interval', array('!interval' => format_interval($importer->config['import_period'])));
}
$items[] = t('Periodic import: !import_period', array('!import_period' => $import_period));
$items[] = $importer->config['import_on_create'] ? t('Import on submission') : t('Do not import on submission');
Alex Barth
committed
$info['title'] = t('Basic settings');
$info['body'] = array(
array(
'body' => theme('item_list', array('items' => $items)),
'actions' => array(l(t('Settings'), $path . '/settings')),
Alex Barth
committed
),
);
$config_info[] = $info;
// Fetcher.
$fetcher = isset($plugins[$config['fetcher']['plugin_key']]) ? $plugins[$config['fetcher']['plugin_key']] : $plugins['FeedsMissingPlugin'];
Alex Barth
committed
$actions = array();
if ($importer->fetcher->hasConfigForm()) {
$actions = array(l(t('Settings'), $path . '/settings/' . $config['fetcher']['plugin_key']));
Alex Barth
committed
}
$info['title'] = t('Fetcher');
$info['body'] = array(
array(
'title' => $fetcher['name'],
'body' => $fetcher['description'],
'actions' => $actions,
),
);
$info['actions'] = array(l(t('Change'), $path . '/fetcher'));
Alex Barth
committed
$config_info[] = $info;
// Parser.
$parser = isset($plugins[$config['parser']['plugin_key']]) ? $plugins[$config['parser']['plugin_key']] : $plugins['FeedsMissingPlugin'];
Alex Barth
committed
$actions = array();
if ($importer->parser->hasConfigForm()) {
$actions = array(l(t('Settings'), $path . '/settings/' . $config['parser']['plugin_key']));
Alex Barth
committed
}
$info['title'] = t('Parser');
$info['body'] = array(
array(
'title' => $parser['name'],
'body' => $parser['description'],
'actions' => $actions,
)
);
$info['actions'] = array(l(t('Change'), $path . '/parser'));
Alex Barth
committed
$config_info[] = $info;
// Processor.
$processor = isset($plugins[$config['processor']['plugin_key']]) ? $plugins[$config['processor']['plugin_key']] : $plugins['FeedsMissingPlugin'];
Alex Barth
committed
$actions = array();
if ($importer->processor->hasConfigForm()) {
$actions[] = l(t('Settings'), $path . '/settings/' . $config['processor']['plugin_key']);
Alex Barth
committed
}
$actions[] = l(t('Mapping'), $path . '/mapping');
Alex Barth
committed
$info['title'] = t('Processor');
$info['body'] = array(
array(
'title' => $processor['name'],
'body' => $processor['description'],
'actions' => $actions,
)
);
$info['actions'] = array(l(t('Change'), $path . '/processor'));
Alex Barth
committed
$config_info[] = $info;
return theme('feeds_ui_edit_page', array(
'info' => $config_info,
'active' => $active_container,
));
Alex Barth
committed
}
Alex Barth
committed
* Build a form of plugins to pick from.
*
* @param $form_state
* Form API form state array.
* @param $importer
* FeedsImporter object.
* @param $type
* Plugin type. One of 'fetcher', 'parser', 'processor'.
*
* @return
* A Form API form definition.
function feeds_ui_plugin_form($form, &$form_state, $importer, $type) {
Alex Barth
committed
$plugins = FeedsPlugin::byType($type);
Alex Barth
committed
$form['#importer'] = $importer->id;
Alex Barth
committed
$form['#plugin_type'] = $type;
$importer_key = $importer->config[$type]['plugin_key'];
Alex Barth
committed
foreach ($plugins as $key => $plugin) {
Alex Barth
committed
$form['plugin_key'][$key] = array(
'#type' => 'radio',
'#parents' => array('plugin_key'),
'#title' => check_plain($plugin['name']),
'#description' => filter_xss(isset($plugin['help']) ? $plugin['help'] : $plugin['description']),
Alex Barth
committed
'#return_value' => $key,
'#default_value' => ($key == $importer_key) ? $key : '',
Alex Barth
committed
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
Alex Barth
committed
* Submit handler for feeds_ui_plugin_form().
Alex Barth
committed
function feeds_ui_plugin_form_submit($form, &$form_state) {
// Set the plugin and save feed.
$importer = feeds_importer($form['#importer']);
$importer->setPlugin($form_state['values']['plugin_key']);
$importer->save();
drupal_set_message(t('Changed @type plugin.', array('@type' => $form['#plugin_type'])));
Alex Barth
committed
* Theme feeds_ui_plugin_form().
function theme_feeds_ui_plugin_form($variables) {
$form = $variables['form'];
Alex Barth
committed
$output = '';
foreach (element_children($form['plugin_key']) as $key) {
// Assemble container, render form elements.
$container = array(
'title' => $form['plugin_key'][$key]['#title'],
'body' => isset($form['plugin_key'][$key]['#description']) ? $form['plugin_key'][$key]['#description'] : '',
Alex Barth
committed
);
$form['plugin_key'][$key]['#title'] = t('Select');
$form['plugin_key'][$key]['#attributes']['class'] = array('feeds-ui-radio-link');
Alex Barth
committed
unset($form['plugin_key'][$key]['#description']);
$container['actions'] = array(drupal_render($form['plugin_key'][$key]));
$output .= theme('feeds_ui_container', array('container' => $container));
Alex Barth
committed
}
$output .= drupal_render_children($form);
Alex Barth
committed
return $output;
* Edit mapping.
Alex Barth
committed
*
* @todo Completely merge this into config form handling. This is just a
Alex Barth
committed
* shared form of configuration, most of the common functionality can live in
* FeedsProcessor, a flag can tell whether mapping is supported or not.
function feeds_ui_mapping_form($form, &$form_state, $importer) {
$form['#importer'] = $importer->id;
$form['#mappings'] = $mappings = $importer->processor->getMappings();
$form['help']['#markup'] = feeds_ui_mapping_help();
niklas
committed
$form['#prefix'] = '<div id="feeds-ui-mapping-form-wrapper">';
$form['#suffix'] = '</div>';
Alex Barth
committed
megachriz
committed
// Show message when target configuration gets changed.
if (!empty($form_state['mapping_settings'])) {
$form['#mapping_settings'] = $form_state['mapping_settings'];
$form['changed'] = array(
'#theme_wrappers' => array('container'),
'#attributes' => array('class' => array('messages', 'warning')),
'#markup' => t('* Changes made to target configuration are stored temporarily. Click Save to make your changes permanent.'),
);
}
Alex Barth
committed
// Get mapping sources from parsers and targets from processor, format them
// for output.
// Some parsers do not define mapping sources but let them define on the fly.
if ($sources = $importer->parser->getMappingSources()) {
$source_options = _feeds_ui_format_options($sources);
foreach ($sources as $k => $source) {
if (!empty($source['deprecated'])) {
continue;
}
$legend['sources'][$k]['name']['#markup'] = empty($source['name']) ? $k : $source['name'];
$legend['sources'][$k]['description']['#markup'] = empty($source['description']) ? '' : $source['description'];
Alex Barth
committed
}
$legend['sources']['#markup'] = t('This parser supports free source definitions. Enter the name of the source field in lower case into the Source text field above.');
Alex Barth
committed
$targets = $importer->processor->getMappingTargets();
$target_options = _feeds_ui_format_options($targets);
$legend['targets'] = array();
foreach ($targets as $k => $target) {
if (!empty($target['deprecated'])) {
continue;
}
$legend['targets'][$k]['name']['#markup'] = empty($target['name']) ? $k : $target['name'];
$legend['targets'][$k]['description']['#markup'] = empty($target['description']) ? '' : $target['description'];
// Legend explaining source and target elements.
$form['legendset'] = array(
'#type' => 'fieldset',
'#title' => t('Legend'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
);
$form['legendset']['legend'] = $legend;
Alex Barth
committed
niklas
committed
// Add config forms and remove flags to mappings.
$form['config'] = $form['remove_flags'] = $form['mapping_weight'] = array(
Alex Barth
committed
'#tree' => TRUE,
);
if (is_array($mappings)) {
Alex Barth
committed
foreach ($mappings as $i => $mapping) {
niklas
committed
if (isset($targets[$mapping['target']])) {
$form['config'][$i] = feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targets[$mapping['target']]);
Alex Barth
committed
}
niklas
committed
Alex Barth
committed
$form['remove_flags'][$i] = array(
'#type' => 'checkbox',
'#title' => t('Remove'),
'#prefix' => '<div class="feeds-ui-checkbox-link">',
'#suffix' => '</div>',
);
$form['mapping_weight'][$i] = array(
'#type' => 'weight',
'#title' => '',
'#default_value' => $i,
'#attributes' => array(
'class' => array(
'feeds-ui-mapping-weight'
),
),
);
Alex Barth
committed
}
}
Alex Barth
committed
$form['source'] = array(
Chris Leppanen
committed
'#title' => t('Source'),
'#title_display' => 'invisible',
'#options' => $source_options,
'#empty_option' => t('- Select a source -'),
'#description' => t('An element from the feed.'),
Alex Barth
committed
}
else {
$form['source'] = array(
'#type' => 'textfield',
Chris Leppanen
committed
'#title' => t('Source'),
'#title_display' => 'invisible',
Alex Barth
committed
'#size' => 20,
Chris Leppanen
committed
'#default_value' => '',
'#description' => t('The name of source field.'),
Alex Barth
committed
$form['target'] = array(
'#type' => 'select',
Chris Leppanen
committed
'#title' => t('Target'),
'#title_display' => 'invisible',
'#options' => $target_options,
'#empty_option' => t('- Select a target -'),
'#description' => t('The field that stores the data.'),
Alex Barth
committed
);
Chris Leppanen
committed
$form['actions'] = array('#type' => 'actions');
$form['actions']['save'] = array(
Alex Barth
committed
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
niklas
committed
/**
* Per mapper configuration form that is a part of feeds_ui_mapping_form().
*/
function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $target) {
$form_state += array(
'mapping_settings_edit' => NULL,
'mapping_settings' => array(),
);
$base_button = array(
'#submit' => array('feeds_ui_mapping_form_multistep_submit'),
'#ajax' => array(
'callback' => 'feeds_ui_mapping_settings_form_callback',
'wrapper' => 'feeds-ui-mapping-form-wrapper',
'effect' => 'fade',
'progress' => 'none',
),
'#i' => $i,
);
if (isset($form_state['mapping_settings'][$i])) {
$mapping = $form_state['mapping_settings'][$i] + $mapping;
}
if ($form_state['mapping_settings_edit'] === $i) {
$settings_form = array();
foreach ($target['form_callbacks'] as $callback) {
$settings_form += call_user_func($callback, $mapping, $target, $form, $form_state);
niklas
committed
}
// Merge in the optional unique form.
$settings_form += feeds_ui_mapping_settings_optional_unique_form($mapping, $target, $form, $form_state);
return array(
'#type' => 'container',
'settings' => $settings_form,
'save_settings' => $base_button + array(
'#type' => 'submit',
'#name' => 'mapping_settings_update_' . $i,
'#value' => t('Update'),
'#op' => 'update',
),
'cancel_settings' => $base_button + array(
'#type' => 'submit',
'#name' => 'mapping_settings_cancel_' . $i,
'#value' => t('Cancel'),
'#op' => 'cancel',
),
);
}
else {
// Build the summary.
$summary = array();
foreach ($target['summary_callbacks'] as $callback) {
$summary[] = call_user_func($callback, $mapping, $target, $form, $form_state);
niklas
committed
}
// Filter out empty summary values.
$summary = implode('<br />', array_filter($summary));
niklas
committed
// Append the optional unique summary.
if ($optional_unique_summary = feeds_ui_mapping_settings_optional_unique_summary($mapping, $target, $form, $form_state)) {
$summary .= ' ' . $optional_unique_summary;
}
if ($summary) {
return array(
'summary' => array(
'#prefix' => '<div>',
'#markup' => $summary,
'#suffix' => '</div>',
),
'edit_settings' => $base_button + array(
'#type' => 'image_button',
'#name' => 'mapping_settings_edit_' . $i,
'#src' => 'misc/configure.png',
'#attributes' => array('alt' => t('Edit')),
'#op' => 'edit',
),
);
}
}
return array();
niklas
committed
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
}
/**
* Submit callback for a per mapper configuration form. Switches between edit
* and summary mode.
*/
function feeds_ui_mapping_form_multistep_submit($form, &$form_state) {
$trigger = $form_state['triggering_element'];
switch ($trigger['#op']) {
case 'edit':
$form_state['mapping_settings_edit'] = $trigger['#i'];
break;
case 'update':
$values = $form_state['values']['config'][$trigger['#i']]['settings'];
$form_state['mapping_settings'][$trigger['#i']] = $values;
unset($form_state['mapping_settings_edit']);
break;
case 'cancel':
unset($form_state['mapping_settings_edit']);
break;
}
$form_state['rebuild'] = TRUE;
}
/**
* AJAX callback that returns the whole feeds_ui_mapping_form().
*/
function feeds_ui_mapping_settings_form_callback($form, $form_state) {
return $form;
}
/**
Chris Leppanen
committed
* Validation handler for feeds_ui_mapping_form().
Chris Leppanen
committed
function feeds_ui_mapping_form_validate($form, &$form_state) {
Chris Leppanen
committed
if (!strlen($form_state['values']['source']) xor !strlen($form_state['values']['target'])) {
Chris Leppanen
committed
// Check triggering_element here so we can react differently for ajax
// submissions.
switch ($form_state['triggering_element']['#name']) {
// Regular form submission.
case 'op':
Chris Leppanen
committed
if (!strlen($form_state['values']['source'])) {
Chris Leppanen
committed
form_error($form['source'], t('You must select a mapping source.'));
}
else {
form_error($form['target'], t('You must select a mapping target.'));
}
break;
// Be more relaxed on ajax submission.
default:
form_set_value($form['source'], '', $form_state);
form_set_value($form['target'], '', $form_state);
break;
}
Chris Leppanen
committed
* Submission handler for feeds_ui_mapping_form().
Alex Barth
committed
function feeds_ui_mapping_form_submit($form, &$form_state) {
$importer = feeds_importer($form['#importer']);
niklas
committed
$processor = $importer->processor;
$form_state += array(
'mapping_settings' => array(),
'mapping_settings_edit' => NULL,
);
// If an item is in edit mode, prepare it for saving.
if ($form_state['mapping_settings_edit'] !== NULL) {
$values = $form_state['values']['config'][$form_state['mapping_settings_edit']]['settings'];
$form_state['mapping_settings'][$form_state['mapping_settings_edit']] = $values;
}
// We may set some settings to mappings that we remove in the subsequent step,
// that's fine.
$mappings = $form['#mappings'];
niklas
committed
foreach ($form_state['mapping_settings'] as $k => $v) {
$mappings[$k] = array(
'source' => $mappings[$k]['source'],
'target' => $mappings[$k]['target'],
) + $v;
Alex Barth
committed
Tobby Hagler
committed
if (!empty($form_state['values']['remove_flags'])) {
$remove_flags = array_keys(array_filter($form_state['values']['remove_flags']));
foreach ($remove_flags as $k) {
unset($mappings[$k]);
unset($form_state['values']['mapping_weight'][$k]);
Chris Leppanen
committed
drupal_set_message(t('Mapping has been removed.'), 'status', FALSE);
Alex Barth
committed
}
// Keep our keys clean.
$mappings = array_values($mappings);
if (!empty($mappings)) {
array_multisort($form_state['values']['mapping_weight'], $mappings);
}
$processor->addConfig(array('mappings' => $mappings));
Chris Leppanen
committed
Chris Leppanen
committed
if (strlen($form_state['values']['source']) && strlen($form_state['values']['target'])) {
Chris Leppanen
committed
try {
$mappings = $processor->getMappings();
$mappings[] = array(
'source' => $form_state['values']['source'],
'target' => $form_state['values']['target'],
'unique' => FALSE,
);
$processor->addConfig(array('mappings' => $mappings));
drupal_set_message(t('Mapping has been added.'));
}
catch (Exception $e) {
drupal_set_message($e->getMessage(), 'error');
}
}
niklas
committed
$importer->save();
drupal_set_message(t('Your changes have been saved.'));
Alex Barth
committed
* Walk the result of FeedsParser::getMappingSources() or
* FeedsProcessor::getMappingTargets() and format them into
* a Form API options array.
function _feeds_ui_format_options($options, $show_deprecated = FALSE) {
Alex Barth
committed
$result = array();
foreach ($options as $k => $v) {
if (!$show_deprecated && is_array($v) && !empty($v['deprecated'])) {
continue;
}
Alex Barth
committed
if (is_array($v) && !empty($v['name'])) {
$result[$k] = $v['name'] . ' (' . $k . ')';
if (!empty($v['deprecated'])) {
$result[$k] .= ' - ' . t('DEPRECATED');
}
Alex Barth
committed
}
elseif (is_array($v)) {
$result[$k] = $k;
}
else {
$result[$k] = $v;
}
}
asort($result);
Alex Barth
committed
return $result;
niklas
committed
/**
* Per mapping settings summary callback. Shows whether a mapping is used as
* unique or not.
*/
function feeds_ui_mapping_settings_optional_unique_summary($mapping, $target, $form, $form_state) {
if (!empty($target['optional_unique'])) {
if ($mapping['unique']) {
return t('Used as <strong>unique</strong>.');
niklas
committed
return t('Not used as unique.');
}
}
}
/**
* Per mapping settings form callback. Lets the user choose if a target is as
* unique or not.
*/
function feeds_ui_mapping_settings_optional_unique_form($mapping, $target, $form, $form_state) {
$settings_form = array();
if (!empty($target['optional_unique'])) {
$settings_form['unique'] = array(
'#type' => 'checkbox',
'#title' => t('Unique'),
'#default_value' => !empty($mapping['unique']),
);
}
return $settings_form;
}
/**
* Theme feeds_ui_overview_form().
*/
function theme_feeds_ui_overview_form($variables) {
$form = $variables['form'];
drupal_add_css(drupal_get_path('module', 'feeds_ui') . '/feeds_ui.css');
// Iterate through all importers and build a table.
foreach (array('enabled', 'disabled') as $type) {
if (isset($form[$type])) {
foreach (element_children($form[$type]) as $id) {
$row = array();
foreach (element_children($form[$type][$id]) as $col) {
$row[$col] = array(
'data' => drupal_render($form[$type][$id][$col]),
);
}
$rows[] = array(
'data' => $row,
Dave Reid
committed
$output = theme('table', array(
'header' => $form['#header'],
'rows' => $rows,
'attributes' => array('class' => array('feeds-admin-importers')),
'empty' => t('No importers available.'),
));
if (!empty($rows)) {
$output .= drupal_render_children($form);
Dave Reid
committed
Alex Barth
committed
* Theme feeds_ui_edit_page().
function theme_feeds_ui_edit_page($variables) {
$config_info = $variables['info'];
$active_container = $variables['active'];
drupal_add_css(drupal_get_path('module', 'feeds_ui') . '/feeds_ui.css');
Alex Barth
committed
// Outer wrapper.
joachim
committed
$output = '<div class="feeds-settings clearfix">';
Alex Barth
committed
// Build left bar.
$output .= '<div class="left-bar">';
foreach ($config_info as $info) {
$output .= theme('feeds_ui_container', array('container' => $info));
Alex Barth
committed
}
$output .= '</div>';
// Build configuration space.
$output .= '<div class="configuration">';
$output .= '<div class="configuration-squeeze">';
$output .= theme('feeds_ui_container', array('container' => $active_container));
Alex Barth
committed
$output .= '</div>';
$output .= '</div>';
$output .= '</div>'; // ''<div class="feeds-settings">';
return $output;
Alex Barth
committed
* Render a simple container. A container can have a title, a description and
* one or more actions. Recursive.
*
* @todo Replace with theme_fieldset or a wrapper to theme_fieldset?
Alex Barth
committed
*
* @param $variables
* An array containing an array at 'container'.
* A 'container' array may contain one or more of the following keys:
Alex Barth
committed
* array(
* 'title' => 'the title',
* 'body' => 'the body of the container, may also be an array of more
* containers or a renderable array.',
* 'class' => array('the class of the container.'),
Alex Barth
committed
* 'id' => 'the id of the container',
* );
function theme_feeds_ui_container($variables) {
$container = $variables['container'];
Alex Barth
committed
$class = array_merge(array('feeds-container'), empty($container['class']) ? array('plain') : $container['class']);
$id = empty($container['id']) ? '': ' id="' . $container['id'] . '"';
$output = '<div class="' . implode(' ', $class) . '"' . $id . '>';
Alex Barth
committed
if (isset($container['actions']) && count($container['actions'])) {
$output .= '<ul class="container-actions">';
foreach ($container['actions'] as $action) {
$output .= '<li>' . $action . '</li>';
}
$output .= '</ul>';
Alex Barth
committed
}
if (!empty($container['title'])) {
$output .= '<h4 class="feeds-container-title">';
$output .= $container['title'];