linkit_profiles.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. <?php
  2. /**
  3. * @file
  4. * Ctools export ui plugin to handle Linkit profiles.
  5. */
  6. $plugin = array(
  7. 'schema' => 'linkit_profiles',
  8. 'access' => 'administer linkit',
  9. 'menu' => array(
  10. 'menu prefix' => 'admin/config/content',
  11. 'menu item' => 'linkit',
  12. 'menu title' => 'Linkit Profiles',
  13. 'menu description' => t('Manage Linkit profiles.'),
  14. ),
  15. 'title singular' => t('Linkit profile'),
  16. 'title plural' => t('Linkit profiles'),
  17. 'title singular proper' => t('Linkit profile'),
  18. 'title plural proper' => t('Linkit profiles'),
  19. 'handler' => 'linkit_profiles',
  20. );
  21. /**
  22. * Linkit profile settings form.
  23. *
  24. * @param $form
  25. * A nested array of form elements that comprise the form.
  26. * @param $form_state
  27. * An associative array containing the current state of the form.
  28. */
  29. function linkit_profiles_form(&$form, &$form_state) {
  30. $profile = $form_state['item'];
  31. // Set data as a tree.
  32. $form['data'] = array(
  33. '#tree' => TRUE,
  34. '#type' => 'vertical_tabs',
  35. );
  36. // Append profile type settings to the profile form.
  37. _linkit_build_profile_type_form_fields($form, $profile);
  38. // Append search plugin form element to the profile form.
  39. _linkit_build_search_plugin_form_fields($form, $profile);
  40. // Append insert plugin form element to the profile form.
  41. _linkit_build_insert_plugin_form_fields($form, $profile);
  42. // Append attribute plugin form element to the profile form.
  43. _linkit_build_attribute_plugin_form_fields($form, $profile);
  44. // Append IMCE plugin form element to the profile form.
  45. if (module_exists('imce')) {
  46. _linkit_build_imce_form_fields($form, $profile);
  47. }
  48. // Append autocomplete (BAC) form element to the profile form.
  49. _linkit_build_autocomplete_form_fields($form, $profile);
  50. }
  51. /**
  52. * Linkit profile validate callback.
  53. *
  54. * @see linkit_profiles_form()
  55. */
  56. function linkit_profiles_form_validate(&$form, &$form_state) {
  57. // If the profile type is field, then insert plugin is required.
  58. if ($form_state['values']['profile_type'] == LINKIT_PROFILE_TYPE_FIELD
  59. && empty($form_state['values']['data']['insert_plugin']['plugin'])) {
  60. form_set_error('data][insert_plugin][plugin', t('You have to select a insert plugin for profiles used with fields.'));
  61. }
  62. }
  63. /**
  64. * Linkit profile submit callback.
  65. *
  66. * @see linkit_profiles_form()
  67. */
  68. function linkit_profiles_form_submit(&$form, &$form_state) {
  69. // Unset some variables used by "field profiles" to make it clean.
  70. if ($form_state['values']['profile_type'] == LINKIT_PROFILE_TYPE_EDITOR) {
  71. unset($form_state['values']['data']['insert_plugin']['plugin']);
  72. }
  73. // Unset some variables used by "editor profiles" to make it clean.
  74. if ($form_state['values']['profile_type'] == LINKIT_PROFILE_TYPE_FIELD) {
  75. unset($form_state['values']['data']['text_formats']);
  76. }
  77. // Unset active tab state, we dont need to save this.
  78. unset($form_state['values']['data']['data__active_tab']);
  79. }
  80. /**
  81. * Append profile type form element to the profile form.
  82. *
  83. * @param LinkitProfile $profile
  84. * A profile object contains all settings for the profile.
  85. *
  86. * @see linkit_profiles_form()
  87. */
  88. function _linkit_build_profile_type_form_fields(&$form, LinkitProfile $profile) {
  89. $form['data']['profile_type'] = array(
  90. '#type' => 'fieldset',
  91. '#title' => t('Profile type'),
  92. '#collapsible' => TRUE,
  93. '#collapsed' => TRUE,
  94. '#tree' => FALSE,
  95. );
  96. $form['data']['profile_type']['profile_type'] = array(
  97. '#title' => t("This profile will be used with"),
  98. '#type' => 'radios',
  99. '#title_display' => 'before',
  100. '#options' => array(
  101. LINKIT_PROFILE_TYPE_EDITOR => t('Editors'),
  102. LINKIT_PROFILE_TYPE_FIELD => t('Fields'),
  103. ),
  104. LINKIT_PROFILE_TYPE_EDITOR => array(
  105. '#description' => t('This profile will be used with editors like CKeditor or TinyMCE.'),
  106. ),
  107. LINKIT_PROFILE_TYPE_FIELD => array(
  108. '#description' => t('This profile will be used with fields that do not have any editors.'),
  109. ),
  110. '#default_value' => isset($profile->profile_type) ? $profile->profile_type : 'editor',
  111. '#required' => TRUE,
  112. '#parents' => array('profile_type'),
  113. );
  114. $formats = array();
  115. foreach(filter_formats() as $format) {
  116. $formats[$format->format] = $format->name;
  117. }
  118. $form['data']['profile_type']['text_formats'] = array(
  119. '#type' => 'checkboxes',
  120. '#title' => t('Attach this profile to one or more text formats'),
  121. '#options' => $formats,
  122. '#empty_option' => t('- Select one or more text format- '),
  123. '#default_value' => isset($profile->data['text_formats'])
  124. ? $profile->data['text_formats'] : array(),
  125. '#states' => array(
  126. 'visible' => array(
  127. // While waiting for https://drupal.org/node/879580 to be commited, we
  128. // have to convert the constant to a string.
  129. 'input[name="profile_type"]' => array('value' => (string) LINKIT_PROFILE_TYPE_EDITOR),
  130. ),
  131. ),
  132. '#parents' => array('data', 'text_formats'),
  133. );
  134. }
  135. /**
  136. * Append search plugin form element to the profile form.
  137. *
  138. * @param LinkitProfile $profile
  139. * A profile object contains all settings for the profile.
  140. *
  141. * @see linkit_profiles_form()
  142. */
  143. function _linkit_build_search_plugin_form_fields(&$form, LinkitProfile $profile) {
  144. // Load all search plugins.
  145. $search_plugins = linkit_search_plugin_load_all();
  146. $form['data']['search_plugins_fieldset'] = array(
  147. '#type' => 'fieldset',
  148. '#title' => t('Search plugins'),
  149. '#description' => t('Linkit is all about the search plugins. They define what content Linkit will present in the autocomplete search field.'),
  150. '#collapsible' => TRUE,
  151. '#collapsed' => TRUE,
  152. '#tree' => FALSE,
  153. );
  154. $form['data']['search_plugins_fieldset']['search_plugins'] = array(
  155. '#markup' => '',
  156. '#tree' => TRUE,
  157. '#parents' => array('data', 'search_plugins'),
  158. '#theme' => 'linkit_plugin_form_table',
  159. );
  160. $form['data']['search_plugins_fieldset']['search_plugins_settings'] = array(
  161. '#markup' => '',
  162. '#tree' => TRUE,
  163. '#parents' => array('data'),
  164. );
  165. // Used to store plugin form elements temporary so we can use this to sort by
  166. // weight later.
  167. $tmp = array();
  168. foreach ($search_plugins AS $name => $plugin_definition) {
  169. // Get a plugin instance.
  170. $plugin = LinkitSearchPlugin::factory($plugin_definition, $profile);
  171. $tmp[$name]['name'] = array('#markup' => $plugin->ui_title());
  172. $tmp[$name]['description'] = array('#markup' => $plugin->ui_description());
  173. $tmp[$name]['enabled'] = array(
  174. '#type' => 'checkbox',
  175. '#title' => t('Enable @title', array('@title' => $plugin->ui_title())),
  176. '#title_display' => 'invisible',
  177. '#default_value' => isset($profile->data['search_plugins'][$name]['enabled'])
  178. ? $profile->data['search_plugins'][$name]['enabled'] : FALSE,
  179. );
  180. $tmp[$name]['weight'] = array(
  181. '#type' => 'weight',
  182. '#title' => t('Weight for @title', array('@title' => $plugin->ui_title())),
  183. '#title_display' => 'invisible',
  184. '#default_value' => isset($profile->data['search_plugins'][$name]['weight'])
  185. ? $profile->data['search_plugins'][$name]['weight'] : '',
  186. );
  187. // Append the search plugin specific settings.
  188. $plugin_specific_settings = $plugin->buildSettingsForm();
  189. if ($plugin_specific_settings) {
  190. // Add the handler settings form to the generic.
  191. $form['data']['search_plugins_fieldset']['search_plugins_settings'] += $plugin_specific_settings;
  192. }
  193. }
  194. // Sort by weight.
  195. uasort($tmp, '_linkit_sort_plugins_by_weight_default_value');
  196. foreach ($tmp AS $name => $element) {
  197. $form['data']['search_plugins_fieldset']['search_plugins'][$name] = $element;
  198. }
  199. }
  200. /**
  201. * Append insert plugin form element to the profile form.
  202. *
  203. * @param LinkitProfile $profile
  204. * A profile object contains all settings for the profile.
  205. *
  206. * @see linkit_profiles_form()
  207. *
  208. * @TODO: Insert pluings should only be used when dealing with fields as it
  209. * makes no sence to have them when using a wysiwyg editor.
  210. */
  211. function _linkit_build_insert_plugin_form_fields(&$form, LinkitProfile $profile) {
  212. // Make a list of all insert plugins.
  213. $insert_plugins = array();
  214. foreach (linkit_insert_plugin_load_all() as $name => $plugin) {
  215. $insert_plugins[$name] = $plugin['name'];
  216. }
  217. $form['data']['insert_plugin'] = array(
  218. '#type' => 'fieldset',
  219. '#title' => t('Insert methods'),
  220. '#description' => t(''),
  221. '#collapsible' => TRUE,
  222. '#collapsed' => TRUE,
  223. '#tree' => TRUE,
  224. );
  225. // Settings for insert plugins.
  226. $form['data']['insert_plugin']['plugin'] = array(
  227. '#type' => 'select',
  228. '#title' => t('Insert plugin'),
  229. '#options' => $insert_plugins,
  230. '#empty_option' => t('- Select an insert plugin -'),
  231. '#default_value' => isset($profile->data['insert_plugin']['plugin'])
  232. ? $profile->data['insert_plugin'] : '',
  233. '#states' => array(
  234. 'visible' => array(
  235. 'input[name="profile_type"]' => array('value' => LINKIT_PROFILE_TYPE_FIELD),
  236. ),
  237. 'required' => array(
  238. 'input[name="profile_type"]' => array('value' => LINKIT_PROFILE_TYPE_FIELD),
  239. ),
  240. ),
  241. );
  242. $form['data']['insert_plugin']['url_method'] = array(
  243. '#title' => t("Insert paths as:"),
  244. '#type' => 'radios',
  245. '#title_display' => 'before',
  246. '#options' => array(
  247. LINKIT_URL_METHOD_RAW => t('Raw paths'),
  248. LINKIT_URL_METHOD_RAW_SLASH => t('Raw paths, with a slash (/) in the beginning.'),
  249. ),
  250. LINKIT_URL_METHOD_RAW => array(
  251. '#description' => t('This will insert Drupal internal paths like
  252. %example_link which is probably what you want if you are going to use
  253. this profile together with <strong>fields</strong>.
  254. <br/>If used in textareas, these paths typically need to be formatted
  255. using a input filter, but provides more flexibility in a multilingual
  256. site or when moving a site.', array('%example_link' => 'node/123')),
  257. ),
  258. LINKIT_URL_METHOD_RAW_SLASH => array(
  259. '#description' => t('This is the default behavior, it will insert paths
  260. like %example_link.<br/>These will work <strong>without the need for an input filter</strong>,
  261. but might fail after moving a site, or on multilingual sites.',
  262. array('%example_link' => '/node/123')),
  263. ),
  264. '#default_value' => isset($profile->data['insert_plugin']['url_method']) ?
  265. $profile->data['insert_plugin']['url_method'] : LINKIT_URL_METHOD_RAW_SLASH,
  266. '#description' => t('These will have no effect on already created links.'),
  267. );
  268. if (module_exists('path')) {
  269. $form['data']['insert_plugin']['url_method']['#options'][LINKIT_URL_METHOD_ALIAS] = t('Alias paths');
  270. $form['data']['insert_plugin']['url_method'][LINKIT_URL_METHOD_ALIAS] = array(
  271. '#description' => t('This will insert the alias for the result item.
  272. <br/>The paths will be run through the <em>url()</em> function.', array('%example_link' => 'node/123')),
  273. );
  274. }
  275. }
  276. /**
  277. * Append attribute plugin form element to the profile form.
  278. *
  279. * @param LinkitProfile $profile
  280. * A profile object contains all settings for the profile.
  281. *
  282. * @see linkit_profiles_form()
  283. */
  284. function _linkit_build_attribute_plugin_form_fields(&$form, LinkitProfile $profile) {
  285. // Load all attribute plugins.
  286. $attributes = linkit_attribute_plugin_load_all();
  287. $form['data']['attribute_plugins_fieldset'] = array(
  288. '#type' => 'fieldset',
  289. '#title' => t('Attributes'),
  290. '#description' => t('Attributes are HTML attributes that will be attached to
  291. the insert plugin.'),
  292. '#collapsible' => TRUE,
  293. '#collapsed' => TRUE,
  294. '#tree' => FALSE,
  295. );
  296. $form['data']['attribute_plugins_fieldset']['attribute_plugins'] = array(
  297. '#markup' => '',
  298. '#tree' => TRUE,
  299. '#parents' => array('data', 'attribute_plugins'),
  300. '#theme' => 'linkit_plugin_form_table',
  301. );
  302. // Used to store plugin form elements temporary so we can use this to sort by
  303. // weight later.
  304. $tmp = array();
  305. foreach ($attributes AS $name => $attribute) {
  306. $tmp[$name]['name'] = array('#markup' => $attribute['name']);
  307. $tmp[$name]['enabled'] = array(
  308. '#type' => 'checkbox',
  309. '#title' => t('Enable @title', array('@title' => $attribute['name'])),
  310. '#title_display' => 'invisible',
  311. '#default_value' => isset($profile->data['attribute_plugins'][$name]['enabled'])
  312. ? $profile->data['attribute_plugins'][$name]['enabled'] : FALSE,
  313. );
  314. $tmp[$name]['weight'] = array(
  315. '#type' => 'weight',
  316. '#title' => t('Weight for @title', array('@title' => $attribute['name'])),
  317. '#title_display' => 'invisible',
  318. '#default_value' => isset($profile->data['attribute_plugins'][$name]['weight'])
  319. ? $profile->data['attribute_plugins'][$name]['weight'] : '',
  320. );
  321. }
  322. // Sort by weight.
  323. uasort($tmp, '_linkit_sort_plugins_by_weight_default_value');
  324. foreach ($tmp AS $name => $element) {
  325. $form['data']['attribute_plugins_fieldset']['attribute_plugins'][$name] = $element;
  326. }
  327. $form['data']['attribute_plugins_fieldset']['attribute_plugins_info'] = array(
  328. '#markup' => 'Keep in mind that not all attributes can be used by all insert plugins.',
  329. );
  330. }
  331. /**
  332. * Append IMCE plugin form element to the profile form.
  333. *
  334. * @param LinkitProfile $profile
  335. * A profile object contains all settings for the profile.
  336. *
  337. * @see linkit_profiles_form()
  338. */
  339. function _linkit_build_imce_form_fields(&$form, LinkitProfile $profile) {
  340. $form['data']['imce'] = array(
  341. '#type' => 'fieldset',
  342. '#title' => t('IMCE File Picker'),
  343. '#collapsible' => TRUE,
  344. '#collapsed' => TRUE,
  345. '#tree' => FALSE,
  346. '#weight' => 80,
  347. );
  348. $form['data']['imce']['use_imce'] = array(
  349. '#title' => t('Enable !imce File Picker', array('!imce' => l(t('IMCE'),
  350. 'admin/config/media/imce'))),
  351. '#type' => 'checkbox',
  352. '#description' => t('Note that only public files are supported.'),
  353. '#default_value' => isset($profile->data['imce'])
  354. ? $profile->data['imce'] : FALSE,
  355. '#parents' => array('data', 'imce'),
  356. );
  357. }
  358. /**
  359. * Append autocomplete (BAC) form element to the profile form.
  360. *
  361. * @param LinkitProfile $profile
  362. * A profile object contains all settings for the profile.
  363. *
  364. * @see linkit_profiles_form()
  365. */
  366. function _linkit_build_autocomplete_form_fields(&$form, LinkitProfile $profile) {
  367. $form['data']['autocomplete'] = array(
  368. '#type' => 'fieldset',
  369. '#title' => t('Autocomplete options'),
  370. '#description' => t('Linkit uses !bac which may be configured with a focus on
  371. performance.', array('!bac' => l(t('Better Autocomplete'),
  372. 'https://github.com/betamos/Better-Autocomplete'))),
  373. '#collapsible' => TRUE,
  374. '#collapsed' => TRUE,
  375. '#tree' => TRUE,
  376. '#weight' => 100,
  377. );
  378. $form['data']['autocomplete']['charLimit'] = array(
  379. '#title' => t('Character limit'),
  380. '#type' => 'textfield',
  381. '#default_value' => isset($profile->data['autocomplete']['charLimit']) ? $profile->data['autocomplete']['charLimit'] : LINKIT_CHAR_LIMIT,
  382. '#size' => 5,
  383. '#description' => t('Minimum number of characters to perform server polling.
  384. A higher value reduces server load. <em>Default: @default</em>', array('@default' => LINKIT_CHAR_LIMIT)),
  385. '#element_validate' => array('linkit_isnumeric_validate'),
  386. );
  387. $form['data']['autocomplete']['wait'] = array(
  388. '#title' => t('Key press delay'),
  389. '#type' => 'textfield',
  390. '#default_value' => isset($profile->data['autocomplete']['wait']) ? $profile->data['autocomplete']['wait'] : LINKIT_WAIT,
  391. '#size' => 5,
  392. '#description' => t('Time from last key press to poll the server. A higher
  393. value reduces server load. <em>Default: @default</em>', array('@default' => LINKIT_WAIT)),
  394. '#field_suffix' => t('ms'),
  395. '#element_validate' => array('linkit_isnumeric_validate'),
  396. );
  397. $form['data']['autocomplete']['remoteTimeout'] = array(
  398. '#title' => t('Remote timeout'),
  399. '#type' => 'textfield',
  400. '#default_value' => isset($profile->data['autocomplete']['remoteTimeout']) ? $profile->data['autocomplete']['remoteTimeout'] : LINKIT_REMOTE_TIMEOUT,
  401. '#size' => 5,
  402. '#description' => t('Client side timeout for a request to the server.
  403. <em>Default: @default</em>', array('@default' => LINKIT_REMOTE_TIMEOUT)),
  404. '#field_suffix' => t('ms'),
  405. '#element_validate' => array('linkit_isnumeric_validate'),
  406. );
  407. }
  408. /**
  409. * Function used by uasort to sort plugin arrays by the weight default value.
  410. */
  411. function _linkit_sort_plugins_by_weight_default_value($a, $b) {
  412. return $a["weight"]['#default_value'] >= $b["weight"]['#default_value'];
  413. }
  414. /**
  415. * Extract tokens that can be used by the $type.
  416. *
  417. * @param $type
  418. * A string with the entity type.
  419. */
  420. function linkit_extract_tokens($type) {
  421. // token_info() has it own static cache, so we can call it as we like.
  422. $tokens = token_info();
  423. // If no tokens for the type exists, return an empty array.
  424. if (!isset($tokens['tokens'][$type])) {
  425. return array();
  426. }
  427. $available_tokens = array();
  428. foreach ($tokens['tokens'][$type] as $token_key => $token) {
  429. $available_tokens[] = '[' . $type . ':' . $token_key . ']';
  430. }
  431. return $available_tokens;
  432. }
  433. /**
  434. * Element validate callback for fields that should be numeric.
  435. *
  436. * This function is assigned as an #element_validate callback in
  437. * linkit_profiles_form().
  438. */
  439. function linkit_isnumeric_validate($element, &$form_state, $form) {
  440. if (!empty($element['#value']) && !is_numeric($element['#value'])) {
  441. form_error($element, $element['#title'] . ' should only contains numbers.');
  442. }
  443. }