1161 lines
34 KiB
Plaintext
1161 lines
34 KiB
Plaintext
<?php
|
|
/**
|
|
* @file
|
|
* Main file for Linkit module.
|
|
*/
|
|
|
|
/**
|
|
* Define that urls should be constructed as it is (raw).
|
|
*/
|
|
define('LINKIT_URL_METHOD_RAW', 1);
|
|
|
|
/**
|
|
* Define that urls should be constructed as it is (raw) with a prepending
|
|
* slash.
|
|
*/
|
|
define('LINKIT_URL_METHOD_RAW_SLASH', 2);
|
|
|
|
/**
|
|
* Define that paths should be constructed as an alias.
|
|
*/
|
|
define('LINKIT_URL_METHOD_ALIAS', 3);
|
|
|
|
/**
|
|
* Define which query string key Better autocomplete will just.
|
|
*/
|
|
define('LINKIT_BAC_QUERY_KEY', 's');
|
|
|
|
/**
|
|
* Define the minimum number of characters to perform server polling.
|
|
*/
|
|
define('LINKIT_CHAR_LIMIT', 3);
|
|
|
|
/**
|
|
* Define the time from last key press to poll the server.
|
|
*/
|
|
define('LINKIT_WAIT', 350);
|
|
|
|
/**
|
|
* Define the client side timeout for a request to the server.
|
|
*/
|
|
define('LINKIT_REMOTE_TIMEOUT', 10000);
|
|
|
|
/**
|
|
* Define the profile type editor.
|
|
*/
|
|
define('LINKIT_PROFILE_TYPE_EDITOR', 1);
|
|
|
|
/**
|
|
* Define the profile type field.
|
|
*/
|
|
define('LINKIT_PROFILE_TYPE_FIELD', 2);
|
|
|
|
// Include the file with the field functions.
|
|
require_once dirname(__FILE__) . '/linkit.field.inc';
|
|
|
|
/**
|
|
* Implements hook_permission().
|
|
*/
|
|
function linkit_permission() {
|
|
return array(
|
|
'administer linkit' => array(
|
|
'title' => t('Administer Linkit'),
|
|
'description' => t('Perform administration tasks for Linkit.'),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_ctools_plugin_directory().
|
|
*/
|
|
function linkit_ctools_plugin_directory($module, $plugin) {
|
|
if ($module == 'ctools' && !empty($plugin)) {
|
|
return "plugins/" . $plugin;
|
|
}
|
|
if ($module == 'linkit' && !empty($plugin)) {
|
|
return "plugins/" . $plugin;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_ctools_plugin_TYPE() to inform the plugin system that Linkit
|
|
* owns Linkit plugin types.
|
|
*/
|
|
function linkit_ctools_plugin_type() {
|
|
$plugins['linkit_search'] = array(
|
|
'child plugins' => TRUE,
|
|
'classes' => array('handler'),
|
|
);
|
|
$plugins['linkit_insert'] = array(
|
|
'process' => array(
|
|
'function' => 'linkit_insert_plugin_process',
|
|
),
|
|
);
|
|
$plugins['linkit_attribute'] = array();
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Provide defaults for insert plugins.
|
|
*/
|
|
function linkit_insert_plugin_process(&$plugin, $info) {
|
|
// The plugin javascript can be just a filename or a full path,
|
|
// in case it's just a filename, add the plugin path.
|
|
if (!file_exists($plugin['javascript'])) {
|
|
$plugin['javascript'] = $plugin['path'] . '/' . $plugin['javascript'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load a single Linkit profile.
|
|
*
|
|
* @param $name
|
|
* A string with the name of the profile to load.
|
|
*
|
|
* @return
|
|
* A LinkitProfile object or FALSE if no profile is found.
|
|
*/
|
|
function linkit_profile_load($name) {
|
|
ctools_include('export');
|
|
$result = ctools_export_load_object('linkit_profiles', 'names', array($name));
|
|
if (isset($result[$name])) {
|
|
return $result[$name];
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Load all Linkit profiles.
|
|
*
|
|
* @return
|
|
* An array with LinkitProfile objects.
|
|
*/
|
|
function linkit_profile_load_all() {
|
|
ctools_include('export');
|
|
$profiles = ctools_export_load_object('linkit_profiles');
|
|
return $profiles;
|
|
}
|
|
|
|
/**
|
|
* Load all Linkit profiles that is for fields.
|
|
*
|
|
* @return
|
|
* An array with LinkitProfile objects.
|
|
*/
|
|
function linkit_profile_field_load_all() {
|
|
$profiles = linkit_profile_load_all();
|
|
foreach ($profiles as &$profile) {
|
|
if ($profile->profile_type != LINKIT_PROFILE_TYPE_FIELD) {
|
|
$profile = FALSE;
|
|
}
|
|
}
|
|
return array_filter($profiles);
|
|
}
|
|
|
|
/**
|
|
* Load all Linkit profiles that is for editors.
|
|
*
|
|
* @return
|
|
* An array with LinkitProfile objects.
|
|
*/
|
|
function linkit_profile_editor_load_all() {
|
|
$profiles = linkit_profile_load_all();
|
|
foreach ($profiles as &$profile) {
|
|
if ($profile->profile_type != LINKIT_PROFILE_TYPE_EDITOR) {
|
|
$profile = FALSE;
|
|
}
|
|
}
|
|
return array_filter($profiles);
|
|
}
|
|
|
|
/**
|
|
* Temporary saves the active profile. Active means that the user is working
|
|
* with the profile in the dialog.
|
|
*
|
|
* @param string LinkitProfile $profile
|
|
* A LinkitProfile object.
|
|
*/
|
|
function linkit_set_active_profile(LinkitProfile $profile) {
|
|
$active_profile = &drupal_static('linkit_active_profile');
|
|
$active_profile = $profile;
|
|
}
|
|
|
|
/**
|
|
* Get the currently active profile.
|
|
*
|
|
* @return
|
|
* A LinkitProfile object if there is one set.
|
|
*
|
|
* @see linkit_set_active_profile()
|
|
*/
|
|
function linkit_get_active_profile() {
|
|
return drupal_static('linkit_active_profile');
|
|
}
|
|
|
|
/**
|
|
* Fetch metadata for all Linkit search plugins.
|
|
*
|
|
* @return
|
|
* An array of arrays with information about all available Linkit search
|
|
* plugins.
|
|
*/
|
|
function linkit_search_plugin_load_all() {
|
|
ctools_include('plugins');
|
|
$plugins = ctools_get_plugins('linkit', 'linkit_search');
|
|
// If you alter the plugin handler, be sure the new handler is registerd or
|
|
// you include it in some other way.
|
|
drupal_alter('linkit_search_plugins', $plugins);
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Function used by uasort to sort plugins by weight.
|
|
*/
|
|
function linkit_sort_plugins_by_weight($a, $b) {
|
|
return $a["weight"] >= $b["weight"];
|
|
}
|
|
|
|
/**
|
|
* Fetch metadata for one Linkit search plugin by the given name.
|
|
*
|
|
* @param $plugin_name
|
|
* A string with the name of the plugin to load.
|
|
*
|
|
* @return
|
|
* An array with information about the search plugin.
|
|
*/
|
|
function linkit_search_plugin_load($plugin_name) {
|
|
ctools_include('plugins');
|
|
$plugin = ctools_get_plugins('linkit', 'linkit_search', $plugin_name);
|
|
// If you alter the plugin handler, be sure the new handler is registerd or
|
|
// you include it in some other way.
|
|
drupal_alter('linkit_search_plugin', $plugin);
|
|
return $plugin;
|
|
}
|
|
|
|
/**
|
|
* Fetch metadata for all Linkit insert plugins.
|
|
*
|
|
* @return
|
|
* An array of arrays with information about all available insert plugins.
|
|
*/
|
|
function linkit_insert_plugin_load_all() {
|
|
ctools_include('plugins');
|
|
// Load all insert plugins.
|
|
$plugins = ctools_get_plugins('linkit', 'linkit_insert');
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Fetch metadata for one Linkit insert plugin by the given name.
|
|
*
|
|
* @param $plugin_name
|
|
* A string with the name of the plugin to load.
|
|
*
|
|
* @return
|
|
* An array with information about the insert plugin.
|
|
*/
|
|
function linkit_insert_plugin_load($plugin_name) {
|
|
ctools_include('plugins');
|
|
// Load all insert plugins.
|
|
$plugins = ctools_get_plugins('linkit', 'linkit_insert', $plugin_name);
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Fetch metadata for all Linkit attribute plugins.
|
|
*
|
|
* @return
|
|
* An array of arrays with information about all available attribute plugins.
|
|
*/
|
|
function linkit_attribute_plugin_load_all() {
|
|
ctools_include('plugins');
|
|
// Load all attribute plugins.
|
|
$attributes = ctools_get_plugins('linkit', 'linkit_attribute');
|
|
return $attributes;
|
|
}
|
|
|
|
function linkit_attribute_plugin_load($plugin_name) {
|
|
ctools_include('plugins');
|
|
// Load all insert plugins.
|
|
$plugins = ctools_get_plugins('linkit', 'linkit_attribute', $plugin_name);
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_theme().
|
|
*/
|
|
function linkit_theme($existing, $type, $theme, $path) {
|
|
return array(
|
|
'linkit_plugin_form_table' => array(
|
|
'render element' => 'form',
|
|
'file' => 'includes/theme.inc',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu_alter().
|
|
*/
|
|
function linkit_menu_alter(&$items) {
|
|
// Override the default titles that ctools export_ui sets.
|
|
// This way there is less code compared to define this in the plugin array.
|
|
$items['admin/config/content/linkit/add']['title'] = 'Add new profile';
|
|
$items['admin/config/content/linkit/import']['title'] = 'Import profiles';
|
|
|
|
// Make tabs instead of action links.
|
|
$items['admin/config/content/linkit/add']['type'] = MENU_LOCAL_TASK;
|
|
$items['admin/config/content/linkit/import']['type'] = MENU_LOCAL_TASK;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_module_implements_alter().
|
|
*
|
|
* @TODO: Document why we are doing this.
|
|
* @see linkit_element_info_alter()
|
|
*/
|
|
function linkit_module_implements_alter(&$implementations, $hook) {
|
|
if ($hook == 'element_info_alter') {
|
|
$group = $implementations['linkit'];
|
|
unset($implementations['linkit']);
|
|
$implementations['linkit'] = $group;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_element_info_alter().
|
|
*/
|
|
function linkit_element_info_alter(&$types) {
|
|
// Append a after_build function for the field integration.
|
|
foreach (linkit_get_allowed_field_elements() as $element) {
|
|
if (isset($types[$element])) {
|
|
$types[$element]['#after_build'][] = 'linkit_field_element_after_build';
|
|
}
|
|
}
|
|
|
|
// Used when using ckeditor module.
|
|
if (isset($types['text_format']['#pre_render']) && is_array($types['text_format']['#pre_render'])) {
|
|
if (in_array('ckeditor_pre_render_text_format', $types['text_format']['#pre_render'])) {
|
|
$types['text_format']['#pre_render'][] = 'linkit_pre_render_editor_element';
|
|
// Add the linkit library for the editor.
|
|
$types['text_format']['#attached']['library'][] = array('linkit', 'ckeditor');
|
|
}
|
|
}
|
|
|
|
// Used when using wysiwyg module.
|
|
if (isset($types['text_format']['#pre_render']) && is_array($types['text_format']['#pre_render'])) {
|
|
if (in_array('wysiwyg_pre_render_text_format', $types['text_format']['#pre_render'])) {
|
|
$types['text_format']['#process'][] = 'linkit_pre_render_editor_element';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_library().
|
|
*/
|
|
function linkit_library() {
|
|
$path = drupal_get_path('module', 'linkit');
|
|
|
|
$common = array(
|
|
'website' => 'http://drupal.org/project/linkit',
|
|
'version' => '7.3',
|
|
);
|
|
|
|
// Linkit base
|
|
$libraries['base'] = array(
|
|
'title' => 'Linkit base',
|
|
'js' => array(
|
|
$path . '/js/linkit.js' => array('group' => JS_DEFAULT, 'weight' => -1),
|
|
// Add global settings for Linkit.
|
|
array(
|
|
'type' => 'setting',
|
|
// ___profile___ is just a placeholder.
|
|
'data' => array(
|
|
'linkit' => array(
|
|
'autocompletePath' => url('linkit/autocomplete/___profile___', array('query' => array(LINKIT_BAC_QUERY_KEY => ''), 'absolute' => TRUE)),
|
|
'dashboardPath' => url('linkit/dashboard/'),
|
|
'currentInstance' => new stdClass(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
'dependencies' => array(
|
|
array('system', 'ui.dialog'),
|
|
array('system', 'drupal.ajax'),
|
|
),
|
|
);
|
|
|
|
// Linkit field ui script.
|
|
$libraries['field'] = array(
|
|
'title' => 'Linkit Field UI',
|
|
'js' => array(
|
|
$path . '/js/linkit.field.js' => array('group' => JS_DEFAULT),
|
|
),
|
|
'dependencies' => array(
|
|
array('linkit', 'base'),
|
|
),
|
|
);
|
|
|
|
// Linkit ckeditor dialog script.
|
|
$libraries['ckeditor'] = array(
|
|
'title' => 'Linkit CKeditor',
|
|
'js' => array(
|
|
$path . '/editors/ckeditor/linkitDialog.js' => array('group' => JS_DEFAULT),
|
|
),
|
|
'dependencies' => array(
|
|
array('linkit', 'base'),
|
|
),
|
|
);
|
|
|
|
// Linkit tinymce dialog script.
|
|
$libraries['tinymce'] = array(
|
|
'title' => 'Linkit TinyMCE',
|
|
'js' => array(
|
|
$path . '/editors/tinymce/linkitDialog.js' => array('group' => JS_DEFAULT),
|
|
),
|
|
'dependencies' => array(
|
|
array('linkit', 'base'),
|
|
),
|
|
);
|
|
|
|
foreach ($libraries as &$library) {
|
|
$library += $common;
|
|
}
|
|
|
|
// Linkit BAC
|
|
$libraries['bac'] = array(
|
|
'website' => 'https://github.com/betamos/Better-Autocomplete',
|
|
'version' => '1.0',
|
|
'title' => 'Better autocomplete',
|
|
'js' => array(
|
|
$path . '/better-autocomplete/jquery.better-autocomplete.js' => array('group' => JS_LIBRARY),
|
|
),
|
|
'css' => array(
|
|
$path . '/better-autocomplete/better-autocomplete.css' => array(
|
|
'group' => CSS_DEFAULT,
|
|
'preprocess' => FALSE,
|
|
),
|
|
),
|
|
);
|
|
|
|
return $libraries;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu().
|
|
*/
|
|
function linkit_menu() {
|
|
$items = array();
|
|
|
|
// This is the Linkit dashboard menu callback.
|
|
$items['linkit/dashboard/%linkit_profile'] = array(
|
|
'title' => 'Linkit',
|
|
'description' => 'Dashboard',
|
|
'delivery callback' => 'ajax_deliver',
|
|
'page callback' => 'linkit_dashboard_page',
|
|
'page arguments' => array(2),
|
|
'access callback' => TRUE,
|
|
'theme callback' => 'ajax_base_page_theme',
|
|
'type' => MENU_CALLBACK,
|
|
'file path' => 'includes',
|
|
'file' => 'form.inc',
|
|
);
|
|
|
|
// The autocomplete callback, the search_string is found in the $_GET array
|
|
// so dont pass that to the page callback.
|
|
$items['linkit/autocomplete/%linkit_profile'] = array(
|
|
'title' => 'Linkit autocomplete response function',
|
|
'page callback' => 'linkit_autocomplete',
|
|
'page arguments' => array(2),
|
|
'access callback' => TRUE,
|
|
'type' => MENU_CALLBACK,
|
|
);
|
|
|
|
return $items;
|
|
};
|
|
|
|
/**
|
|
* Creates the dialog dashboard.
|
|
*
|
|
* We don't call drupal_get_form() in the menu callback as we don't want to
|
|
* return the rendered form, we just want to print it as it is.
|
|
*
|
|
* @param $profile
|
|
* A LinkitProfile object.
|
|
*/
|
|
function linkit_dashboard_page(LinkitProfile $profile) {
|
|
// Set the active Linkit profile.
|
|
linkit_set_active_profile($profile);
|
|
// The dashboard isn't really a form.
|
|
// See comment in linkit_dashboard_form() for more info.
|
|
$form = drupal_get_form('linkit_dashboard_form');
|
|
//$change_profile = drupal_get_form('linkit_dashboad_profile_change_form');
|
|
return array(
|
|
'#type' => 'ajax',
|
|
'#commands' => array(
|
|
ajax_command_html('#linkit-modal', drupal_render($form)),
|
|
ajax_command_prepend('#linkit-modal', theme('status_messages')),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Ajax Form callback;
|
|
*
|
|
* Returns the Linkit "form" when changing profile.
|
|
*/
|
|
function linkit_change_profile($form, $form_state) {
|
|
return $form['linkit_container'];
|
|
}
|
|
|
|
/**
|
|
* Create the dashboard page.
|
|
*/
|
|
function linkit_dashboard_form($form, &$form_state) {
|
|
// The use of a form here is insignificant as we are not submitting any data.
|
|
// A form here just cause trouble because it can be submitted and will do new
|
|
// request to the action of the form.
|
|
// In normal cases this isn't really a problem as the javascript is preventing
|
|
// the form to be submitted, but in case of a javascript error, this event
|
|
// can't be prevented.
|
|
// We still have to use the FAPI to build this "form", as we want proper
|
|
// classes and ids on the elements and take advantage of all the good parts of
|
|
// the form generation.
|
|
// So, just make sure the form tags dont get rendered.
|
|
//$form['#theme_wrappers'] = array();
|
|
|
|
// Get the active Linkit profile.
|
|
if (!empty($form_state['values']['profile'])) {
|
|
linkit_set_active_profile(linkit_profile_load($form_state['values']['profile']));
|
|
}
|
|
|
|
$active_profile = linkit_get_active_profile();
|
|
$profiles = linkit_profile_editor_load_all();
|
|
|
|
$_profiles = array();
|
|
foreach ($profiles as $profile) {
|
|
$_profiles[$profile->name] = check_plain($profile->admin_title);
|
|
}
|
|
|
|
// Attach css to the form.
|
|
$form['#attached']['css'][drupal_get_path('module', 'linkit') . '/css/linkit.css'] = array(
|
|
'preprocess' => FALSE,
|
|
);
|
|
|
|
// Attach js to the form.
|
|
$form['#attached']['js'] = array(
|
|
drupal_get_path('module', 'linkit') . '/js/linkit.dashboard.js',
|
|
);
|
|
|
|
if ($active_profile->profile_type == LINKIT_PROFILE_TYPE_EDITOR) {
|
|
$form['profile'] = array(
|
|
'#type' => 'radios',
|
|
'#title' => t('Select profile to use'),
|
|
'#default_value' => $active_profile->name,
|
|
'#weight' => -100,
|
|
'#options' => $_profiles,
|
|
'#ajax' => array(
|
|
'callback' => 'linkit_change_profile',
|
|
'wrapper' => 'linkit-dashboard-ajax-wrapper',
|
|
'method' => 'replaceWith',
|
|
'effect' => 'fade',
|
|
'event' => 'click',
|
|
),
|
|
'#prefix' => '<div id="linkit-profile-changer">',
|
|
'#suffix' => '</div>',
|
|
);
|
|
|
|
foreach ($profiles as $profile) {
|
|
$form['profile'] += array(
|
|
$profile->name => array(
|
|
'#description' => check_markup($profile->admin_description),
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
$form['linkit_container'] = array(
|
|
'#type' => 'container',
|
|
'#weight' => 100,
|
|
'#prefix' => '<div id="linkit-dashboard-ajax-wrapper">',
|
|
'#suffix' => '</div>',
|
|
'#attached' => array(
|
|
'js' => array(
|
|
array(
|
|
'data' => array(
|
|
'linkit' => array(
|
|
'currentInstance' => array(
|
|
'profile' => $active_profile->name,
|
|
'autocomplete' => array_filter($active_profile->data['autocomplete']),
|
|
),
|
|
),
|
|
),
|
|
'type' => 'setting',
|
|
)
|
|
),
|
|
),
|
|
);
|
|
|
|
$form['linkit_container']['linkit_search'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Search for content.'),
|
|
'#description' => t('Start typing to find content or paste a URL.'),
|
|
'#maxlength' => 255,
|
|
'#size' => 60,
|
|
'#default_value' => '',
|
|
'#weight' => -10,
|
|
'#attributes' => array(
|
|
'class' => array(
|
|
'linkit-search-element',
|
|
),
|
|
),
|
|
'#attached' => array(
|
|
'library' => array(
|
|
array('linkit', 'bac'),
|
|
),
|
|
),
|
|
);
|
|
|
|
$form['linkit_container']['linkit_path'] = array(
|
|
'#type' => 'textfield',
|
|
'#title' => t('Link URL'),
|
|
'#description' => t('This will be populated by the search, or you can fill it in yourself.'),
|
|
'#required' => TRUE,
|
|
'#maxlength' => NULL,
|
|
'#size' => 60,
|
|
'#default_value' => '',
|
|
'#weight' => -1,
|
|
'#attributes' => array(
|
|
'class' => array(
|
|
'linkit-path-element',
|
|
),
|
|
),
|
|
);
|
|
|
|
// If we have enabled attributes, lets put them inside a fieldset.
|
|
if (count($active_profile->getEnabledAttributePlugins())) {
|
|
// Create the container fieldset.
|
|
$form['linkit_container']['linkit_attributes'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Options'),
|
|
'#collapsible' => TRUE,
|
|
'#collapsed' => TRUE,
|
|
'#weight' => 10,
|
|
'#attributes' => array(
|
|
'class' => array(
|
|
'linkit-attributes',
|
|
),
|
|
),
|
|
);
|
|
// Append the attributes info the fieldset.
|
|
foreach ($active_profile->getEnabledAttributePlugins() AS $name => $attribute) {
|
|
// Add a class to all items.
|
|
$attribute['#attributes']['class'][] = 'linkit-attribute-' . $name;
|
|
// Add 'linkit_' prefix to ensure that is unique.
|
|
$form['linkit_container']['linkit_attributes']['linkit_' . $name] = $attribute;
|
|
}
|
|
}
|
|
|
|
$form['linkit_container']['linkit_insert'] = array(
|
|
'#type' => 'button',
|
|
'#value' => t('Insert link'),
|
|
'#suffix' => '<a id="linkit-cancel" href="#">' . t('Cancel') . '</a>',
|
|
'#weight' => 100,
|
|
'#attributes' => array(
|
|
'class' => array(
|
|
'linkit-insert',
|
|
),
|
|
),
|
|
);
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Autocomplete callback function.
|
|
*
|
|
* @param object $profile
|
|
* A LinkitProfile object.
|
|
*/
|
|
function linkit_autocomplete(LinkitProfile $profile) {
|
|
// Set the active Linkit profile.
|
|
linkit_set_active_profile($profile);
|
|
|
|
// This is not sanitized until it is used within output.
|
|
$search_string = $_GET[LINKIT_BAC_QUERY_KEY];
|
|
|
|
$results = array();
|
|
|
|
// Special for link to frontpage.
|
|
if (strpos($search_string, 'front') !== FALSE) {
|
|
$results[] = array(
|
|
'title' => t('Frontpage'),
|
|
'description' => 'The frontpage for this site.',
|
|
'path' => url('<front>'),
|
|
'group' => t('System'),
|
|
);
|
|
}
|
|
|
|
// Let the Linkit search plugins do their job.
|
|
$results = array_merge($results, linkit_autocomplete_search_plugins($search_string));
|
|
|
|
// If there is results from the Linkit search plugins, don't care about
|
|
// searching for absolute URL's results.
|
|
if (!count($results)) {
|
|
// Try to parse the string as an URL.
|
|
// We will not use the drupal wrapper function drupal_pasre_url() as that
|
|
// function should only be used for URL's that have been generated by the
|
|
// system, and we can't be sure that this is the case here.
|
|
|
|
// Check for an e-mail address then return an e-mail result and create a
|
|
// mail-to link if appropriate.
|
|
if (filter_var($search_string, FILTER_VALIDATE_EMAIL)) {
|
|
$results = array(array(
|
|
'title' => t('E-mail @email', array('@email' => $search_string)),
|
|
'path' => 'mailto:'. check_plain($search_string),
|
|
'description' => t('Open your mail client ready to e-mail @email', array('@email' => $search_string)),
|
|
'addClass' => 'status-notice',
|
|
));
|
|
}
|
|
else {
|
|
$parts = parse_url(trim($search_string, '/'));
|
|
|
|
// This seems to be an absolute URL.
|
|
if (isset($parts['scheme']) || isset($parts['host'])) {
|
|
$results = array_merge($results, linkit_autocomplete_absolute_url($search_string, $parts));
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there is still no results, return a "no results" array.
|
|
if (!count($results)) {
|
|
$results = array(
|
|
array(
|
|
'title' => t('No results'),
|
|
'addClass' => 'status-notice',
|
|
'disabled' => TRUE,
|
|
)
|
|
);
|
|
}
|
|
|
|
print drupal_json_output($results);
|
|
drupal_exit();
|
|
}
|
|
|
|
/**
|
|
* Perform autocomplete search with the Linkit search plugins.
|
|
*
|
|
* @param $search_string
|
|
* The search string.
|
|
*
|
|
* @return
|
|
* An array with the results objects, or an empty array if no results.
|
|
*/
|
|
function linkit_autocomplete_search_plugins($search_string) {
|
|
$matches = array();
|
|
$profile = linkit_get_active_profile();
|
|
|
|
// Get matches from all search plugins.
|
|
foreach ($profile->getEnabledsearchPlugins() as $plugin_name => $plugin) {
|
|
$matches = array_merge($matches, $plugin->fetchResults($search_string));
|
|
}
|
|
|
|
return $matches;
|
|
}
|
|
|
|
/**
|
|
* Retrieve relevant information about a URL. Specifically this function is
|
|
* usable for internal (absolute) URL:s, but it also works for external URL:s.
|
|
*
|
|
* @param $url
|
|
* The search string (URL) that should be scanned.
|
|
*
|
|
* @param $parts
|
|
* An array of URL parts from parse_url().
|
|
*
|
|
* @return
|
|
* An associative array containing:
|
|
* - url: The same as the argument $url, untouched.
|
|
* - target: Either "internal" or "external".
|
|
* - requested_path: If internal, the path requested relative to Drupal root.
|
|
* The only exception is when frontpage is referred directly, then it will
|
|
* be whatever the frontpage is set to.
|
|
* - system_path: If internal and the path is valid, the Drupal system path,
|
|
* e.g. "node/23".
|
|
* - query_fragment: If internal, the query and fragment of the url.
|
|
* Typically it is not needed for searching and is just reappended back
|
|
* when processing of the path is done. It could e.g. look like
|
|
* "?foo=bar#anchor".
|
|
*/
|
|
function linkit_parse_url($url, $parts) {
|
|
global $base_url;
|
|
|
|
// Make a new array, this will hold the components from parse_url() and our
|
|
// own "Linkit" components.
|
|
$path_info = array();
|
|
|
|
// Append the original components from parse_url() to our array.
|
|
$path_info += $parts;
|
|
|
|
// Save the whole URL.
|
|
$path_info['url'] = $url;
|
|
|
|
if (!isset($path_info['query'])) {
|
|
$path_info['query'] = '';
|
|
}
|
|
|
|
// Convert the query string to an array as Drupal can only handle querys as
|
|
// arrays.
|
|
// @see http://api.drupal.org/drupal_http_build_query
|
|
parse_str($path_info['query'], $path_info['query']);
|
|
|
|
// The 'q' parameter contains the path of the current page if clean URLs are
|
|
// disabled. It overrides the 'path' of the URL when present, even if clean
|
|
// URLs are enabled, due to how Apache rewriting rules work.
|
|
if (isset($path_info['query']['q'])) {
|
|
$path_info['path'] = $path_info['query']['q'];
|
|
unset($path_info['query']['q']);
|
|
}
|
|
|
|
// Load all local stream wrappers. The $path_info['scheme'] will be tested
|
|
// against this later to ensure it is local.
|
|
$local_stream_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
|
|
|
|
// Internal URL.
|
|
// We can not use the url_is_external() as it treats all absolute links as
|
|
// external and treats all stream wrappers as internal.
|
|
$local_hosts = array($base_url);
|
|
// Give other modules a chance to add/remove/alter the local hosts.
|
|
drupal_alter('linkit_local_hosts', $local_hosts);
|
|
$local_url = in_array(trim($path_info['scheme'] . '://' . $path_info['host'] . base_path(), '/'), $local_hosts);
|
|
$local_stream_wrapper = isset($local_stream_wrappers[$path_info['scheme']]);
|
|
//@TODO: maybe file_valid_uri() ?
|
|
|
|
if ($local_url || $local_stream_wrapper) {
|
|
// Set target as internal.
|
|
$path_info['target'] = 'internal';
|
|
|
|
// If this is seems to be a valid local stream wrapper string, force the
|
|
// $path_info['path'] to be set to the file_url.
|
|
if ($local_stream_wrapper) {
|
|
$path_info = array_merge($path_info, parse_url(file_create_url($path_info['url'])));
|
|
}
|
|
|
|
// Trim the path from slashes.
|
|
$path_info['path'] = trim($path_info['path'], '/');
|
|
|
|
// If we have an empty path, and an internal target, we can assume that the
|
|
// URL should go the the frontpage.
|
|
if (empty($path_info['path'])) {
|
|
$path_info['frontpage'] = TRUE;
|
|
$path_info['path'] = variable_get('site_frontpage', 'node');
|
|
}
|
|
|
|
// Try converting the path to an internal Drupal path.
|
|
$internal_url = drupal_get_normal_path($path_info['path']);
|
|
|
|
// Add the "real" system path (not the alias) if the current user have
|
|
// access to the URL.
|
|
$path_info['system_path'] = drupal_valid_path($internal_url) ? $internal_url : FALSE;
|
|
|
|
$menu_item = menu_get_item($path_info['system_path']);
|
|
if ($menu_item) {
|
|
$path_info['menu']['path'] = $path_info['system_path'];
|
|
$path_info['menu']['description'] = check_plain($menu_item['description']);
|
|
$path_info['menu']['title'] = check_plain($menu_item['title']);
|
|
}
|
|
// If we have a valid stream wrapper URL, find out the internal url.
|
|
if ($local_stream_wrapper) {
|
|
$path_info['system_path'] = $path_info['path'];
|
|
$path_info['menu']['path'] = $path_info['path'];
|
|
$path_info['menu']['description'] = 'This funciton is not fully integrated yet.';
|
|
$path_info['menu']['title'] = 'This funciton is not fully integrated yet.';
|
|
}
|
|
}
|
|
else {
|
|
// Set target as external.
|
|
$path_info['target'] = 'external';
|
|
}
|
|
|
|
return $path_info;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the result object from an absolute URL. Both internal and external
|
|
* paths work.
|
|
*
|
|
* @param $url
|
|
* The search string which seems to be an URL.
|
|
*
|
|
* @param $parts
|
|
* An array of URL parts from parse_url().
|
|
*
|
|
* @return
|
|
* A result object. This is an associative array which consists of:
|
|
* - title: The title of the result.
|
|
* - description: The description of the result (may contain HTML).
|
|
* - path: The target path which will be inserted as the href in the link.
|
|
* - addClass: A CSS class that will be added to the DOM result item.
|
|
*/
|
|
function linkit_autocomplete_absolute_url($url, $parts) {
|
|
$result = array();
|
|
|
|
// Retrieve relevant information about the search string and if its a URL.
|
|
$path_info = linkit_parse_url($url, $parts);
|
|
|
|
// Set default options to pass with the url() function if the URL is internal.
|
|
$url_options = array();
|
|
// Add the URL frament.
|
|
$url_options['fragment'] = isset($path_info['fragment']) ? $path_info['fragment'] : '';
|
|
// Add the URL query.
|
|
$url_options['query'] = isset($path_info['query']) ? $path_info['query'] : '';
|
|
|
|
// The URL is registerd by Drupal (Internal).
|
|
if (isset($path_info['menu']) && $path_info['system_path'] !== FALSE) {
|
|
$result = array(
|
|
'path' => linkit_get_insert_plugin_processed_path(linkit_get_active_profile(), $path_info['menu']['path'], $url_options),
|
|
'title' => $path_info['menu']['title'] ? check_plain($path_info['menu']['title']) : check_plain($path_info['menu']['path']),
|
|
'description' => check_plain($path_info['menu']['description']) . ' ' . t('This is an internal path.'),
|
|
'addClass' => 'status-ok',
|
|
);
|
|
}
|
|
// No internal menu result, but the URL seems to be internal. Either we do not
|
|
// have access to it or it does not exists.
|
|
elseif ($path_info['target'] == 'internal') {
|
|
$result = array(
|
|
'path' => linkit_get_insert_plugin_processed_path(linkit_get_active_profile(), $path_info['path'], $url_options),
|
|
'title' => t('Page not found'),
|
|
'description' => t('This page does not exist or you do not have access to it.'),
|
|
'addClass' => 'status-warning',
|
|
);
|
|
}
|
|
// The URL seems to be external.
|
|
elseif ($path_info['target'] == 'external') {
|
|
$result = array(
|
|
'title' => t('No information available'),
|
|
'description' => t('This is an external URL, but we don\'t know where it leads.'),
|
|
'path' => $path_info['url'],
|
|
'addClass' => 'status-notice',
|
|
);
|
|
}
|
|
|
|
// Return the results in an array as BAC will need to have it that way.
|
|
return array($result);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_image_default_styles().
|
|
*
|
|
* @return
|
|
* An array of image styles, keyed by the style name.
|
|
*/
|
|
function linkit_image_default_styles() {
|
|
$styles = array();
|
|
|
|
$styles['linkit_thumb'] = array(
|
|
'effects' => array(
|
|
array(
|
|
'name' => 'image_scale',
|
|
'data' => array(
|
|
'width' => 50,
|
|
'height' => 50,
|
|
'upscale' => 0,
|
|
),
|
|
'weight' => 0,
|
|
),
|
|
),
|
|
);
|
|
return $styles;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_wysiwyg_plugin().
|
|
*/
|
|
function linkit_wysiwyg_plugin($editor, $version) {
|
|
$plugin = array();
|
|
|
|
$plugin['linkit'] = array(
|
|
'path' => drupal_get_path('module', 'linkit') . '/editors/' . $editor,
|
|
'buttons' => array('linkit' => t('Linkit')),
|
|
'url' => 'http://drupal.org/project/linkit',
|
|
'load' => TRUE,
|
|
);
|
|
|
|
// TinyMCE needs to know the filename.
|
|
if ($editor == 'tinymce') {
|
|
$plugin['linkit']['filename'] = 'editor_plugin.js';
|
|
}
|
|
|
|
// Add the linkit library for the editor.
|
|
drupal_add_library('linkit', $editor);
|
|
|
|
return $plugin;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_wysiwyg_editor_settings_alter().
|
|
*/
|
|
function linkit_wysiwyg_editor_settings_alter(&$settings, $context) {
|
|
if ($context['profile']->editor == 'ckeditor') {
|
|
$button_exists = isset($context['profile']->settings['buttons']['linkit']);
|
|
if (!empty($context['profile']->settings['default_toolbar_grouping']) && $button_exists) {
|
|
foreach ($settings['toolbar'] as &$group) {
|
|
if ($group['name'] == 'links') {
|
|
array_unshift($group['items'], 'linkit');
|
|
}
|
|
if ($group['name'] == 'other') {
|
|
if (in_array('linkit', $group['items'])) {
|
|
unset($group['items'][array_search('linkit', $group['items'])]);
|
|
// Regenerate the keys.
|
|
$group['items'] = array_values($group['items']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_ckeditor_plugin().
|
|
*/
|
|
function linkit_ckeditor_plugin() {
|
|
return array(
|
|
'linkit' => array(
|
|
// Name of the plugin used to write it
|
|
'name' => 'linkit',
|
|
// Description of plugin - it would appear in plugins managment of profile settings
|
|
'desc' => t('Support for Linkit module'),
|
|
// The full path to the CKEditor plugin directory, with trailing slash.
|
|
'path' => drupal_get_path('module', 'linkit') . '/editors/ckeditor/',
|
|
// Buttons to show up in the toolbar config area.
|
|
'buttons' => array(
|
|
'linkit' => array(
|
|
'label' => 'Linkit',
|
|
'icon' => 'icons/linkit.png',
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Add Linkit settings to pages where we have an editor element.
|
|
*/
|
|
function linkit_pre_render_editor_element($element) {
|
|
static $processed = array();
|
|
|
|
if (!isset($processed[$element['#id']])) {
|
|
global $user;
|
|
$all_formats = array_keys(filter_formats($user));
|
|
|
|
$profiles_formats = array();
|
|
|
|
$use_imce = FALSE;
|
|
|
|
// First we need to figure out which formats that the current user can access have active Linkit profiles for them.
|
|
foreach ($all_formats as $format) {
|
|
// Load the first profile that is assigned to this text format.
|
|
$profile = linkit_profile_load_by_format($format);
|
|
|
|
if ($profile) {
|
|
if (isset($profile->data['imce']) && $profile->data['imce'] == 1) {
|
|
$use_imce = TRUE;
|
|
}
|
|
$profiles_formats[$format] = array('profile' => $profile->name);
|
|
}
|
|
}
|
|
|
|
if (!empty($profiles_formats)) {
|
|
|
|
$field_js = array(
|
|
'data' => array(
|
|
'linkit' => array(
|
|
'formats' => $profiles_formats,
|
|
),
|
|
),
|
|
'type' => 'setting',
|
|
);
|
|
|
|
// Configure Linkit to have an IMCE selector.
|
|
if (module_invoke('imce', 'access') && $use_imce) {
|
|
$field_js['data']['linkit']['IMCEurl'] = url('imce', array('query' => array(
|
|
'app' => 'Linkit|sendto@Drupal.linkit.IMCECallback',
|
|
'absolute' => TRUE,
|
|
)));
|
|
// We will only serv public files with IMCE.
|
|
$field_js['data']['linkit']['publicFilesDirectory'] = variable_get('file_public_path', conf_path() . '/files');
|
|
}
|
|
|
|
// Attach the linkit_base librar
|
|
$element['#attached']['library'][] = array('linkit', 'base');
|
|
$element['#attached']['js'][] = $field_js;
|
|
|
|
$processed[$element['#id']] = TRUE;
|
|
}
|
|
}
|
|
|
|
return $element;
|
|
}
|
|
|
|
/**
|
|
* Load the first profile assigned to a text format.
|
|
*
|
|
* @param $format
|
|
* A string with the format machine name.
|
|
*
|
|
* @return
|
|
* A LinkitProfile object or FALSE if no profile is found.
|
|
*/
|
|
function linkit_profile_load_by_format($format) {
|
|
$profiles = linkit_profile_editor_load_all();
|
|
foreach ($profiles as $profile) {
|
|
if (is_array($profile->data['text_formats']) && in_array($format, array_filter($profile->data['text_formats']))) {
|
|
return $profile;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Get profile type.
|
|
*/
|
|
function linkit_get_profile_type($type) {
|
|
switch ($type) {
|
|
case LINKIT_PROFILE_TYPE_EDITOR:
|
|
return t('Editor');
|
|
case LINKIT_PROFILE_TYPE_FIELD:
|
|
return t('Field');
|
|
default:
|
|
return t('Can not find the profile type');
|
|
}
|
|
}
|
|
/**
|
|
* Gets the path processed by the inputfilter choice.
|
|
*
|
|
* @param LinkitProfile $profile
|
|
* The Linkit profile to use.
|
|
*
|
|
* @param $uri
|
|
* The uri to act on.
|
|
*
|
|
* @param $options
|
|
* An array of options to the URL function if its used.
|
|
*
|
|
* @return The processed uri.
|
|
*/
|
|
function linkit_get_insert_plugin_processed_path(LinkitProfile $profile, $uri, $options = array()) {
|
|
switch ($profile->data['insert_plugin']['url_method']) {
|
|
case LINKIT_URL_METHOD_RAW:
|
|
$path = $uri;
|
|
break;
|
|
case LINKIT_URL_METHOD_RAW_SLASH:
|
|
$options['alias'] = TRUE;
|
|
$path = url($uri, $options);
|
|
break;
|
|
case LINKIT_URL_METHOD_ALIAS:
|
|
$path = url($uri, $options);
|
|
break;
|
|
}
|
|
|
|
return $path;
|
|
}
|