Glossary helps newbies understand the jargon which always crops up when specialists talk about a topic. Doctors discuss CBC and EKG and CCs. Web developers keep talking about CSS, P2P, XSLT, etc. This is all intimidating for newbies.

The Glossary module scans posts for glossary terms (and their synonyms) in the body. If found, the glossary indicator is inserted after the term, or the term is turned into an indicator link depending on the settings. By hovering over the indicator, users may learn the definition of that term. Clicking leads the user to that term presented within the whole glossary.

Glossary terms are managed as vocabularies within the taxonomy.module. To get started with glossary, create a new vocabulary on the !taxonomy_admin page. The vocabulary need not be associated with any modules, although you can add detailed description to terms by attaching (story or other type of) nodes to them. Add a few terms to the vocabulary. The term title should be the glossary entry and the description should be its definition. You can make use of the hierarchy, synonym, and related terms features. These features impact the display of the glossary when viewed in an overview.

Next, you have to set up the input formats with which you want to use the glossary. On the !input_formats page, select an input format to configure. Select the Glossary filter checkbox and press "Save configuration". Now proceed to the !glossary page and select the tab for the input format and select the vocabulary and other settings.

You can see how a vocabulary would function as a glossary by going to the !glossaries page and selecting the vocabulary to view.

Administration of glossary requires %permissions permissions.

', array('%permissions' => join(', ', array(t('administer taxonomy'), t('access administration pages'), t('administer filters'))), '!taxonomy_admin' => l(t('administer >> content >> taxonomy'), 'admin/content/taxonomy'), '!input_formats' => l(t('administer >> site configuration >> input formats'), 'admin/settings/filters'), '!glossary' => l(t('administer >> site configuration >> glossary'), 'admin/settings/glossary'), '!glossaries' => l(t('glossaries'), 'glossary'))); break; case 'admin/settings/glossary': return '

'. t('This page and its tabs allow you to control how the Glossary module functions.') .'

