Parent Directory
|
Revision Log
|
Revision Graph
First experimental version for Drupal 6
| 1 | <?php |
| 2 | /** |
| 3 | * This defines a node-based glossary module, |
| 4 | * as opposed to the term-based glossary module in drupal 4.6/4.7 |
| 5 | * Copyright (C) 2005-2006 Frederic G. MARAND |
| 6 | * Licensed under the CeCILL, version 2 |
| 7 | * $Id: g2.module,v 1.18 2007/05/20 15:40:34 fgm Exp $ |
| 8 | * @todo split settings form with local tabs |
| 9 | * @todo convert to class format, rename constants |
| 10 | */ |
| 11 | |
| 12 | $_g2_er = error_reporting(E_ALL | E_STRICT); |
| 13 | |
| 14 | /** |
| 15 | * Constants missing from older node.module versions (still missing from node.module 1.582, see http://drupal.org/node/43355) |
| 16 | */ |
| 17 | if (!defined('NODE_PUBLISHED')) |
| 18 | { |
| 19 | define('NODE_NOT_PUBLISHED', 0); |
| 20 | define('NODE_PUBLISHED', 1) ; |
| 21 | define('NODE_NOT_IN_MODERATION', 0); // moderate |
| 22 | define('NODE_IN_MODERATION', 1); |
| 23 | define('NODE_NOT_PROMOTED', 0); // promote |
| 24 | define('NODE_PROMOTED', 1); |
| 25 | define('NODE_NOT_STICKY', 0); // sticky |
| 26 | define('NODE_STICKY', 1); |
| 27 | } |
| 28 | |
| 29 | /** |
| 30 | * G2 various constants |
| 31 | */ |
| 32 | define('G2NODETYPE', 'g2_entry'); |
| 33 | define('G2PERMVIEW', 'view g2 entries'); |
| 34 | define('G2PERMADMIN', 'administer g2 entries'); |
| 35 | define('G2VERSION', '$Id: g2.module,v 1.18 2007/05/20 15:40:34 fgm Exp $'); |
| 36 | |
| 37 | /** |
| 38 | * G2 menu information |
| 39 | */ |
| 40 | define('G2PATHSETTINGS', 'admin/settings/g2'); |
| 41 | define('G2PATHAUTOCOMPLETE', 'g2/autocomplete'); |
| 42 | define('G2PATHENTRIES', 'g2/entries'); |
| 43 | define('G2PATHINITIAL', 'g2/initial'); |
| 44 | define('G2PATHNODEADD', 'node/add/' . G2NODETYPE); /// @see g2_form |
| 45 | define('G2PATHWOTDFEED', 'g2/wotd/feed'); |
| 46 | define('G2PATHREFERERWIPE', 'g2/wipe'); |
| 47 | define('G2TITLEAUTOCOMPLETE', t('entry autocomplete')); |
| 48 | define('G2TITLEENTRIES', t('G2 entries by name')); |
| 49 | define('G2TITLEINITIAL', t('entries starting by initial %initial')); |
| 50 | define('G2TITLEMAIN', t('G2 glossary main page')); |
| 51 | define('G2TITLEWOTDFEED', t('G2 word of the day RSS feed')); |
| 52 | define('G2TITLEREFERERWIPE', t('Wipe all G2 referer information')); |
| 53 | |
| 54 | /** |
| 55 | * G2 settings and block configuration, persisted in {variable} |
| 56 | */ |
| 57 | define('G2VARALPHABAR', 'g2_alphabar'); // Alphabar block: list of the one-symbol initials being displayed |
| 58 | define('G2VARALPHABARROWLEN', 'g2_alphabar_rowlen');// Alphabar block: row length of the themed alphabar |
| 59 | define('G2VARALPHABARTITLE', 'g2_alphabar_title'); // Alphabar block: title |
| 60 | define('G2VARGOTOSINGLE', 'g2_goto_single'); // Automatically go to the match on an "entries" page if only one exists |
| 61 | define('G2VARHIDDENTITLE', 'g2_hidden_title'); // Does hook_view include a hidden version of title for hook_update_index |
| 62 | define('G2VARHOMONYMS', 'g2_homonyms'); // disambiguation page for homonyms |
| 63 | define('G2VARHOMONYMSREDIRECT', 'g2_homonyms_redirect');// The HTTP 30x code to be used for automatic redirects |
| 64 | define('G2VARHOMONYMSVID', 'g2_homonyms_vid'); // disambiguation vocabulary id for homonyms |
| 65 | define('G2VARLATESTITEMCOUNT', 'g2_latest_item_count');// Latest(x) block: value of x |
| 66 | define('G2VARLATESTTITLE', 'g2_latest_title'); // Latest(x) block: title |
| 67 | define('G2VARMAIN', 'g2_main'); // nid of the node used as main page for G2 |
| 68 | define('G2VARPAGETITLE', 'g2_page_title'); // Override for default site title on G2 pages |
| 69 | define('G2VARPATHMAIN', 'g2_pathmain'); // path for the G2 main page |
| 70 | define('G2VARNOFREETAGGING', 'g2_nofreetagging'); // Hide information from freetagging vocabularies to non-G2 admin |
| 71 | define('G2VARRANDOMENTRY', 'g2_random_entry'); // Random block: latest pseudo-random entry displayed |
| 72 | define('G2VARRANDOMSTORE', 'g2_random_store'); // Random block: store the latest random entry |
| 73 | define('G2VARRANDOMTERMS', 'g2_random_terms'); // Random block: show terms bound to entry |
| 74 | define('G2VARRANDOMTITLE', 'g2_random_title'); // Random block: title |
| 75 | define('G2VARREMOTEG2', 'g2_remote_g2'); // Base URL of remote G2 instance |
| 76 | define('G2VARRPCTHROTTLE', 'g2_rpc_throttle'); // Coefficient limit for XML-RPC operations over block settings |
| 77 | define('G2VARWOTDAUTOCHANGE', 'g2_wotd_autochange');// WOTD block: automatically change the WOTD once a day |
| 78 | define('G2VARWOTDBODYSIZE', 'g2_wotd_bodysize'); // WOTD block: number of body characters to be displayed in the block |
| 79 | define('G2VARWOTDDATE', 'g2_wotd_date'); // WOTD block: date for which this WOTD entry is current |
| 80 | define('G2VARWOTDENTRY', 'g2_wotd_entry'); // WOTD block: current entry |
| 81 | define('G2VARWOTDFEEDLINK', 'g2_wotd_feed_link'); // WOTD block feed: include a link to the WOTD RSS feed in the block |
| 82 | define('G2VARWOTDFEEDTITLE', 'g2_wotd_feed_title');// WOTD block feed: the title for the WOTD RSS feed |
| 83 | define('G2VARWOTDFEEDDESCR', 'g2_wotd_feed_descr');// WOTD block feed: the description for the WOTD RSS feed |
| 84 | define('G2VARWOTDFEEDAUTHOR', 'g2_wotd_feed_author');//WOTD block feed: include the author in the feed entries |
| 85 | define('G2VARWOTDTITLE', 'g2_wotd_title'); // WOTD block: title |
| 86 | define('G2VARWOTDTERMS', 'g2_wotd_terms'); // WOTD block: show terms bound to entry |
| 87 | define('G2VARTOPITEMCOUNT', 'g2_top_item_count'); // Top(x) block: value of x |
| 88 | define('G2VARTOPTITLE', 'g2_top_title'); // Top(x) block: title |
| 89 | define('G2VARXMLRPC', 'g2_xmlrpc'); // Is the XML-RPC server enabled ? |
| 90 | |
| 91 | /** |
| 92 | * G2 default values for some of the persistent variables above |
| 93 | */ |
| 94 | define('G2DEFAULTALPHABAR', '0123456789abcdefghijklmnopqrstuvwxyz'); |
| 95 | define('G2DEFAULTHOMONYMSREDIRECT', '302');// The HTTP 30x code to be used for automatic redirects |
| 96 | define('G2DEFAULTPATHMAIN', 'g2'); |
| 97 | define('G2DEFAULTRPCTHROTTLE', 10); |
| 98 | define('G2DEFAULTPAGETITLE', t('G2 Glossary on %title')); |
| 99 | define('G2DEFAULTREMOTEG2', 'http://www.riff.org/g2/entries'); |
| 100 | define('G2DEFAULTREMOTENO', '<local>'); |
| 101 | define('G2DEFAULTWOTDTITLE', t('Word of the day in the G2 glossary')); |
| 102 | define('G2DEFAULTWOTDFEEDDESCR', t("A daily definition from the G2 Glossary at %site")); // see _g2_wotd_feed() |
| 103 | define('G2DEFAULTWOTDFEEDAUTHOR', "%author"); // This default will use the actual node author |
| 104 | |
| 105 | /** |
| 106 | * ========== Unimplemented hooks below: ========== |
| 107 | **/ |
| 108 | /* |
| 109 | function g2_execute(&$node) |
| 110 | function g2_prepare(&$node) |
| 111 | function g2_comment($comment, $op) |
| 112 | function g2_db_rewrite_sql($query, $primary_table, $primary_field, $args) |
| 113 | function g2_elements() |
| 114 | function g2_exit($destination = NULL) |
| 115 | function g2_file_download($file) |
| 116 | function g2_footer($main = 0) |
| 117 | function g2_form_alter($form_id, &$form_values) |
| 118 | function g2_init() |
| 119 | function g2_link($type, $node = NULL, $teaser = FALSE) |
| 120 | function g2_user($op, &$edit, &$user, $category = NULL) |
| 121 | function g2_onload() |
| 122 | function g2_node_grants($user, $op) |
| 123 | function g2_ping($name = '', $url = '') { |
| 124 | function g2_search($op = 'search', $keys = null) {} |
| 125 | function g2_search_item($item) {} |
| 126 | function g2_search_preprocess($text) -- for Asian languages only ? |
| 127 | function g2_update_index() |
| 128 | function g2_taxonomy($op, $type, $object = NULL) |
| 129 | */ |
| 130 | |
| 131 | /** |
| 132 | * Return alphabar data |
| 133 | */ |
| 134 | function _g2_alphabar() |
| 135 | { |
| 136 | $rawalphabar = variable_get(G2VARALPHABAR, G2DEFAULTALPHABAR); |
| 137 | $ret = array(); |
| 138 | for ($i = 0 ; $i < strlen($rawalphabar) ; $i++) |
| 139 | { |
| 140 | $c = drupal_substr($rawalphabar, $i, 1); |
| 141 | $path = _g2_terminal_encode($c); |
| 142 | $link = array |
| 143 | ( |
| 144 | 'title' => $c, |
| 145 | 'href' => G2PATHINITIAL . "/$path", |
| 146 | 'absolute' => true, // new in 6.0, was always relative in 5.x |
| 147 | 'html' => true, |
| 148 | ); |
| 149 | $ret[] = $link; |
| 150 | } |
| 151 | return $ret; |
| 152 | } |
| 153 | |
| 154 | /** |
| 155 | * AJAX autocomplete for entry |
| 156 | * |
| 157 | * @param string $string The beginning of the entry |
| 158 | * @see g2_menu() |
| 159 | * @see g2_block() |
| 160 | */ |
| 161 | function _g2_autocomplete($string = NULL) |
| 162 | { |
| 163 | $matches = array(); |
| 164 | if (isset($string)) |
| 165 | { |
| 166 | $q = db_query_range("SELECT title FROM {node} WHERE LOWER(title) LIKE LOWER('%s%%') and type = '" . G2NODETYPE . "' and (status = 1)", $string, 0, 10); |
| 167 | while ($result = db_fetch_object($q)) { |
| 168 | $matches[$result->title] = check_plain($result->title); |
| 169 | // watchdog('g2', "string = $string, matches: " . print_r($matches, TRUE), WATCHDOG_NOTICE); |
| 170 | } |
| 171 | } |
| 172 | print drupal_to_js($matches); |
| 173 | exit(); |
| 174 | } |
| 175 | |
| 176 | /** |
| 177 | * Provides the block-specific contents common to each G2 block: ability to rename the block and change its title |
| 178 | * |
| 179 | * @param array $form The current form for which this is built |
| 180 | * @param string $infotitle Block information: the title |
| 181 | * @param string $infovar Block information: the config variable name |
| 182 | * @param string $infodefault Block information: the default name |
| 183 | * @param string $titletitle Block title: the title |
| 184 | * @param string $titlevar Block title: the config variable name |
| 185 | * @param string $titledefault Block title: the default title |
| 186 | * @return void |
| 187 | */ |
| 188 | function _g2_block_settings_show(&$form, $infotitle, $infovar, $infodefault, $titletitle, $titlevar, $titledefault) |
| 189 | { |
| 190 | $form['info'] = array |
| 191 | ( |
| 192 | '#type' => 'textfield', |
| 193 | '#title' => $infotitle, |
| 194 | '#default_value' => variable_get('g2_' . $infovar . '_info', $infodefault), |
| 195 | '#weight' => -2, |
| 196 | ); |
| 197 | $form['title'] = array |
| 198 | ( |
| 199 | '#type' => 'textfield', |
| 200 | '#title' => $titletitle, |
| 201 | '#default_value' => variable_get('g2_' . $titlevar . '_title', $titledefault), |
| 202 | '#weight' => -1, |
| 203 | ); |
| 204 | } |
| 205 | |
| 206 | function _g2_block_settings_save($edit, $blockname) |
| 207 | { |
| 208 | variable_set('g2_' . $blockname . '_info', $edit['info' ]); |
| 209 | variable_set('g2_' . $blockname . '_title', $edit['title']); |
| 210 | } |
| 211 | |
| 212 | /** |
| 213 | * Remove unwanted terms from a taxonomy array |
| 214 | * |
| 215 | * @param array $taxonomy array of fully loaded terms (tid, vid, weight..) |
| 216 | */ |
| 217 | function _g2_comb_taxonomy($taxonomy) |
| 218 | { |
| 219 | $vocabs = array(); |
| 220 | if (variable_get(G2VARNOFREETAGGING, true)) // These are hidden by default |
| 221 | { |
| 222 | // We still hide the terms within freetagging vocabularies to allow partial display |
| 223 | foreach ($taxonomy as $key => $value) |
| 224 | { |
| 225 | // Is the current term in a freetagging vocabulary ? |
| 226 | if (!array_key_exists($value->vid, $vocabs)) |
| 227 | { |
| 228 | $vocab = taxonomy_get_vocabulary($value->vid); |
| 229 | $vocabs[$value->vid] = $vocab->tags; |
| 230 | } |
| 231 | |
| 232 | if ($vocabs[$value->vid] == true) |
| 233 | unset($taxonomy[$key]); |
| 234 | } |
| 235 | } |
| 236 | return $taxonomy; |
| 237 | } |
| 238 | |
| 239 | /** |
| 240 | * Return a span containing links to taxonomy terms, or nothing |
| 241 | * if node information contains no terms. The "node" passed must |
| 242 | * contain full term information, not just tids. |
| 243 | * @param object $node imitation of a node |
| 244 | */ |
| 245 | function _g2_entry_terms($node) |
| 246 | { |
| 247 | if (sizeof($node->taxonomy) > 0) |
| 248 | { |
| 249 | $ret = ' <span class="taxonomy">' ; |
| 250 | foreach ($node->taxonomy as $term) |
| 251 | { |
| 252 | $ret .= l($term->name, "taxonomy/term/$term->tid", |
| 253 | array('attributes' => array('rel' => 'tag', 'title' => $term->title))) |
| 254 | . ' | '; |
| 255 | } |
| 256 | $ret = substr($ret, 0, strlen($ret) - 3); |
| 257 | $ret .= '</span>' ; |
| 258 | } |
| 259 | return $ret; |
| 260 | } |
| 261 | |
| 262 | /** |
| 263 | * Return a list of words starting by an initial segment |
| 264 | * (typically one letter, but this can be any starting substring) |
| 265 | * The logic is different from the one in _g2_entries because |
| 266 | * we don't care for the case of "/" as an initial segment |
| 267 | * |
| 268 | * @param string $initial |
| 269 | * @return string HTML |
| 270 | */ |
| 271 | function _g2_initial($initial) |
| 272 | { |
| 273 | $initial = check_plain($initial); |
| 274 | $arTotal = _g2_stats(); |
| 275 | $arInitial = _g2_stats(0, $initial); |
| 276 | $ret = t("<p>Displaying %count entries starting by '%initial' from a total number of %total entries.</p>", |
| 277 | array( |
| 278 | // Since _g2_stats() no longer returns empty arrays, we no longer need to check values |
| 279 | '%count' => $arInitial[NODE_PUBLISHED], |
| 280 | '%initial' => $initial, |
| 281 | '%total' => $arTotal [NODE_PUBLISHED], |
| 282 | ) |
| 283 | ); |
| 284 | if (user_access(G2PERMADMIN)) |
| 285 | { |
| 286 | $ret .= t('<p>Admin info: there are also %count unpublished matching entries from a total number of %total unpublished entries.</p>', |
| 287 | array( |
| 288 | '%count' => $arInitial[NODE_NOT_PUBLISHED], |
| 289 | '%total' => $arTotal[NODE_NOT_PUBLISHED], |
| 290 | ) |
| 291 | ); |
| 292 | } |
| 293 | unset($arInitial); |
| 294 | unset($arTotal); |
| 295 | |
| 296 | $sq = "select n.nid, v.title, v.teaser from {node} n inner join {node_revisions} v on n.vid = v.vid " |
| 297 | . " where (n.type='%s') and (v.title like '%s%%') and (n.status = 1) " |
| 298 | . "order by v.title "; |
| 299 | $q = db_query($sq, G2NODETYPE, $initial); |
| 300 | $ar = array(); |
| 301 | while ($result = db_fetch_object($q)) |
| 302 | { |
| 303 | $teaser = strip_tags($result->teaser); |
| 304 | $ar[] = l($result->title, "node/$result->nid", array('html' => true)) |
| 305 | . t(': %teaser', array('%teaser' => $teaser)) |
| 306 | . l(' (+)', "node/$result->nid", array('attributes' => array('class' => 'read-more'))); |
| 307 | } |
| 308 | $ret .= theme('item_list', $ar); |
| 309 | return $ret; |
| 310 | } |
| 311 | |
| 312 | function _g2_ip_ban() |
| 313 | { |
| 314 | return xmlrpc_error(); |
| 315 | } |
| 316 | |
| 317 | /** |
| 318 | * Returns a list of the latest n nodes |
| 319 | * as counted by time of update |
| 320 | * @return array |
| 321 | */ |
| 322 | function _g2_latest($max = null) |
| 323 | { |
| 324 | $defmax = variable_get(G2VARLATESTITEMCOUNT, 10); |
| 325 | $rpcthrottle = variable_get(G2VARRPCTHROTTLE, G2DEFAULTRPCTHROTTLE); |
| 326 | if (empty($max) or ($max > $rpcthrottle*$defmax)) // Limit extraction |
| 327 | { |
| 328 | $max = $defmax; |
| 329 | } |
| 330 | $sq = "select n.title, n.nid, n.status from {node} n where (n.type = '" . G2NODETYPE . "') order by n.changed desc"; |
| 331 | $q = db_query_range($sq, 0, $max); |
| 332 | $ret = array(); |
| 333 | while ($row = db_fetch_object($q)) |
| 334 | { |
| 335 | $ret[] = $row; |
| 336 | } |
| 337 | return $ret; |
| 338 | } |
| 339 | |
| 340 | /** |
| 341 | * Ancillary function for g2_block to return a pseudo-random entry |
| 342 | * selected to be different from the current WOTD and, in the |
| 343 | * default setting, from the latest pseudo-random result returned. |
| 344 | * Only works for glossaries with 3 entries or more. |
| 345 | * @return object title / nid / teaser |
| 346 | */ |
| 347 | function _g2_random() |
| 348 | { |
| 349 | $wotd = variable_get(G2VARWOTDENTRY, ''); |
| 350 | |
| 351 | // Count the allowed nodes |
| 352 | if (variable_get(G2VARRANDOMSTORE, True)) |
| 353 | { |
| 354 | $random = variable_get(G2VARRANDOMENTRY, ''); |
| 355 | $sq = 'select count(*) cnt ' |
| 356 | . 'from {node} n ' |
| 357 | . "where n.type = '" . G2NODETYPE . "' and (n.status = 1) and not (n.title = '%s' or n.nid = %d)" ; |
| 358 | $q = db_query($sq, $random, $wotd); |
| 359 | } |
| 360 | else |
| 361 | { |
| 362 | $random = ''; |
| 363 | $sq = "select count(*) cnt from {node} n where n.type = '" . G2NODETYPE . "' and (n.status = 1) and not (n.nid = %d)" ; |
| 364 | $q = db_query($sq, $wotd); |
| 365 | } |
| 366 | $ret = db_fetch_object($q); |
| 367 | $n = $ret->cnt; |
| 368 | $rand = rand(0, $n - 1); |
| 369 | |
| 370 | // Select from the exact same list of nodes, assuming none was inserted/deleted in the meantime |
| 371 | $sq = 'select n.title, n.nid, v.teaser ' |
| 372 | . 'from {node} n inner join {node_revisions} v on n.vid = v.vid ' |
| 373 | . "where n.type = '" . G2NODETYPE . "' and (n.status = 1) and not (n.title = '%s' or n.nid = %d)" ; |
| 374 | $q = db_query_range($sq, $random, $wotd, $rand, 1); |
| 375 | $ret = db_fetch_object($q); |
| 376 | |
| 377 | if (variable_get(G2VARRANDOMTERMS, FALSE)) |
| 378 | { |
| 379 | $taxonomy = taxonomy_node_get_terms($ret->nid); |
| 380 | |
| 381 | // Currently an OSInet.fr private extension. Ignored on other sites. |
| 382 | if (function_exists('_osinode_comb_taxonomy')) |
| 383 | { |
| 384 | $taxonomy = _osinode_comb_taxonomy($taxonomy); |
| 385 | } |
| 386 | $ret->taxonomy = $taxonomy; |
| 387 | unset($taxonomy); |
| 388 | } |
| 389 | // echo "<pre>ret = " . print_r($ret, TRUE) . ", terms: " . print_r($x, TRUE) . "</pre>"; |
| 390 | if (variable_get(G2VARRANDOMSTORE, True)) |
| 391 | { |
| 392 | variable_set(G2VARRANDOMENTRY, $ret->title); |
| 393 | } |
| 394 | return $ret; |
| 395 | } |
| 396 | |
| 397 | /** |
| 398 | * Counts the number of entries matching two criteria: |
| 399 | * @param int $tid Term Id (ignored if 0) |
| 400 | * @param string $initial Start of entry (ignored if null) |
| 401 | * @return string HTML |
| 402 | * @todo check referer wipe: it may have been damaged in the D6 port |
| 403 | */ |
| 404 | function _g2_referer_links() |
| 405 | { |
| 406 | $nid = arg(1); |
| 407 | $sq = "SELECT gr.referer, gr.incoming " |
| 408 | . "FROM {g2_referer} gr " |
| 409 | . "WHERE gr.nid = %d " |
| 410 | . "ORDER BY gr.incoming DESC"; |
| 411 | $q = db_query($sq, $nid); |
| 412 | $ar = array(); |
| 413 | while ($o = db_fetch_object($q)) |
| 414 | { |
| 415 | $ar[] = l( |
| 416 | t("%link : %incoming incoming clicks", array('%link' => $o->referer, '%incoming' => $o->incoming)), |
| 417 | $o->referer, |
| 418 | array('absolute' => true) |
| 419 | ); |
| 420 | } |
| 421 | $ret = theme('item_list', $ar, ''); |
| 422 | $ret .= t('WARNING: just because a click came from a node doesn\'t mean the node has a link. |
| 423 | The click may have come from a block on the page. These stats are just a hint for editors.'); |
| 424 | $ret = theme('box', t('Local referers for this node'), $ret); |
| 425 | |
| 426 | $form = array(); |
| 427 | $form['#action'] = url(G2PATHREFERERWIPE . '/' . $nid, array('absolute' => true)); |
| 428 | $form['submit'] = array( |
| 429 | '#type' => 'submit', |
| 430 | '#value' => t('Wipe referer info for this entry'), |
| 431 | ); |
| 432 | |
| 433 | $ret .= drupal_get_form('g2_referer_wipe', $form); |
| 434 | return $ret; |
| 435 | } |
| 436 | |
| 437 | /** |
| 438 | * Erase the referer counts on g2 entries |
| 439 | * |
| 440 | * Difference from the 4.7 version: it no longer includes a goto when erasing all |
| 441 | * |
| 442 | * @param int $nid Node from which to erase referers, or null to erase all g2 referers |
| 443 | * @return void |
| 444 | */ |
| 445 | function _g2_referer_wipe($nid = NULL) |
| 446 | { |
| 447 | if (isset($nid)) |
| 448 | { |
| 449 | $sq .= 'DELETE from {g2_referer} WHERE nid = %d'; |
| 450 | db_query($sq, check_plain($nid)); |
| 451 | drupal_goto(drupal_get_path_alias("node/$nid")); |
| 452 | } |
| 453 | else |
| 454 | { |
| 455 | $sq .= 'DELETE from {g2_referer}'; |
| 456 | db_query($sq); |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | /** |
| 461 | * Extract statistics from the G2 glossary |
| 462 | * - g2 entries having chosen taxonomy term |
| 463 | * - g2 entries starting by chosen initial segment |
| 464 | * |
| 465 | * @param int $tid Taxonomy term id |
| 466 | * @param string $initial Initial segment |
| 467 | * @return array |
| 468 | */ |
| 469 | function _g2_stats($tid = 0, $initial = NULL) |
| 470 | { |
| 471 | $test1 = false; |
| 472 | $test2 = false; |
| 473 | |
| 474 | $sq = "SELECT status, count(distinct n.nid) cnt FROM {node} n "; |
| 475 | $sq_test = ' n.type = \'' . G2NODETYPE . "' "; |
| 476 | if (isset($tid) && $tid > 0) |
| 477 | { |
| 478 | $sq .= "INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid = %d AND $sq_test "; |
| 479 | $test1 = true; |
| 480 | } |
| 481 | else |
| 482 | { |
| 483 | $sq .= "WHERE $sq_test "; |
| 484 | } |
| 485 | if (isset($initial) && $initial <> '') |
| 486 | { |
| 487 | $sq .= "AND n.title like '%s%%' "; |
| 488 | $test2 = true; |
| 489 | } |
| 490 | $sq .= 'GROUP BY status'; |
| 491 | if ($test1 && $test2) |
| 492 | $q = db_query($sq, $tid, $initial); |
| 493 | elseif ($test1) |
| 494 | $q = db_query($sq, $tid); |
| 495 | elseif ($test2) |
| 496 | $q = db_query($sq, $initial); |
| 497 | else |
| 498 | $q = db_query($sq); |
| 499 | |
| 500 | // Avoid empty returns |
| 501 | $ret = array(NODE_NOT_PUBLISHED => 0, NODE_PUBLISHED => 0) ; |
| 502 | |
| 503 | while ($o = db_fetch_object($q)) |
| 504 | { |
| 505 | $ret[$o->status] = $o->cnt; |
| 506 | } |
| 507 | return $ret; |
| 508 | } |
| 509 | |
| 510 | /** |
| 511 | * Returns a list of the top n nodes |
| 512 | * as counted by statistics.module |
| 513 | * @param $max |
| 514 | * @return array |
| 515 | */ |
| 516 | function _g2_top($max = null) |
| 517 | { |
| 518 | $defmax = variable_get(G2VARTOPITEMCOUNT, 10); |
| 519 | $rpcthrottle = variable_get(G2VARRPCTHROTTLE, G2DEFAULTRPCTHROTTLE); |
| 520 | if (empty($max) or ($max > $rpcthrottle*$defmax)) // Limit extraction |
| 521 | { |
| 522 | $max = $defmax; |
| 523 | } |
| 524 | $sq = "select n.title, n.nid, n.status from {node} n inner join {node_counter} c on n.nid = c.nid where (n.type = '" . G2NODETYPE . "') and (c.totalcount is not null) order by c.totalcount desc, n.changed desc"; |
| 525 | $q = db_query_range($sq, 0, $max); |
| 526 | $ret = array(); |
| 527 | while ($row = db_fetch_object($q)) |
| 528 | { |
| 529 | $ret[] = $row; |
| 530 | } |
| 531 | return $ret; |
| 532 | } |
| 533 | |
| 534 | /** |
| 535 | * Returns a structure for the WOTD. |
| 536 | * Limitation: always returns just the FIRST entry for a given word |
| 537 | * @param int $bodysize |
| 538 | * @return object title / nid / teaser |
| 539 | */ |
| 540 | function _g2_wotd($bodysize = 0) |
| 541 | { |
| 542 | // No need for a static: this function is normally never called twice |
| 543 | |
| 544 | $sqhead = 'select n.title, n.nid, v.teaser' ; |
| 545 | $entrynid = variable_get(G2VARWOTDENTRY, 0); |
| 546 | |
| 547 | if ($bodysize > 0) |
| 548 | $sqhead .= ', v.body'; |
| 549 | $sq = $sqhead |
| 550 | . " from {node} n inner join {node_revisions} v on n.vid = v.vid where n.type='" |
| 551 | . G2NODETYPE |
| 552 | . "' and (n.status = 1) and (n.nid=%d)"; |
| 553 | $q = db_query_range($sq, $entrynid, 0, 1); |
| 554 | $ret = db_fetch_object($q); |
| 555 | if (variable_get(G2VARWOTDTERMS, FALSE)) |
| 556 | { |
| 557 | $ret->taxonomy = _g2_comb_taxonomy(taxonomy_node_get_terms($ret->nid)); |
| 558 | } |
| 559 | return $ret; |
| 560 | } |
| 561 | |
| 562 | /** |
| 563 | * Generate an RSS feed containing the latest WOTD |
| 564 | * @return string XML in UTF-8 encoding |
| 565 | */ |
| 566 | function _g2_wotd_feed() |
| 567 | { |
| 568 | global $base_url; |
| 569 | |
| 570 | $channelinfo = array |
| 571 | ( |
| 572 | // Link element: Drupal 4.7 defaults to $base url |
| 573 | // Language: Drupal 4.7 defaults to $locale |
| 574 | 'title' => variable_get(G2VARWOTDFEEDTITLE, variable_get(G2VARWOTDTITLE, G2DEFAULTWOTDTITLE)), // Drupal defaults to site name - site slogan |
| 575 | 'description' => strtr(variable_get(G2VARWOTDFEEDDESCR, G2DEFAULTWOTDFEEDDESCR), array('%site' => $base_url)), // Drupal defaults to $site_mission |
| 576 | 'managingEditor' => variable_get('site_mail', 'nobody@example.com'), |
| 577 | ); |
| 578 | $items = array(variable_get(G2VARWOTDENTRY, 0)); |
| 579 | $ret = node_feed($items, $channelinfo); |
| 580 | return $ret; |
| 581 | } |
| 582 | |
| 583 | /** |
| 584 | * implement hook_access |
| 585 | * |
| 586 | * @param $op string |
| 587 | * @param $node int |
| 588 | * The node on which the operation is to be performed, or, if it does |
| 589 | * not yet exist, the type of node to be created. |
| 590 | * @return boolean |
| 591 | * TRUE if the operation may be performed; FALSE if the operation may not be |
| 592 | * returned; NULL to not override the settings in the node_access table. |
| 593 | */ |
| 594 | function g2_access($op, $node) |
| 595 | { |
| 596 | global $user; |
| 597 | |
| 598 | switch ($op) |
| 599 | { |
| 600 | case 'create': |
| 601 | case 'delete': |
| 602 | case 'update': |
| 603 | $ret = user_access(G2PERMADMIN); |
| 604 | break; |
| 605 | case 'view': |
| 606 | $ret = user_access(G2PERMVIEW); |
| 607 | break; |
| 608 | } |
| 609 | return $ret; |
| 610 | } |
| 611 | |
| 612 | /** |
| 613 | * implement hook_block |
| 614 | * |
| 615 | * @param $op string |
| 616 | * What kind of information to retrieve about the block or blocks. |
| 617 | * - 'list': A list of all blocks defined by the module. |
| 618 | * - 'configure': A configuration form. |
| 619 | * - 'save': Save the configuration options. |
| 620 | * - 'view': Information about a particular block. |
| 621 | * @param $delta int |
| 622 | * Which block to return (not applicable if $op is 'list'). |
| 623 | * @param $edit array |
| 624 | * If $op is 'save', the submitted form data from the configuration form. |
| 625 | * @return mixed |
| 626 | * If $op is 'list', return an array of arrays, each of which must define an |
| 627 | * 'info' element describing the block. If $op is 'configure', optionally |
| 628 | * return a string containing the configuration form. If $op is 'save', |
| 629 | * return nothing, If $op is 'view', return an array which must define a |
| 630 | * 'subject' element and a 'content' element defining the block indexed by |
| 631 | * $delta. |
| 632 | */ |
| 633 | function g2_block($op = 'list', $delta = 0, $edit = array()) { |
| 634 | if ($op == 'list') |
| 635 | { |
| 636 | $blocks[0]['info'] = variable_get('g2_alphabar_info', t('G2 Alphabar')); |
| 637 | $blocks[1]['info'] = variable_get('g2_random_info', t('G2 Random')); |
| 638 | $blocks[2]['info'] = variable_get('g2_top_info', t('G2 Top')); |
| 639 | $blocks[3]['info'] = variable_get('g2_wotd_info', t('G2 Word of the day')); |
| 640 | $blocks[4]['info'] = variable_get('g2_latest_info', t('G2 Latest')); |
| 641 | return $blocks; |
| 642 | } |
| 643 | elseif ($op == 'configure') |
| 644 | { |
| 645 | switch ($delta) |
| 646 | { |
| 647 | case 0: // Alphabar |
| 648 | $form['alphabar'] = array |
| 649 | ( |
| 650 | '#type' => 'textfield', |
| 651 | '#title' => t('List of initials to be included in alphabar'), |
| 652 | '#default_value' => variable_get(G2VARALPHABAR, G2DEFAULTALPHABAR), |
| 653 | '#description' => t('The alphabar lists the initials for which links to initial pages will be included.') |
| 654 | ); |
| 655 | $form['rowlen'] = array |
| 656 | ( |
| 657 | '#type' => 'textfield', |
| 658 | '#title' => t('Maximum length of lines in the alphabar'), |
| 659 | '#default_value' => variable_get(G2VARALPHABARROWLEN, 13), |
| 660 | '#size' => 3, |
| 661 | '#description' => t('Each line except the last one will have exactly that number of links.') |
| 662 | ); |
| 663 | _g2_block_settings_show($form, |
| 664 | t('Name of the block in the block list'), 'alphabar', t('G2 Alphabar'), |
| 665 | t('Title of the block when displayed'), 'alphabar', t('G2 Glossary pages')); |
| 666 | break; |
| 667 | case 1: // Random |
| 668 | $form['random_store'] = array |
| 669 | ( |
| 670 | '#type' => 'checkbox', |
| 671 | '#title' => t('Store latest random entry'), |
| 672 | '#default_value' => variable_get(G2VARRANDOMSTORE, TRUE), |
| 673 | '#description' => t('When this setting is true (default value), |
| 674 | the latest random value is kept in the DB to avoid showing the same pseudo-random |
| 675 | value on consecutive page displays. |
| 676 | For small sites, it is usually best to keep it saved. |
| 677 | For larger sites, unchecking this setting will remove one database write with locking.'), |
| 678 | ); |
| 679 | $form['random_terms'] = array( |
| 680 | '#type' => 'checkbox', |
| 681 | '#title' => t('Return taxonomy terms for the current entry'), |
| 682 | '#default_value' => variable_get(G2VARRANDOMTERMS, FALSE), |
| 683 | '#description' => t('The taxonomy terms will be returned by XML-RPC and made available to the theme. |
| 684 | Default G2 themeing will display them.'), |
| 685 | ); |
| 686 | _g2_block_settings_show($form, |
| 687 | t('Name of the block in the block list'), 'random', t('G2 Random'), |
| 688 | t('Title of the block when displayed'), 'random', t('Random G2 glossary entry')); |
| 689 | break ; |
| 690 | case 2: // Top |
| 691 | $topcount = variable_get(G2VARTOPITEMCOUNT, 10); |
| 692 | $form['itemcount'] = array |
| 693 | ( |
| 694 | '#type' => 'select', |
| 695 | '#title' => t('Number of items'), |
| 696 | '#default_value' => $topcount, |
| 697 | '#options' => array('1' => '1', '2' => '2', '5' => '5', '10' => '10') |
| 698 | ); |
| 699 | _g2_block_settings_show($form, |
| 700 | t('Name of the block in the block list'), 'top', sprintf(t('G2 Top %d'), $topcount), |
| 701 | t('Title of the block when displayed'), 'top', t('%d most popular G2 glossary entries')); |
| 702 | break; |
| 703 | case 3: // WOTD |
| 704 | /** |
| 705 | * @see _g2_autocomplete() |
| 706 | */ |
| 707 | $node = node_load(variable_get(G2VARWOTDENTRY, 0)); |
| 708 | $form['wotd_entry'] = array |
| 709 | ( |
| 710 | '#type' => 'textfield', |
| 711 | '#title' => t('Entry for the day'), |
| 712 | '#maxlength' => 60, |
| 713 | '#autocomplete_path' => G2PATHAUTOCOMPLETE, |
| 714 | '#required' => TRUE, |
| 715 | '#default_value' => $node->title, |
| 716 | ); |
| 717 | $form['wotd_bodysize'] = array |
| 718 | ( |
| 719 | '#type' => 'textfield', |
| 720 | '#title' => t('Number of text characters to be displayed from entry definition body, if one exists'), |
| 721 | '#size' => 4, |
| 722 | '#maxlength' => 4, |
| 723 | '#required' => TRUE, |
| 724 | '#default_value' => variable_get(G2VARWOTDBODYSIZE, '') |
| 725 | ); |
| 726 | $form['wotd_autochange'] = array |
| 727 | ( |
| 728 | '#type' => 'checkbox', |
| 729 | '#title' => t('Auto-change daily'), |
| 730 | '#required' => TRUE, |
| 731 | '#default_value' => variable_get(G2VARWOTDAUTOCHANGE, TRUE), |
| 732 | '#description' => t('This setting will only work if cron or poormanscron is used.') |
| 733 | ); |
| 734 | |
| 735 | $form['wotd_terms'] = array( |
| 736 | '#type' => 'checkbox', |
| 737 | '#title' => t('Return taxonomy terms for the current entry'), |
| 738 | '#default_value' => variable_get(G2VARWOTDTERMS, FALSE), |
| 739 | '#description' => t('The taxonomy terms will be returned by XML-RPC and made available to the theme. |
| 740 | Default G2 themeing will display them.'), |
| 741 | ); |
| 742 | $form['wotd_feed'] = array( |
| 743 | '#type' => 'fieldset', |
| 744 | '#title' => 'RSS Feed', |
| 745 | ); |
| 746 | $form['wotd_feed']['wotd_feed_link'] = array( |
| 747 | '#type' => 'checkbox', |
| 748 | '#title' => t('Display feed link'), |
| 749 | '#default_value' => variable_get(G2VARWOTDFEEDLINK, TRUE), |
| 750 | '#description' => t('Should the theme display the link to the RSS feed for this block ?'), |
| 751 | ); |
| 752 | $form['wotd_feed']['wotd_feed_title'] = array( |
| 753 | '#type' => 'textfield', |
| 754 | '#title' => t('The feed title'), |
| 755 | '#size' => 60, |
| 756 | '#maxlength' => 60, |
| 757 | '#required' => TRUE, |
| 758 | '#default_value' => variable_get(G2VARWOTDFEEDTITLE, variable_get(G2VARWOTDTITLE, G2DEFAULTWOTDTITLE)), |
| 759 | '#description' => t('The title for the feed itself. |
| 760 | This will typically be used by aggregators to remind users of the feed and link to it. |
| 761 | If nulled, G2 will reset it to the title of the block.'), |
| 762 | ); |
| 763 | $form['wotd_feed']['wotd_feed_author'] = array( |
| 764 | '#type' => 'textfield', |
| 765 | '#title' => t('The feed item author'), |
| 766 | '#size' => 60, |
| 767 | '#maxlength' => 60, |
| 768 | '#required' => TRUE, |
| 769 | '#default_value' => variable_get(G2VARWOTDFEEDAUTHOR, G2DEFAULTWOTDFEEDAUTHOR), |
| 770 | '#description' => t('The author name to be included in the feed entries. |
| 771 | In this string %author will be replaced by the actual author information. |
| 772 | Defaults to %author.'), |
| 773 | ); |
| 774 | $form['wotd_feed']['wotd_feed_descr'] = array( |
| 775 | '#type' => 'textfield', |
| 776 | '#title' => t('The feed description'), |
| 777 | '#size' => 60, |
| 778 | '#maxlength' => 60, |
| 779 | '#required' => TRUE, |
| 780 | '#default_value' => variable_get(G2VARWOTDFEEDDESCR, G2DEFAULTWOTDFEEDDESCR), |
| 781 | '#description' => t('The description for the feed itself. |
| 782 | This will typically be used by aggregators when describing the feed prior to subscription. |
| 783 | It may contain %site, which will dynamically be replaced by the site base URL. |
| 784 | If nulled, G2 will reset it to a default description.'), |
| 785 | ); |
| 786 | |
| 787 | _g2_block_settings_show($form, |
| 788 | t('Name of the block in the block list'), 'wotd', t('G2 Word of the day'), |
| 789 | t('Title of the block when displayed'), 'wotd', t('Word of the day in the G2 glossary')); |
| 790 | break; |
| 791 | case 4: // Latest |
| 792 | $latestcount = variable_get(G2VARLATESTITEMCOUNT, 10); |
| 793 | $form['itemcount'] = array |
| 794 | ( |
| 795 | '#type' => 'select', |
| 796 | '#title' => t('Number of items'), |
| 797 | '#default_value' => $latestcount, |
| 798 | '#options' => array('1' => '1', '2' => '2', '5' => '5', '10' => '10') |
| 799 | ); |
| 800 | _g2_block_settings_show($form, |
| 801 | t('Name of the block in the block list'), 'latest', sprintf(t('G2 Latest %d'), $latestcount), |
| 802 | t('Title of the block when displayed'), 'latest', t('%d most recently updated G2 glossary entries')); |
| 803 | break; |
| 804 | default: |
| 805 | break; |
| 806 | } |
| 807 | return $form; |
| 808 | } |
| 809 | elseif ($op == 'save') |
| 810 | { |
| 811 | //echo "<pre>block/SAVE" . print_r($edit, TRUE) . "</pre>"; |
| 812 | switch ($delta) |
| 813 | { |
| 814 | case 0: // Alphabar |
| 815 | variable_set(G2VARALPHABAR, $edit['alphabar']); |
| 816 | variable_set(G2VARALPHABARROWLEN, $edit['rowlen']); |
| 817 | _g2_block_settings_save($edit, 'alphabar'); |
| 818 | break; |
| 819 | case 1: // Random |
| 820 | variable_set(G2VARRANDOMTERMS, $edit['random_terms']); |
| 821 | _g2_block_settings_save($edit, 'random'); |
| 822 | break; |
| 823 | case 2: // Top |
| 824 | variable_set(G2VARTOPITEMCOUNT, $edit['itemcount']); |
| 825 | _g2_block_settings_save($edit, 'top'); |
| 826 | break; |
| 827 | case 3: // WOTD |
| 828 | $node = node_load(array('title' => $edit['wotd_entry'])); |
| 829 | variable_set(G2VARWOTDENTRY, $node->nid); |
| 830 | variable_set(G2VARWOTDBODYSIZE, $edit['wotd_bodysize']); |
| 831 | variable_set(G2VARWOTDAUTOCHANGE, $edit['wotd_autochange']); |
| 832 | variable_set(G2VARWOTDDATE, mktime()); |
| 833 | variable_set(G2VARWOTDTERMS, $edit['wotd_terms']); |
| 834 | variable_set(G2VARWOTDFEEDLINK, $edit['wotd_feed_link']); |
| 835 | variable_set(G2VARWOTDFEEDTITLE, $edit['wotd_feed_title']); |
| 836 | variable_set(G2VARWOTDFEEDDESCR, $edit['wotd_feed_descr']); |
| 837 | variable_set(G2VARWOTDFEEDAUTHOR, $edit['wotd_feed_author']); |
| 838 | _g2_block_settings_save($edit, 'wotd'); |
| 839 | break; |
| 840 | case 4: // Top |
| 841 | variable_set(G2VARLATESTITEMCOUNT, $edit['itemcount']); |
| 842 | _g2_block_settings_save($edit, 'latest'); |
| 843 | default: |
| 844 | break; |
| 845 | } |
| 846 | } |
| 847 | elseif ($op == 'view') |
| 848 | { |
| 849 | // watchdog('g2', "hook_block/view/$delta"); |
| 850 | switch ($delta) |
| 851 | { |
| 852 | case 0: |
| 853 | $block['subject'] = variable_get(G2VARALPHABARTITLE, t('G2 Glossary pages')); |
| 854 | $block['content'] = theme('g2_block_alphabar'); |
| 855 | break; |
| 856 | case 1: |
| 857 | $block['subject'] = variable_get(G2VARRANDOMTITLE, t('Random G2 glossary entry')); |
| 858 | $block['content'] = theme('g2_block_random'); |
| 859 | break; |
| 860 | case 2: |
| 861 | $block['subject'] = sprintf( |
| 862 | variable_get(G2VARTOPTITLE, t('%d most popular G2 glossary entries')), |
| 863 | variable_get(G2VARTOPITEMCOUNT, 10)); |
| 864 | $block['content'] = theme('g2_block_top'); |
| 865 | break; |
| 866 | case 3: |
| 867 | $block['subject'] = variable_get(G2VARWOTDTITLE, G2DEFAULTWOTDTITLE); |
| 868 | $block['content'] = theme('g2_block_wotd'); |
| 869 | break; |
| 870 | case 4: |
| 871 | $block['subject'] = sprintf( |
| 872 | variable_get(G2VARLATESTTITLE, t('%d most recently updated G2 glossary entries')), |
| 873 | variable_get(G2VARLATESTITEMCOUNT, 10)); |
| 874 | $block['content'] = theme('g2_block_latest'); |
| 875 | break; |
| 876 | } |
| 877 | return $block; |
| 878 | } |
| 879 | } |
| 880 | |
| 881 | /** |
| 882 | * In G2's case, change the WOTD once a day if this feature |
| 883 | * is enabled, which is the default case. |
| 884 | * |
| 885 | * @return void |
| 886 | * |
| 887 | * This hook will only be called if cron.php is run (e.g. by crontab). |
| 888 | */ |
| 889 | function g2_cron() |
| 890 | { |
| 891 | if (variable_get(G2VARWOTDAUTOCHANGE, TRUE)) |
| 892 | { |
| 893 | $date0 = date('z', variable_get(G2VARWOTDDATE, mktime())); |
| 894 | $date1 = date('z'); |
| 895 | if ($date1 <> $date0) |
| 896 | { |
| 897 | $random = _g2_random(); |
| 898 | // watchdog("g2_cron", "d0 = $date0, d1 = $date1, random : " . print_r($random,TRUE) . "</pre>", null, WATCHDOG_INFO); |
| 899 | variable_set(G2VARWOTDENTRY, $random->nid); |
| 900 | variable_set(G2VARWOTDDATE, mktime()); |
| 901 | } |
| 902 | } |
| 903 | } |
| 904 | |
| 905 | /** |
| 906 | * Respond to node deletion. |
| 907 | * |
| 908 | * This is a hook used by node modules. It is called to allow the module |
| 909 | * to take action when a node is being deleted from the database by, for |
| 910 | * example, deleting information from related tables. |
| 911 | * |
| 912 | * @param &$node int |
| 913 | * The node being deleted. |
| 914 | * @return void |
| 915 | * |
| 916 | * To take action when nodes of any type are deleted (not just nodes of |
| 917 | * the type defined by this module), use hook_nodeapi() instead. |
| 918 | */ |
| 919 | function g2_delete(&$node) { |
| 920 | db_query('DELETE FROM {g2_node} WHERE nid = %d', $node->nid); |
| 921 | } |
| 922 | |
| 923 | /** |
| 924 | * implement hook_filter |
| 925 | * |
| 926 | * @param string $op |
| 927 | * Which filtering operation to perform. Possible values: |
| 928 | * - list: provide a list of available filters. |
| 929 | * Returns an associative array of filter names with numerical keys. |
| 930 | * These keys are used for subsequent operations and passed back through |
| 931 | * the $delta parameter. |
| 932 | * - no cache: Return true if caching should be disabled for this filter. |
| 933 | * - description: Return a short description of what this filter does. |
| 934 | * - prepare: Return the prepared version of the content in $text. |
| 935 | * - process: Return the processed version of the content in $text. |
| 936 | * - settings: Return HTML form controls for the filter's settings. These |
| 937 | * settings are stored with variable_set() when the form is submitted. |
| 938 | * Remember to use the $format identifier in the variable and control names |
| 939 | * to store settings per input format (e.g. "mymodule_setting_$format"). |
| 940 | * @param int $delta |
| 941 | * Which of the module's filters to use (applies to every operation except |
| 942 | * 'list'). Modules that only contain one filter can ignore this parameter. |
| 943 | * @param int $format |
| 944 | * Which input format the filter is being used in (applies to 'prepare', |
| 945 | * 'process' and 'settings'). |
| 946 | * @param string $text |
| 947 | * The content to filter (applies to 'prepare' and 'process'). |
| 948 | * @return string |
| 949 | * The return value depends on $op. The filter hook is designed so that a |
| 950 | * module can return $text for operations it does not use/need. |
| 951 | */ |
| 952 | function g2_filter($op, $delta = 0, $format = -1, $text = '') { |
| 953 | switch ($op) { |
| 954 | case 'list': |
| 955 | return array(0 => t('G2 Glossary filter')); |
| 956 | |
| 957 | case 'description': |
| 958 | return t('Allows users to link to G2 entries using <dfn> elements.'); |
| 959 | |
| 960 | case 'prepare': |
| 961 | // Note: we use the bytes 0xFE and 0xFF to replace < > during the filtering process. |
| 962 | // These bytes are not valid in UTF-8 data and thus least likely to cause problems. |
| 963 | $text = preg_replace('@<dfn>(.+?)</dfn>@s', "\xFEdfn\xFF\\1\xFE/dfn\xFF", $text); |
| 964 | return $text; |
| 965 | |
| 966 | case "process": |
| 967 | $text = preg_replace('@\xFEdfn\xFF(.+?)\xFE/dfn\xFF@se', "_g2_filter_process('$1')", $text); |
| 968 | return $text; |
| 969 | |
| 970 | default: |
| 971 | return $text; |
| 972 | } |
| 973 | } |
| 974 | |
| 975 | /** |
| 976 | * implement hook_filter_tips |
| 977 | * |
| 978 | * @param $delta |
| 979 | * Which of this module's filters to use. Modules which only implement one |
| 980 | * filter can ignore this parameter. |
| 981 | * @param $format |
| 982 | * Which format we are providing tips for. |
| 983 | * @param $long |
| 984 | * If set to true, long tips are requested, otherwise short tips are needed. |
| 985 | * @return stringe |
| 986 | * The text of the filter tip. |
| 987 | * |
| 988 | * |
| 989 | */ |
| 990 | function g2_filter_tips($delta, $format, $long = false) { |
| 991 | if ($long) { |
| 992 | return t('Wrap <dfn> elements around the terms for which you want a link to the available G2 definition(s).'); |
| 993 | } |
| 994 | else { |
| 995 | return t('You may link to G2 definitions using <dfn> elements.'); |
| 996 | } |
| 997 | } |
| 998 | |
| 999 | /** |
| 1000 | * Translate glossary linking elements (<dfn>) to actual links) |
| 1001 | * |
| 1002 | * This function generates absolute links, for the benefit of the WOTD RSS feed |
| 1003 | * If this feed is not used, it is possible to use the (shorter) relative URLs |
| 1004 | * by swapping comments. |
| 1005 | * @param string $entry An entry |
| 1006 | * @return string HTML |
| 1007 | */ |
| 1008 | function _g2_filter_process($entry) |
| 1009 | { |
| 1010 | $target = variable_get(G2VARREMOTEG2, G2DEFAULTREMOTEG2); |
| 1011 | if ($target == G2DEFAULTREMOTENO) /* Then we are not using a remote glossary */ |
| 1012 | { |
| 1013 | $target = G2PATHENTRIES; |
| 1014 | } |
| 1015 | // $ret = l($entry, G2PATHENTRIES ."/$entry"); |
| 1016 | $path = urlencode(_g2_terminal_encode($entry)); |
| 1017 | $ret = l($entry, "$target/$path", array('absolute' => true, 'html' => false)); |
| 1018 | return $ret; |
| 1019 | } |
| 1020 | |
| 1021 | /** |
| 1022 | * Display a node editing form. |
| 1023 | * |
| 1024 | * This hook, implemented by node modules, is called to retrieve the form |
| 1025 | * that is displayed when one attempts to "create/edit" an item. This form is |
| 1026 | * displayed at the URI http://www.example.com/?q=node/<add|edit>/nodetype. |
| 1027 | * |
| 1028 | * @param $node int |
| 1029 | * The node being added or edited. |
| 1030 | * @param $param array |
| 1031 | * The hook can set this variable to an associative array of attributes |
| 1032 | * to add to the enclosing \<form\> tag. |
| 1033 | * @return array |
| 1034 | * An array containing the form elements to be displayed in the node |
| 1035 | * edit form. |
| 1036 | * |
| 1037 | * The submit and preview buttons, taxonomy controls, and administrative |
| 1038 | * accoutrements are displayed automatically by node.module. This hook |
| 1039 | * needs to return the node title, the body text area, and fields |
| 1040 | * specific to the node type. |
| 1041 | * |
| 1042 | * For a detailed usage example, see node_example.module. |
| 1043 | */ |
| 1044 | function g2_form(&$node, &$param) |
| 1045 | { |
| 1046 | if (!isset($node->title)) |
| 1047 | { |
| 1048 | $node->title = check_plain(substr($_REQUEST['q'], strlen(G2PATHNODEADD) + 1)) ; |
| 1049 | } |
| 1050 | |
| 1051 | $form['content'] = array( |
| 1052 | '#type' => 'fieldset', |
| 1053 | '#title' => 'Contents', |
| 1054 | '#collapsible' => TRUE, |
| 1055 | '#collapsed' => FALSE, |
| 1056 | '#weight' => -10 |
| 1057 | ); |
| 1058 | $form['content']['title'] = array( |
| 1059 | '#type' => 'textfield', |
| 1060 | '#title' => t('Title'), |
| 1061 | '#required' => TRUE, |
| 1062 | '#default_value' => $node->title |
| 1063 | ); |
| 1064 | $form['content']['teaser'] = array( |
| 1065 | '#type' => 'textfield', |
| 1066 | '#title' => t('Entry expansion (for acronyms) or translation'), |
| 1067 | '#required' => FALSE, |
| 1068 | '#default_value' => $node->teaser |
| 1069 | ); |
| 1070 | $form['content']['body'] = array( |
| 1071 | '#type' => 'textarea', |
| 1072 | '#title' => t('Entry definition'), |
| 1073 | '#rows' => 10, |
| 1074 | '#required' => TRUE, |
| 1075 | '#default_value' => $node->body |
| 1076 | ); |
| 1077 | $form['content']['period'] = array( |
| 1078 | '#type' => 'textfield', |
| 1079 | '#title' => t('Life period of this entry'), |
| 1080 | '#required' => FALSE, |
| 1081 | '#description' => t('This is the period of time during which the entity described by the term was actually alive, not the lifetime of the term itself, since any term is immortal to some extent.'), |
| 1082 | '#default_value' => $node->period |
| 1083 | ); |
| 1084 | $form['publishing'] = array( |
| 1085 | '#type' => 'fieldset', |
| 1086 | '#title' => 'Editor-only information', |
| 1087 | '#collapsible' => TRUE, |
| 1088 | '#collapsed' => TRUE, |
| 1089 | '#description' => 'Information in this box is not published in view mode, only during node edition.', |
| 1090 | '#weight' => 0 |
| 1091 | ); |
| 1092 | $form['publishing']['complement'] = array( |
| 1093 | '#type' => 'textarea', |
| 1094 | '#title' => t('Complement'), |
| 1095 | '#rows' => 10, |
| 1096 | '#required' => FALSE, |
| 1097 | '#description' => t('Information not pertaining to origin of document: comments, notes...'), |
| 1098 | '#default_value' => $node->complement |
| 1099 | ); |
| 1100 | $form['publishing']['origin'] = array( |
| 1101 | '#type' => 'textarea', |
| 1102 | '#title' => t('Origin/I.P.'), |
| 1103 | '#rows' => 10, |
| 1104 | '#required' => FALSE, |
| 1105 | '#description' => t('Informations about the origin/IP licensing of the definition'), |
| 1106 | '#default_value' => $node->origin |
| 1107 | ); |
| 1108 | |
| 1109 | $form['format'] = filter_form($node->format); |
| 1110 | return $form; |
| 1111 | } |
| 1112 | |
| 1113 | /** |
| 1114 | * implement hook_help |
| 1115 | * |
| 1116 | * Modified in D6. |
| 1117 | * @todo API doc on 2007-08-19 seems wrong. Review after D6 release |
| 1118 | */ |
| 1119 | function g2_help($path, $arg) |
| 1120 | { |
| 1121 | $ret = ''; |
| 1122 | switch ($path) |
| 1123 | { |
| 1124 | case 'admin/build/modules#name': |
| 1125 | $ret = 'g2'; |
| 1126 | break; |
| 1127 | case 'admin/help#g2': // works in D6 |
| 1128 | $ret = t('<p>G2 defines a glossary service for Drupal sites. To compare it with the default Drupal glossary: |
| 1129 | <ul><li>G2 content is node-based, not term-based</li> |
| 1130 | <li>G2 leverages existing code from glossary for input filtering and node marking</li> |
| 1131 | <li>G2 RAM use does not significantly increase with larger entry counts, which makes is more suitable for larger glossaries</li> |
| 1132 | <li>G2 requests much less from the database than the default glossary</li> |
| 1133 | <li>G2 uses three taxonomy vocabularies: context, period, and grammatical nature.</li> |
| 1134 | <li>G2 defines optional blocks</li> |
| 1135 | <li>G2 is remotely usable via XML-RPC</li> |
| 1136 | <li>G2 does not provide term feeds</li> |
| 1137 | <li>G2 access control is simplistic, targeted to non-community sites</ul></p>'); |
| 1138 | break; |
| 1139 | case 'admin/modules#description': // seems useless since D5 |
| 1140 | $ret = t('G2 manages a node-based glossary.'); |
| 1141 | break; |
| 1142 | case 'admin/build/block/configure/g2/0': |
| 1143 | $ret = t('This block displays a clickable list of initials from the G2 glossary.'); |
| 1144 | break; |
| 1145 | case 'admin/build/block/configure/g2/1': |
| 1146 | $ret = t('This block displays a pseudo-random entry (different each time) from the G2 glossary.'); |
| 1147 | break; |
| 1148 | case 'admin/build/block/configure/g2/2': |
| 1149 | $stats = module_exists('statistics'); |
| 1150 | $count = variable_get('statistics_count_content_views', NULL); |
| 1151 | $ar = array(); |
| 1152 | $ar[] = $stats |
| 1153 | ? t('Statistics module installed and activated: OK.') |
| 1154 | : t('Statistics module not installed or not activated. Install and activate it and try again.'); |
| 1155 | $ret .= '"' . t('Count content views') . '" ' . t('setting is ') ; |
| 1156 | $ret .= ($count > 0) |
| 1157 | ? 'ON: OK' |
| 1158 | : 'OFF: Error. Please enabled this counter in admin/settings/statistics'; |
| 1159 | $ar[] = $ret; |
| 1160 | $ret = theme('item_list', $ar, t("Dependencies checklist")); |
| 1161 | break; |
| 1162 | case 'admin/build/block/configure/g2/3': |
| 1163 | $ret = t('This block displays a once-a-day entry from the G2 glossary.'); |
| 1164 | break; |
| 1165 | default: // ignore, this hook is called all over the place in 4.7b1 |
| 1166 | //$ret = "g2_help($path)"; |
| 1167 | } |
| 1168 | return $ret; |
| 1169 | } |
| 1170 | |
| 1171 | /** |
| 1172 | * Respond to node insertion. |
| 1173 | * |
| 1174 | * This is a hook used by node modules. It is called to allow the module |
| 1175 | * to take action when a new node is being inserted in the database by, |
| 1176 | * for example, inserting information into related tables. |
| 1177 | * |
| 1178 | * @param $node int |
| 1179 | * @return void |
| 1180 | * |
| 1181 | * To take action when nodes of any type are inserted (not just nodes of |
| 1182 | * the type(s) defined by this module), use hook_nodeapi() instead. |
| 1183 | */ |
| 1184 | function g2_insert($node) |
| 1185 | { |
| 1186 | db_query("INSERT INTO {g2_node} (nid, period, complement, origin) VALUES (%d, '%s', '%s', '%s')", |
| 1187 | $node->nid, $node->period, $node->complement, $node->origin); |
| 1188 | } |
| 1189 | |
| 1190 | /** |
| 1191 | * implement hook_load |
| 1192 | * |
| 1193 | * @param int $node |
| 1194 | * @return object |
| 1195 | */ |
| 1196 | function g2_load($node) |
| 1197 | { |
| 1198 | $ret = db_fetch_object(db_query('SELECT * FROM {g2_node} WHERE nid = %s', $node->nid)); |
| 1199 | return $ret; |
| 1200 | } |
| 1201 | |
| 1202 | /** |
| 1203 | * implement hook_menu |
| 1204 | * |
| 1205 | * Note: restructured in Drupal 6 |
| 1206 | * |
| 1207 | * @return array |
| 1208 | */ |
| 1209 | function g2_menu() |
| 1210 | { |
| 1211 | global $user; |
| 1212 | $items = array(); |
| 1213 | |
| 1214 | /** |
| 1215 | * @todo why arg(1) ? |
| 1216 | $view_access = (user_access(G2PERMVIEW) || ($user->uid == arg(1))); |
| 1217 | $admin_access = (user_access(G2PERMADMIN) || ($user->uid == arg(1))); |
| 1218 | */ |
| 1219 | |
| 1220 | $items[G2PATHSETTINGS] = array |
| 1221 | ( |
| 1222 | 'title' => 'G2 glossary', |
| 1223 | 'description' => 'Define the various parameters used by the G2 module', |
| 1224 | 'page callback' => 'drupal_get_form', |
| 1225 | 'page arguments' => array('g2_admin_settings'), |
| 1226 | 'access arguments' => array('administer site configuration'), |
| 1227 | 'type' => MENU_NORMAL_ITEM, |