/[drupal]/contributions/modules/contextlinks/contextlinks.module
ViewVC logotype

Contents of /contributions/modules/contextlinks/contextlinks.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.11 - (show annotations) (download) (as text)
Thu Feb 22 03:01:05 2007 UTC (2 years, 9 months ago) by jhriggs
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +5 -5 lines
File MIME type: text/x-php
merge from DRUPAL-5
1 <?php
2 // $Id: contextlinks.module,v 1.10.2.1 2007/02/22 02:59:35 jhriggs Exp $
3
4 /**
5 * The context links module provides a link -- internal or external --
6 * to more information on a given word, phrase, or acronym. Different
7 * classes of these links can be created, each being identified by a
8 * different icon, string, or both. Examples of classes are help,
9 * info, warning, etc.
10 *
11 * Links are inserted into content using markup that looks like this:
12 * "[?:some/link The Link Text]" or
13 * "[?info:http://some.external.site/link Other Link Text]". The
14 * former uses a relative link with the provided text and the default
15 * class. The latter uses an absolute link with the provided text,
16 * using the "info" class. The link can be created on the text itself
17 * or by using an icon/image or string before or after the text. The
18 * text provided will be placed inside a span tag with a class of
19 * "contextlinks contextlinks-<class>" so that text can be modified with style
20 * sheets if desired.
21 *
22 * @version $Id: contextlinks.module,v 1.10.2.1 2007/02/22 02:59:35 jhriggs Exp $
23 * @copyright Copyright (c) 2004-2007 Jim Riggs. All rights reserved.
24 * @author Jim Riggs <drupal at jim and lissa dot com>
25 */
26
27 /********************************************************************
28 * Drupal Hooks
29 ********************************************************************/
30
31 /**
32 * Implementation of hook_perm().
33 */
34 function contextlinks_perm() {
35 return array('administer contextlinks');
36 }
37
38 /**
39 * Implementation of hook_menu().
40 */
41 function contextlinks_menu($may_cache) {
42 $items = array();
43
44 if (!$may_cache) {
45 $path = drupal_get_path('module', 'contextlinks');
46
47 drupal_add_css("$path/contextlinks.css");
48 drupal_add_js("$path/contextlinks.js");
49 }
50
51 if ($may_cache) {
52 $items[] = array(
53 'path' => 'admin/settings/contextlinks',
54 'title' => t('Context links'),
55 'description' => t('Create and configure context links classes.'),
56 'access' => user_access('administer contextlinks'),
57 'callback' => 'drupal_get_form',
58 'callback arguments' => array('_contextlinks_admin_settings')
59 );
60 $items[] = array(
61 'path' => 'admin/settings/contextlinks/overview',
62 'title' => t('Overview'),
63 'type' => MENU_DEFAULT_LOCAL_TASK,
64 'weight' => -10
65 );
66 $items[] = array(
67 'path' => 'admin/settings/contextlinks/add',
68 'title' => t('Add'),
69 'callback' => 'drupal_get_form',
70 'callback arguments' => array('_contextlinks_admin_form'),
71 'type' => MENU_LOCAL_TASK
72 );
73 $items[] = array(
74 'path' => 'admin/settings/contextlinks/edit',
75 'title' => t('Edit'),
76 'callback' => 'drupal_get_form',
77 'callback arguments' => array('_contextlinks_admin_form'),
78 'type' => MENU_CALLBACK
79 );
80 $items[] = array(
81 'path' => 'admin/settings/contextlinks/delete',
82 'title' => t('Delete'),
83 'callback' => 'drupal_get_form',
84 'callback arguments' => array('_contextlinks_admin_delete'),
85 'type' => MENU_CALLBACK
86 );
87 }
88
89 return $items;
90 }
91
92 /**
93 * Implementation of hook_filter().
94 */
95 function contextlinks_filter($op, $delta = 0, $format = -1, $text = '') {
96 switch ($op) {
97 case 'list':
98 return array(t('Context links'));
99
100 case 'description':
101 return t('Allows filtered input of various types of informational, context-related links.');
102
103 case 'process':
104 return _contextlinks_process($text);
105
106 default:
107 return $text;
108 }
109 }
110
111 /**
112 * Implementation of hook_filter_tips().
113 */
114 function contextlinks_filter_tips($delta, $format, $long = FALSE) {
115 if ($long) {
116 $output = t('
117 <h1 id="contextlinks">Context Links Help</h1>
118
119 <p>
120 The context links module allows you to easily create links to
121 context-related material using a simple markup syntax. The links
122 are indicated by either linking the text itself or by inserting a
123 specific string or icon that links to the related information.
124 </p>
125
126 <p>
127 Site administrators can define different "classes" of context
128 links. Each class can have a specific icon or string that is used
129 for all instances of that class. Additionally, administrators
130 define a default class which will be used if no class is specified.
131 </p>
132
133 <p>
134 The syntax to insert context links is as follows:
135 </p>
136
137 <p>
138 <code>[?<i><b>class</b></i>:<i><b>URL</b></i> <i><b>link text</b></i>]</code><br />
139 or, to use the default class,<br />
140 <code>[?:<i><b>URL</b></i> <i><b>link text</b></i>]</code>
141 </p>
142
143 <p>
144 Notes:
145 </p>
146
147 <ul>
148 <li>The URL can be relative (some/link), linking to information on
149 the same site, or fully-qualified (http://some.site/), linking to
150 information on another site.</li>
151 <li>The URL can optionally be preceded with a ^ (caret) to force the
152 link to open in a new window or a ` (backtick) to force the link to
153 open in the current window (if the class defaults to opening in a
154 new window).</li>
155 <li>To include a right bracket in the URL or text of a context
156 link, it must be "escaped" by preceding it with a backslash (\\]).
157 Likewise, to use a backslash it must be escaped also (\\\\).</li>
158 </ul>
159
160 <p>
161 The table below shows examples of all of the classes currently
162 defined on this site.
163 </p>
164 ');
165
166 $default = variable_get('contextlinks_default', NULL);
167 $header = array(t('class'), t('new<br />window'), t('input'), t('output'));
168 $rows = array();
169 $result = db_query("SELECT cc.* FROM {contextlinks_class} cc ORDER BY cc.name");
170 $example_text = t('example');
171
172 while ($class = db_fetch_object($result)) {
173 $text = t('An %example link.', array('%example' => "[?$class->name:filter/tips $example_text $class->name]"));
174
175 if ($class->cid == $default) {
176 $class->name .= '<br /><i><b>*' . t('default') . '*</b></i>';
177 $text .= '<br />' . t('A %example using the default class.', array('%example' => '[?:filter/tips ' . t('link') . ']'));
178 }
179
180 $rows[] = array($class->name, ($class->new_window ? t('Yes') : t('No')), $text, _contextlinks_process($text));
181 }
182
183 return $output . theme('table', $header, $rows);
184 }
185 else {
186 return t('You can use !context links in the text to create context-related links to pages or sites that provide additional information about a word or phrase.', array('!context links' => l(t('context links'), 'filter/tips', NULL, NULL, 'contextlinks')));
187 }
188 }
189
190 /**
191 * Implementation of hook_help().
192 */
193 function contextlinks_help($section = 'admin/help#contextlinks') {
194 switch ($section) {
195 case 'admin/help#contextlinks':
196 return t('
197 <p>
198 The context links module allows users to create
199 contextual/informational links within posts. The links may be
200 created on the input text itself, or an icon, a string, or both may
201 be insterted before or after the text and linked to the provided
202 URL.
203 </p>
204
205 <p>
206 Management of context links classes is handled using the
207 admin/settings/contextlinks page. The "overview" provides a list
208 of all context links classes and allows for editing and deleting
209 existing classes.
210 </p>
211 ');
212
213 case 'admin/settings/contextlinks':
214 return t('
215 <p>
216 The table below the status table lists all context links classes on
217 this site. Context links classes may be edited or deleted using the
218 links provided.
219 </p>
220 ');
221
222 case 'admin/settings/contextlinks/add':
223 return t('
224 <p>
225 Use the form below to add a context links class to this site.
226 </p>
227 ');
228 }
229 }
230
231 /********************************************************************
232 * Module Functions
233 ********************************************************************/
234
235 /**
236 * Returns the filtered version of the provided string, replacing all
237 * context links markup with the appropriate linked images/text.
238 *
239 * @param $text
240 * The string specifying the text to be processed.
241 *
242 * @return
243 * A string containing the filtered version of the
244 * provided text.
245 */
246 function _contextlinks_process($text) {
247 return preg_replace_callback('/
248 \[\? # opening bracket
249 ([a-zA-Z0-9_-]*) # $1 -- class name
250 : # class, url delimiter
251 (\^|`)? # $2 -- optional bypass of link target
252 ([^\s\]]+) # $3 -- url
253 \s+ # url, text delimiter
254 ((?:\\\\.|[^\]\\\\])+) # $4 -- text: escaped chars, not right bracket or backslash
255 \] # closing bracket
256 /x', '_contextlinks_callback', $text);
257 }
258
259 /**
260 * Returns the replacement text for the matching context links RE
261 * provided. Called as a callback from _contextlinks_process().
262 *
263 * @param $matches
264 * The array containing the matching subexpressions
265 * from the context links RE in _contextlinks_process().
266 *
267 * @return
268 * A string containing the replacement text appropriate
269 * for the provided matching subexpressions.
270 */
271 function _contextlinks_callback($matches) {
272 static $classes = FALSE;
273
274 if ($classes === FALSE) {
275 $classes = array();
276 }
277
278 $class = strtolower($matches[1]);
279
280 switch ($matches[2]) {
281 case '^':
282 $rel = 'CONTEXTLINKS_NEW_WINDOW';
283 break;
284
285 case '`':
286 $rel = '';
287 break;
288 }
289
290 if (!$class) {
291 $class = db_result(db_query("SELECT cc.name FROM {contextlinks_class} cc WHERE cc.cid = %d", variable_get('contextlinks_default', NULL)));
292 }
293
294 if ($classes[$class]) {
295 $url = url(str_replace('{}', $matches[3], $classes[$class]['url_template']));
296 $text = preg_replace('/\\\\(.)/', '$1', $matches[4]);
297
298 $rel = (isset($rel) ? $rel : $classes[$class]['rel']);
299 $rel = ($rel ? " rel=\"$rel\"" : '');
300
301 return str_replace(array('{URL}', '{TARGET}', '{TEXT}'), array($url, $rel, $text), $classes[$class]['markup']);
302 }
303
304 $class = db_fetch_object(db_query("SELECT cc.* FROM {contextlinks_class} cc WHERE cc.name = '%s'", $class));
305
306 if (!$class) {
307 return $matches[0];
308 }
309
310 if ($class->image) {
311 $class->image = url($class->image);
312 $markup = "<img src=\"$class->image\" alt=\"$class->name\" />";
313 }
314
315 $matches2 = array();
316
317 if ($class->string) {
318 preg_match('/^([\(\[\{])?(.+?)([\)\]\}])?$/', $class->string, $matches2);
319
320 $markup .= ($markup ? ' ' : '') . $matches2[2];
321 }
322
323 if (!$class->url_template || (strpos($class->url_template, '{}') === FALSE)) {
324 $class->url_template .= '{}';
325 }
326
327 if (!$markup) {
328 $markup = '<span class="contextlinks-text"><a href="{URL}"{TARGET}>{TEXT}</a></span>';
329 }
330 else {
331 $text_mark = '<span class="contextlinks-text">' . ($class->link_text ? '<a href="{URL}"{TARGET}>{TEXT}</a>' : '{TEXT}') . '</span>';
332 $markup = $matches2[1] . '<a href="{URL}"{TARGET}>' . $markup . '</a>' . $matches2[3];
333 $markup = ($class->position ? "$text_mark $markup" : "$markup $text_mark");
334 }
335
336 $markup = "<span class=\"contextlinks contextlinks-$class->name\">$markup</span>";
337
338 $classes[$class->name]['rel'] = ($class->new_window ? 'CONTEXTLINKS_NEW_WINDOW' : '');
339 $classes[$class->name]['url_template'] = $class->url_template;
340 $classes[$class->name]['markup'] = $markup;
341
342 return _contextlinks_callback($matches);
343 }
344
345 /**
346 * Displays the context links class table.
347 *
348 * @return
349 * An array containing the form elements to be displayed.
350 */
351 function _contextlinks_admin_settings() {
352 $result = db_query("SELECT cc.cid, cc.name FROM {contextlinks_class} cc ORDER BY cc.name");
353 $names = array();
354
355 while ($class = db_fetch_object($result)) {
356 $names[$class->cid] = '';
357 }
358
359 $form = array();
360 $form['contextlinks_default'] = array(
361 '#type' => 'radios',
362 '#default_value' => variable_get('contextlinks_default', NULL),
363 '#options' => $names,
364 );
365 $form['submit'] = array(
366 '#type' => 'submit',
367 '#value' => t('Set default')
368 );
369
370 return $form;
371 }
372
373 /**
374 * Sets the default class.
375 *
376 * @param $form_id
377 * The string specifying the form ID of the form that was submitted.
378 * @param $form_values
379 * The array specifying the form values.
380 */
381 function _contextlinks_admin_settings_validate($form_id, $form_values) {
382 variable_set('contextlinks_default', $form_values['contextlinks_default']);
383 cache_clear_all('*', 'cache_filter', TRUE);
384 cache_clear_all('*', 'cache_page', TRUE);
385 }
386
387 /**
388 * Renders the class list, including the default column.
389 *
390 * @param $form
391 * The array specifying the form to be rendered.
392 *
393 * @result
394 * The formatted HTML table of classes.
395 */
396 function theme__contextlinks_admin_settings($form) {
397 $positions = array(t('before'), t('after'));
398 $header = array(t('Default'), array('data' => t('Class'), 'field' => 'name', 'sort' => 'asc'), t('URL template/image/text'), array('data' => t('Position'), 'field' => 'position'), array('data' => t('New Window'), 'field' => 'new_window'), array('data' => t('Link text'), 'field' => 'link_text'), array('data' => t('Operations')));
399 $rows = array();
400 $result = db_query("SELECT cc.* FROM {contextlinks_class} cc" . tablesort_sql($header));
401
402 while ($class = db_fetch_object($result)) {
403 $image = ($class->image ? url($class->image) : '');
404 $rows[] = array(
405 array('data' => drupal_render($form['contextlinks_default'][$class->cid]), 'align' => 'center'),
406 $class->name,
407 (($class->url_template ? $class->url_template : t('&lt;no template&gt;')) . '<br />' . ($class->image ? "$class->image <img src=\"$image\" alt=\"?\" style=\"width: 1.2em; height: 1.2em;\" />" : t('&lt;no image&gt;')) . '<br />' . ($class->string ? $class->string : t('&lt;no text&gt;'))), $positions[$class->position], ($class->new_window ? t('Yes') : t('No')), ($class->link_text ? t('Yes') : t('No')), l(t('edit'), "admin/settings/contextlinks/edit/$class->cid") . ' ' . l(t('delete'), "admin/settings/contextlinks/delete/$class->cid"));
408 }
409
410 $output = theme('table', $header, $rows);
411 $output .= drupal_render($form);
412
413 return $output;
414 }
415
416 /**
417 * Creates a form for adding or editing a link class.
418 *
419 * @return
420 * A string containing the HTML-formatted form.
421 */
422 function _contextlinks_admin_form($cid = 0) {
423 if ($cid) {
424 $class = db_fetch_object(db_query("SELECT cc.* FROM {contextlinks_class} cc WHERE cc.cid = %d", $cid));
425 }
426
427 $form = array();
428 $form['name'] = array(
429 '#type' => 'textfield',
430 '#title' => t('Class name'),
431 '#default_value' => $class->name,
432 '#size' => 16,
433 '#maxlength' => 16,
434 '#description' => t('The name of this class. The name must be unique and can only contain letters, numbers, dash, and underscore.'),
435 '#required' => TRUE
436 );
437 $form['url_template'] = array(
438 '#type' => 'textfield',
439 '#title' => t('URL template'),
440 '#default_value' => $class->url_template,
441 '#description' => t('Optional. The link template to be used for this class. For example, a template of %http://www.google.com/search?q= with a context link of [?google:foo search for foo] will result in a link of %http://www.google.com/search?q=foo by appending "foo" to the template. Alternatively, the placeholder %{} can be used to specify the location of the context link portion of the URL within the template (i.e. %http://www.google.com/search?q={}&hl=en&lr=lang_sr, %http://my.site/node/{}/edit).', array('%http://www.google.com/search?q=' => 'http://www.google.com/search?q=', '%http://www.google.com/search?q=foo' => 'http://www.google.com/search?q=foo', '%{}' => '{}', '%http://www.google.com/search?q={}&hl=en&lr=lang_sr' => 'http://www.google.com/search?q={}&hl=en&lr=lang_sr', '%http://my.site/node/{}/edit' => 'http://my.site/node/{}/edit'))
442 );
443 $form['link_text'] = array(
444 '#type' => 'checkbox',
445 '#title' => t('Link text'),
446 '#default_value' => $class->link_text,
447 '#description' => t('Whether on not this class should make the text of the context link a link also. If neither an image nor a string is specified, this option will be implied.')
448 );
449 $form['new_window'] = array(
450 '#type' => 'checkbox',
451 '#title' => t('Open new window'),
452 '#default_value' => $class->new_window,
453 '#description' => t('Whether on not this class should open links in a new window by default. This setting can be overridden in any given link by preceding the URL with a ^ (new window) or ` (current window).')
454 );
455 $form['image_text'] = array(
456 '#type' => 'fieldset',
457 '#title' => t('Image and text'),
458 '#description' => '<h3>' . t('Note') . '</h3>' . t('An image URL, text string, or both may be entered below. If present, these items will become the link. If neither is specified or if the "Link text" option is selected, the text of the context link itself will become the link.')
459 );
460 $form['image_text']['image'] = array(
461 '#type' => 'textfield',
462 '#title' => t('Image URL'),
463 '#default_value' => $class->image,
464 '#description' => t('The URL of the image to be displayed before or after this link class.')
465 );
466 $form['image_text']['string'] = array(
467 '#type' => 'textfield',
468 '#title' => t('Text'),
469 '#default_value' => $class->string,
470 '#description' => t('A string to be displayed before or after this link class. If desired, the string can be enclosed in brackets, braces, or parentheses. Only the text inside these pairs will be linked.')
471 );
472 $form['image_text']['position'] = array(
473 '#type' => 'radios',
474 '#title' => t('Position'),
475 '#default_value' => (isset($class->position) ? $class->position : 1),
476 '#options' => array(t('Before'), t('After')),
477 '#description' => t('Whether the link image or text string appears before or after the text.')
478 );
479 $form['submit'] = array(
480 '#type' => 'submit',
481 '#value' => t('Submit')
482 );
483 $form['cid'] = array(
484 '#type' => 'value',
485 '#value' => $cid);
486
487 return $form;
488 }
489
490 /**
491 * Validates a new or modified link class.
492 *
493 * @param $form_id
494 * The form ID of the form data.
495 * @param $form_values
496 * The form values passed from the form.
497 */
498 function _contextlinks_admin_form_validate($form_id, $form_values) {
499 if (!preg_match('/^[a-z0-9_-]+$/', trim($form_values['name']))) {
500 form_set_error('name', t('Please enter a class name consisting of only a-z, 0-9, _, and -.'));
501 }
502
503 $template = str_replace('{}', 'foo', $form_values['url_template']);
504
505 if (!valid_url($template, TRUE) && !valid_url($template, FALSE)) {
506 form_set_error('url_template', t('Please enter a valid template URL.'));
507 }
508
509 if ($form_values['image'] && !valid_url($form_values['image'], TRUE) && !valid_url($form_values['image'], FALSE)) {
510 form_set_error('image', t('Please enter a valid image URL.'));
511 }
512 }
513
514 /**
515 * Saves a new or modified link class into the database.
516 *
517 * @param $form_id
518 * The form ID of the form data.
519 * @param $form_values
520 * The form values passed from the form.
521 */
522 function _contextlinks_admin_form_submit($form_id, $form_values) {
523 $position = ($form_values['position'] ? 1 : 0);
524 $target = ($form_values['new_window'] ? 1 : 0);
525 $link_text = (($form_values['link_text'] || (!$image && !$string)) ? 1 : 0);
526
527 if ($form_values['cid']) {
528 db_query("UPDATE {contextlinks_class} SET name = '%s', position = %d, new_window = %d, image = '%s', string = '%s', link_text = %d, url_template = '%s' WHERE cid = %d", $form_values['name'], $position, $target, $form_values['image'], $form_values['string'], $link_text, $form_values['url_template'], $form_values['cid']);
529 }
530 else {
531 db_query("INSERT INTO {contextlinks_class} (cid, name, position, new_window, image, string, link_text, url_template) VALUES (%d, '%s', %d, %d, '%s', '%s', %d, '%s')", db_next_id('{contextlinks}_cid'), $form_values['name'], $position, $target, $form_values['image'], $form_values['string'], $link_text, $form_values['url_template']);
532 }
533
534 cache_clear_all('*', 'cache_filter', TRUE);
535 cache_clear_all('*', 'cache_page', TRUE);
536 drupal_set_message(t('Class %name successfully saved.', array('%name' => $name)));
537
538 return 'admin/settings/contextlinks';
539 }
540
541 /**
542 * Deletes a context links class.
543 *
544 * @param $cid
545 * The class ID of the class to delete.
546 */
547 function _contextlinks_admin_delete($cid) {
548 $class = db_result(db_query('SELECT cc.name FROM {contextlinks_class} cc WHERE cc.cid = %d', $cid));
549
550 $form = array();
551 $form['cid'] = array(
552 '#type' => 'value',
553 '#value' => $cid
554 );
555 $form['class_name'] = array(
556 '#type' => 'value',
557 '#value' => $class
558 );
559
560 return confirm_form($form, t('Are you sure you want to permanently delete the context links class %name?', array('%name' => $class)), 'admin/settings/contextlinks', t('Any existing content that uses this class will not be formatted. This cannot be undone.'), t('Delete'));
561 }
562
563 /**
564 * Deletes the specified class.
565 *
566 * @param $form_id
567 * The string specifying the form ID of the form that was submitted.
568 * @param $form_values
569 * The array specifying the form values.
570 */
571 function _contextlinks_admin_delete_submit($form_id, $form_values) {
572 db_query("DELETE FROM {contextlinks_class} WHERE cid = %d", $form_values['cid']);
573 cache_clear_all('*', 'cache_filter', TRUE);
574 cache_clear_all('*', 'cache_page', TRUE);
575 drupal_set_message(t('Class %name successfully deleted.', array('%name' => $form_values['class_name'])));
576
577 return 'admin/settings/contextlinks';
578 }
579
580 ?>

  ViewVC Help
Powered by ViewVC 1.1.2