'; break; case 'admin/modules#description': return t('Maintain one or more glossaries on your site.'); break; } } /** * Implementation of hook_block(). */ function glossary_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $blocks = array(); $blocks[0]['info'] = t('Search for glossary terms'); return $blocks; } else if ($op == 'view') { if ($delta == 0) { $block['subject'] = t('Search Glossary'); $block['content'] = drupal_get_form('glossary_search_form'); } return $block; } } /** * Implementation of hook_requirements(). */ function glossary_requirements($phase) { $requirements = array(); // Ensure translations don't break at install time $t = get_t(); // check that php is compiled with ctype support $requirements['ctype'] = array( 'title' => $t('Character type functions (ctype)'), ); if (function_exists('ctype_alnum')) { $requirements['ctype']['value'] = $t('Enabled'); $requirements['ctype']['severity'] = REQUIREMENT_OK; } else { $requirements['ctype']['value'] = $t('Disabled'); $requirements['ctype']['description'] = $t('The Glossary module requires that you configure PHP with --enable-ctype.'); $requirements['ctype']['severity'] = REQUIREMENT_ERROR; } return $requirements; } /** * Implementation of hook_menu(). */ function glossary_menu() { $items['glossary/search'] = array( 'title' => 'Glossary Search', 'page callback' => 'glossary_search_results', 'page arguments' => array(2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['glossary/clearcache'] = array( 'title' => 'Glossary clear cache', 'page callback' => 'glossary_clearcache', 'access arguments' => array('administer filters'), 'type' => MENU_CALLBACK, ); $items['glossary'] = array( 'title' => 'Glossary', 'page callback' => 'glossary_page', 'page arguments' => array(1, 2), 'access arguments' => array('access content'), 'type' => MENU_SUGGESTED_ITEM, ); $items['admin/settings/glossary'] = array( 'title' => 'Glossary Settings', 'page callback' => 'glossary_settings_page', 'description' => 'Select how you want the Glossary module to behave.', 'access arguments' => array('administer filters'), 'type' => MENU_NORMAL_ITEM, 'file' => 'glossary.admin.inc', ); $items['admin/settings/glossary/general'] = array( 'title' => 'General', 'description' => 'General settings', 'page callback' => 'drupal_get_form', 'page arguments' => array('glossary_general_settings_form'), 'access arguments' => array('administer filters'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -3, 'file' => 'glossary.admin.inc', ); $items['admin/settings/glossary/alphabet'] = array( 'title' => 'Alphabet', 'access arguments' => array('administer filters'), 'page callback' => 'drupal_get_form', 'page arguments' => array('glossary_alphabet_form'), 'description' => 'Alphabet settings.', 'type' => MENU_LOCAL_TASK, 'weight' => 0, 'file' => 'glossary.admin.inc', ); $items['admin/settings/glossary/clearcache'] = array( 'title' => 'Clear cache', 'access arguments' => array('administer filters'), 'page callback' => 'drupal_get_form', 'page arguments' => array('glossary_clearcache_form'), 'description' => 'Clear the filter cache.', 'type' => MENU_LOCAL_TASK, 'weight' => 0, 'file' => 'glossary.admin.inc', ); $result = db_query('SELECT format, name FROM {filter_formats}'); while ($filter = db_fetch_array($result)) { $enabled = db_result(db_query("SELECT COUNT(delta) FROM {filters} WHERE format=%d AND module='glossary'", $filter['format'])); if ($enabled || !variable_get('glossary_hide_menus', false)) { $format = $filter['format']; $items['admin/settings/glossary/filter/'. $format] = array( 'title' => '!name', 'title arguments' => array('!name' => $filter['name']), 'access arguments' => array('administer filters'), 'page callback' => 'drupal_get_form', 'page arguments' => array('glossary_filter_form', 4), 'description' => 'Settings for the !name input format.', array('!name' => $filter['name']), 'weight' => 2, 'type' => MENU_LOCAL_TASK, 'file' => 'glossary.admin.inc', ); } } $items['glossary/term/%'] = array( 'title' => 'Glossary', 'page callback' => 'glossary_term', 'page arguments' => array(2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implementation of hook_init(). */ function glossary_init() { drupal_add_css(drupal_get_path('module', 'glossary') .'/glossary.css'); } /** * Implementation of hook_enable(). */ function glossary_enable() { // In order to make sure all defaults are consistent, we'll just go ahead and set them all. // This also gives us a quick-and-dirty way to reset all variables to the default settings. // Find out how many input formats are set. $filter_count = db_result(db_query('SELECT MAX( format ) FROM {filters}')); // Set all possible variables. $mypath = '/'. drupal_get_path('module', 'glossary') .'/glossary.gif'; for ($i = 0; $i <= $filter_count; ++$i) { variable_set('glossary_case_'. $i, 1); variable_set('glossary_icon_'. $i, $mypath); variable_set('glossary_match_'. $i, 'b'); variable_set('glossary_replace_'. $i, 'superscript'); variable_set('glossary_replace_all_'. $i, 0); variable_set('glossary_superscript_'. $i, 'i'); variable_set('glossary_absolute_'. $i, false); variable_set('glossary_vids_'. $i, array()); variable_set('glossary_blocking_tags_'. $i, 'acronym'); } variable_set('glossary_page_per_letter', false); variable_set('glossary_disable_indicator', false); variable_set('glossary_click_option', 0); variable_set('glossary_allow_no_description', false); variable_set('glossary_alphabet', range('a', 'z')); variable_set('glossary_digits', range('0', '9')); variable_set('glossary_hide_menus', false); variable_set('glossary_show_description', false); variable_set('glossary_suppress_unused', false); variable_set('glossary_alphabar_separator', '|'); variable_set('glossary_separate_letters', false); drupal_set_message(t('The Glossary module has been enabled with default settings. To change the settings, click here.', array('!settings_uri' => url('admin/settings/glossary')))); } function glossary_search_form($form_state, $keys = null) { $form['#action'] = url('glossary/search'); $form['#attributes'] = array('class' => 'glossary search-form'); $form['keys'] = array( '#type' => 'textfield', '#title' => '', '#default_value' => $keys, '#size' => 20, '#maxlength' => 255, ); $form['search'] = array( '#type' => 'submit', '#value' => t('Search'), ); return $form; } function glossary_search_form_submit($form, &$form_state) { $keys = trim($form_state['values']['keys']); $form_state['redirect'] = 'glossary/search/'. $keys; } function glossary_search_results($keys = null) { $vids = _glossary_get_filter_vids(); $output = '
'; $sql = "SELECT tid FROM {term_data} WHERE vid IN (". db_placeholders($vids) .") AND (description LIKE '%%%s%%' OR name LIKE '%%%s%%')"; $vars = $vids; $vars[] = $keys; $vars[] = $keys; $result = db_query($sql, $vars); $count = 0; while ($row = db_fetch_object($result)) { ++$count; $term = taxonomy_get_term($row->tid); $output .= theme('glossary_overview_item', $term, true); } if ($count == 0) { $output .= t("I'm sorry, I couldn't find any terms with that search. [@keys]", array('@keys' => $keys)); } return $output .'
'; } function theme_glossary_search_form($form) { return '
'. drupal_render($form) .'
'; } /** * Implementation of hook_theme. */ function glossary_theme() { return array( 'glossary_search_form' => array( 'arguments' => array('form'), ), 'glossary_overview_item' => array( 'arguments' => array('term', 'show_desc'), ), ); } function glossary_term($tid) { $result = db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid); $output .= '
'."\n"; while ($row = db_fetch_object($result)) { $term = taxonomy_get_term($row->tid); $output .= theme('glossary_overview_item', $term, true); $vid = $row->vid; } $output .= "
\n"; $tree = taxonomy_get_tree($vid); $alphabar = _glossary_alphabar($vid, $tree); $output = $alphabar .'
'. $output; return $output; } function glossary_filter_tips($delta, $format, $long = false) { if ($long) { return t('The Glossary module will automatically mark terms that have been defined in the glossary vocabulary with links to their descriptions. These marks depend on the settings and may be a superscript character or an icon, or the term may be turned into an acronym.'); } else { return t('Glossary terms will be automatically marked with links to their descriptions.'); } } function glossary_filter($op, $delta = 0, $format = -1, $text = "") { switch ($op) { case 'list': return array(0 => t('Glossary filter')); case 'description': return t('Maintain one or more glossaries on your site.'); case 'process': return _glossary_filter_process($format, $text); // case 'settings': // return _glossary_filter_settings($format); case 'no cache': return false; default: return $text; } } function glossary_taxonomy($op, $type, $object = null) { if ($object) { _glossary_clear_cache($object->vid); } } /** * Implementation of hook_user(). */ function glossary_user($type, $edit, $user) { switch ($type) { case 'form': // Note: this requires a setting. Do we also need to clear cache if selected? if (variable_get('glossary_disable_indicator', false)) { $form['content_glossary'] = array( '#type' => 'fieldset', '#title' => t('Glossary Indicators'), ); $form['content_glossary']['glossary_disable_indicator'] = array( '#type' => 'checkbox', '#title' => t('Disable Glossary indicators'), '#return_value' => 1, '#default_value' => $user->glossary_disable_indicator, '#description' => t('Check this box to disable the display of Glossary indicators.'), ); return $form; } break; } } function _glossary_filter_process($format, $text) { global $user; if ($user->glossary_disable_indicator && variable_get('glossary_disable_indicator', false)) { return $text; } if (variable_get("glossary_vids_$format", 0)) { $text = ' '. $text .' '; $replace_mode = variable_get("glossary_replace_$format", 'superscript'); $absolute_link = variable_get("glossary_absolute_$format", false); $terms = _glossary_get_terms($format); $vids = _glossary_get_filter_vids(); $terms_replace = array(); foreach ($terms as $term) { $term_title = $term->name .': '. strip_tags($term->description); $fragment = null; if ($term->nodes > 0) { $linkto = "taxonomy/term/$term->tid"; } elseif (!empty($vids) && (variable_get('glossary_click_option', 0) == 1)) { if (variable_get('glossary_page_per_letter', false)) { $linkto = 'glossary/'. $term->vid .'/letter'. drupal_strtolower(drupal_substr($term->name, 0, 1)); } else { $linkto = 'glossary/'. $term->vid; } $fragment = 'term'. $term->tid; } else { $linkto = 'glossary/term/'. $term->tid; } $ins_before = $ins_after = ''; switch ($replace_mode) { case 'superscript': $ins_after = l(variable_get("glossary_superscript_$format", 'i'), $linkto, array('attributes' => array('title' => $term_title, 'class' => 'glossary-indicator'), 'fragment' => $fragment, 'absolute' => $absolute_link)); break; case 'acronym link': $ins_before = ''; $ins_before .= ''; $ins_after = ''; break; case 'hovertip': $ins_before = ''; $ins_before .= ''; $ins_after = ''. $term->description .''; break; default: $img = ""; $ins_after = l($img, $linkto, array('attributes' => array('title' => $term_title, 'class' => 'glossary-icon'), 'fragment' => $fragment, 'absolute' => $absolute_link, 'html' => true)); break; } // replace term and synonyms with the desired new HTML code $terms_replace[] = array('synonyms' => $term->synonyms, 'ins_before' => $ins_before, 'ins_after' => $ins_after); } return _glossary_insertlink($format, $text, $terms_replace); } return $text; } /** * Insert glossary links to $text after every matching $terms[i]['synonyms'] that is not inside a blocking tag. * $terms[i]['ins_before'] is prepended to the matches, $terms[i]['ins_after'] is appended to them. * Match type and replace mode all depend on user settings. * The text is scanned once for all blocking tags and matches, * then those 'events' are sorted and handled one by one. */ function _glossary_insertlink($format, &$text, &$terms) { $multibyte_enabled = extension_loaded('mbstring'); if ($multibyte_enabled) { $mb_prefix = 'mb_'; } else { $mb_prefix = null; } $findfunc = $mb_prefix . (variable_get("glossary_case_$format", '1') ? 'strpos' : 'stripos'); $findtagfunc = $mb_prefix .'strpos'; $replaceall = variable_get("glossary_replace_all_$format", 0); $events = array(); // Find blocking tags. $open_tags = array('[no-glossary]', '<', '', '', '', '', '[/code]'); /* use these always/when Codefilter module is on? array('', '?]', '%>', '%]', '[/codefilter_'); */ $user_tags = explode(' ', variable_get("glossary_blocking_tags_$format", 'acronym')); foreach ($user_tags as $tag) { if (!empty($tag) && ctype_alnum($tag)) { $open_tags[] = "<$tag"; $close_tags[] = ""; } } foreach ($open_tags as $i => $tag) { $offset=0; while(($offset = $findtagfunc($text, $tag, $offset)) !== false) { //longer tags will override shorter '<' on the same offset $events[$offset] = array('type' => 'open', 'which' => $i); $offset += drupal_strlen($tag); } } // Find match candidates. foreach ($terms as $i => $term) { foreach($term['synonyms'] as $synonym) { $offset=0; $first_match_found = false; while(($offset = $findfunc($text, $synonym, $offset)) !== false) { $match = drupal_substr($text, $offset, drupal_strlen($synonym)); //only longer matches override shorter ones if (!isset($events[$offset]) || drupal_strlen($events[$offset]['match']) < drupal_strlen($match)) { // get synonym with case as in text $events[$offset] = array('type' => 'match', 'which' => $i, 'match' => $match); if (!$replaceall) { $first_match_found = true; break; } } $offset += drupal_strlen($synonym); } //TODO: remove this if we want different synonyms of the same term to be matched independently as 'first matches' if ($first_match_found && !$replaceall) { break; } } } ksort($events); $newtext = ''; $parsed = 0; // text was parsed from chars 0 to $parsed (exclusive) foreach($events as $place => $event) { // skip events inside blocking tag (they're already copied as is) if ($place < $parsed) { continue; } // copy plain text (with no events) $newtext .= drupal_substr($text, $parsed, ($place - $parsed)); $parsed = $place; // if a blocking tag is opened, skip to closing tag if ($event['type'] == 'open') { $skip = $findtagfunc($text, $close_tags[$event['which']], $place); if ($skip === false) { $skip = drupal_strlen($text); } // if the tag is [no-glossary] - remove it with the closing tag (by incrementing $parsed without copying) if ($event['which'] == 0) { $parsed += drupal_strlen($open_tags[$event['which']]); $newtext .= drupal_substr($text, $parsed, ($skip - $parsed)); $parsed = $skip + drupal_strlen($close_tags[$event['which']]); } // copy text without changing it else { $newtext .= drupal_substr($text, $parsed, ($skip - $parsed)); $parsed = $skip; } } if ($event['type'] == 'match') { $matchlen = drupal_strlen($event['match']); $proper_match = false; switch (variable_get("glossary_match_$format", 'b')) { case 'lr': // require word break left or right // $proper_match = (_glossary_is_boundary($text {$next - 1}) || _glossary_is_boundary($text {$next + $matchlen})); $proper_match = (_glossary_is_boundary(drupal_substr($text, $place - 1,1)) || _glossary_is_boundary(drupal_substr($text, $place + $matchlen, 1 ))); break; case 'b': // require word break left and right // $proper_match = (_glossary_is_boundary($text {$next - 1}) && _glossary_is_boundary($text {$next + $matchlen})); $proper_match = (_glossary_is_boundary(drupal_substr($text, $place - 1, 1)) && _glossary_is_boundary(drupal_substr($text,$place + $matchlen,1))); break; case 'l': // require word break left // $proper_match = _glossary_is_boundary($text {$next - 1}); $proper_match = _glossary_is_boundary(drupal_substr($text,$place - 1,1)); break; case 'r': // require word break right // $proper_match = _glossary_is_boundary($text {$next + $matchlen}); $proper_match = _glossary_is_boundary(drupal_substr($text,$place + $matchlen,1)); break; case 's': // match any substring default: $proper_match = true; break; } if ($proper_match) { $newtext .= $terms[$event['which']]['ins_before'] . $event['match'] . $terms[$event['which']]['ins_after']; $parsed += $matchlen; } } } // Append remaining part return $newtext . drupal_substr($text, $parsed); } function glossary_page($vid = null, $letter = null) { $vids = _glossary_get_filter_vids(); $found = false; if (!$vid) { if (count($vids) == 1) { $vid = $vids[0]; $found = true; } } else { $found = array_search($vid, _glossary_get_filter_vids()); } if (!$vid || $found === false) { $breadcrumb = array(l(t('Home'), null)); drupal_set_title(t('Glossaries')); drupal_set_breadcrumb($breadcrumb); return _glossary_list(); } else { $voc = taxonomy_vocabulary_load($vid); $breadcrumb = array(l(t('Home'), null)); if (count($vids) > 1) { $breadcrumb[] = l(t('Glossaries'), 'glossary'); } drupal_set_title(ucwords($voc->name)); drupal_set_breadcrumb($breadcrumb); return glossary_overview($voc, $letter); } } function _glossary_alphabar($vid, &$tree) { $page_per_letter = variable_get('glossary_page_per_letter', false); if (variable_get('glossary_suppress_unused', false)) { // Just make it empty; it will be filled in below. $letters = array(); } else { // array_combine is a PHP 5 function. // $letters = array_merge(variable_get('glossary_alphabet', range('a', 'z')), variable_get('glossary_digits', range('0', '9'))); // $letters = array_combine($letters, $letters); $lets = array_merge(variable_get('glossary_alphabet', range('a', 'z')), variable_get('glossary_digits', range('0', '9'))); $letters = array(); foreach($lets as $lett) { $letters[$lett] = $lett; } } foreach ($tree as $key => $term) { $x = drupal_strtolower(drupal_substr($term->name, 0, 1)); if ($page_per_letter) { $letters[$x] = l(drupal_strtoupper($x), 'glossary/'. $vid .'/letter'. $x); } else { $letters[$x] = l(drupal_strtoupper($x), 'glossary/'. $vid, array('fragment' => 'letter'. $x)); } } $sep = ' '. variable_get('glossary_alphabar_separator', '|') .' '; return '\n"; } function glossary_overview($vocab, $letter = null) { $dest = drupal_get_destination(); $tbl = get_html_translation_table(HTML_SPECIALCHARS); $tbl[' '] = '_'; $output = '
'; if ($vocab->description) { $output .= '

'. $vocab->description .'

'; } else { $output = null; } $vid = $vocab->vid; if ($letter) { $first_let = drupal_substr($letter, 6, 1, 'UTF-8'); } else { $first_let = ''; } $show_desc = variable_get('glossary_show_description', false); $tree = taxonomy_get_tree($vid); $output .= _glossary_alphabar($vid, $tree); $output .= '
'."\n"; if ($tree) { foreach ($tree as $term) { $term_let = drupal_strtolower(drupal_substr($term->name, 0, 1, 'UTF-8')); // See if it's a new section. if ($term_let != $first_let) { $output .= "\n"; if (variable_get('glossary_separate_letters', false)) { $output .= '
'. drupal_strtoupper($term_let) .'
'; } else { $output .= ''; } $first_let = $term_let; } if (!$letter || $term_let == $first_let) { $output .= theme('glossary_overview_item', $term, $show_desc, $dest); } } } $output .= '
'; $output .= glossary_admin_links($vocab, $dest); return $output .'
'; } function theme_glossary_overview_item($term, $show_desc = true, $dest = null) { $click_option = variable_get('glossary_click_option', 0); if (isset($term->firstletter)) { $output .= "\n".''; } $output .= ''; if (module_exists('taxonomy_image') && $show_desc) { $img = taxonomy_image_display($term->tid); if (!$img && variable_get('taxonomy_image_wrapper', false)) { $mypath = '/'. drupal_get_path('module', 'glossary') .'/empty.gif'; $img = '
'; } } else { $img = null; } $output .= '
'. $img; if ($show_desc) { $output .= $term->name .' '; } else { $output .= l($term->name, 'glossary/term/'. $term->tid) .' '; } $links = array(); if (user_access('administer taxonomy')) { $links['glossary-edit-term'] = array( 'title' => t('edit term'), 'href' => 'admin/content/taxonomy/edit/term/'. $term->tid, 'attributes' => array('title' => t('edit this term and definition')), ); } if (user_access('search content')) { $links['glossary-search-term'] = array( 'title' => t('search for term'), 'href' => 'search/node/"'. $term->name .'"', 'attributes' => array('title' => t('search for content using this term')), ); } if (!empty($links)) { $output .= theme('links', $links, array('class' => 'links inline')); } $output .= '
'; if ($show_desc) { $detailed_exists = db_result(db_query('SELECT COUNT(t.nid) FROM {term_node} t JOIN {node} n USING (nid) WHERE t.tid=%d AND n.status=1', $term->tid)); if ($detailed_exists) { $output .= l(t('Detailed definition of @term', array('@term' => $term->name)), "taxonomy/term/$term->tid"); } else { $output .= $term->description; } if ($relations = taxonomy_get_related($term->tid, "name")) { $output .= "". t("See also") .": "; foreach ($relations as $related) { if ($click_option == 1) { $items[] .= l($related->name, 'glossary/'. $term->vid, array('fragment' => "term". $related->tid)); } else { $items[] .= l($related->name, 'glossary/term/'. $related->tid); } } $output .= implode(', ', $items) ."\n"; unset($items); } } $output .= "
\n"; return $output; } function glossary_admin_links($vocabulary, $destination) { $output = ''; } function _glossary_list() { $output = ""; $vids = _glossary_get_filter_vids(); $vocs = array(); foreach ($vids as $vid) { $voc = taxonomy_vocabulary_load($vid); $vocs[$voc->name] = $voc; } uksort($vocs, _glossary_cmp_strcase); $header = array(t("Glossary"), t('Operations')); $rows = array(); foreach ($vocs as $voc) { $row = array(); $row[0] = $voc->name; $row[1] = l(t('view'), "glossary/". $voc->vid); if (user_access('administer taxonomy')) { $row[1] .= " ". l(t('edit'), "admin/content/taxonomy"); } $rows[] = $row; } $output = theme('table', $header, $rows); return $output; } function _glossary_get_terms($format) { static $terms = false; $show_all = variable_get('glossary_allow_no_description', false); if ($terms === false) { $terms = $synonyms = array(); $vids = variable_get("glossary_vids_$format", 0); foreach ($vids as $vid) { // $vocab = taxonomy_vocabulary_load($vid); $synonyms = _glossary_get_synonyms($vid); // Get all glossary terms and attach synonyms. // Omit terms without a description. those are usually container terms. $result = db_query("SELECT t.name, t.description, t.tid, COUNT(tn.nid) as nodes FROM {term_data} t LEFT JOIN {term_node} tn USING(tid) WHERE t.vid=%d GROUP BY t.tid, t.name, t.description ORDER BY LENGTH(t.name) DESC", $vid); while ($term = db_fetch_object($result)) { if ($term->nodes) { // If there were any nodes attached, we need to see if they were unpublished. $unpubs = db_result(db_query("SELECT COUNT(n.nid) FROM {term_node} t JOIN {node} n USING (nid) WHERE t.tid=%d AND n.status=0", $term->tid)); $term->nodes -= $unpubs; } if ($term->description || $show_all) { $term->synonyms = $synonyms[$term->tid]; $term->synonyms[] = $term->name; $term->vid = $vid; $terms[] = $term; } } } } return $terms; } // Get all synonyms for all glossary terms function _glossary_get_synonyms($vid) { $result = db_query("SELECT ts.tid, ts.name FROM {term_synonym} ts, {term_data} t WHERE ts.tid = t.tid AND t.vid = %d", $vid); while ($synonym = db_fetch_object($result)) { $synonyms[$synonym->tid][] = $synonym->name; } return $synonyms; } // This seems to be 1.2 times faster in fine-grained testing then // the ereg solution used before. The chars used here are from the // grep info page. function _glossary_is_boundary($char) { if (extension_loaded('mbstring')) { return (mb_strpos("!\"#\$%&'()*+,-./:;<=>?@[\]^_`{|}~ \t\n\r", $char) !== false); } else { return (strpos("!\"#\$%&'()*+,-./:;<=>?@[\]^_`{|}~ \t\n\r", $char) !== false); } } // Natively only available in PHP 5+ // WARNING: Eats a tremendous amount of memory! if (!function_exists("stripos")) { function stripos($haystack, $needle, $offset = 0) { return strpos(drupal_strtoupper($haystack), drupal_strtoupper($needle), $offset); } } if (!function_exists("mb_stripos")) { function mb_stripos($haystack, $needle, $offset = 0) { return mb_strpos(drupal_strtoupper($haystack), drupal_strtoupper($needle), $offset); } } // Menu call back for clear cache button on settings page. function glossary_clearcache_form() { $form['submit'] = array( '#type' => 'submit', '#value' => t('Clear cache'), ); $form['#submit']['_glossary_clear_cache'] = array(); return $form; } // Menu call back for link on settings page. function glossary_clearcache() { cache_clear_all('*', 'cache_filter', TRUE); drupal_set_message(t('Cache_filter cleared.')); drupal_goto('/glossary'); } function _glossary_clear_cache($format=null) { // We could throw less things away if we checked which filter formats // used the glossary filter, and we only threw those away. In practice, // most if not all formats would use the glossary filter, so we just // get rid of them all. if ($format) { $wildcard = $format .':'; } else { $wildcard = '*'; } cache_clear_all($wildcard, 'cache_filter', true); drupal_set_message(t('The filter cache has been cleared. There may be a temporary performance degradation while it is rebuilt.')); } function _glossary_get_filter_vids() { // We can't use filter_formats() here, because we need all input formats, // not just those we are allowed to post in. $vids = array(); $result = db_query('SELECT format FROM {filter_formats}'); while ($format = db_fetch_object($result)) { $filters = filter_list_format($format->format); foreach ($filters as $filter) { if ($filter->module == "glossary") { $vids = array_merge($vids, variable_get("glossary_vids_". $format->format, array())); } } } return array_unique($vids); } function _glossary_cmp_strcase($a, $b) { return strcmp(drupal_strtolower($a), drupal_strtolower($b)); }