8 * Implements hook_node_info()
10 function mkdru_node_info() {
13 'name' => t("Pazpar2 metasearch interface"),
15 'description' => t("Metasearch interface for Z39.50/SRU and other targets via a Pazpar2/Service Proxy backend"),
20 function mkdru_ting_search_tab($keys) {
21 error_log("TING SEARCH TAB invoked");
22 $path = drupal_get_path('module', 'mkdru');
23 // Include client library.
24 drupal_add_js(variable_get('pz2_js_path', 'pazpar2/js')
25 . '/pz2.js', 'module', 'footer');
26 drupal_add_js($path . '/jquery.ba-bbq.js', 'module', 'footer');
27 drupal_add_js($path . '/recipe.js', 'module', 'footer');
28 drupal_add_js($path . '/mkdru.theme.js', 'module', 'footer');
29 drupal_add_js($path . '/mkdru.client.js', 'module', 'footer');
30 $html = theme('mkdru_results');
31 drupal_add_js(array('mkdru' =>
33 'settings' => json_encode(variable_get('mkdru_ding', NULL)),
34 'pz2_path' => variable_get('pz2_path', '/pazpar2/search.pz2'),
38 return array("content" => $html, "title" => "Meta Search");
42 * Implements hook_perm()
44 function mkdru_perm() {
45 return array('create metasearch interface', 'edit any metasearch interface', 'edit own metasearch interface');
49 * Implements hook_access()
51 function mkdru_access($op, $node, $account) {
53 if ($op == 'create') {
54 // Only users with permission to do so may create this node type.
55 return user_access('create metasearch interface', $account);
58 // Users who create a node may edit or delete it later, assuming they have the
59 // necessary permissions.
60 if ($op == 'update' || $op == 'delete') {
61 if (user_access('edit own metasearch interface', $account) && ($account->uid == $node->uid)) {
64 elseif (user_access('edit any metasearch interface', $account)) {
71 * Implements hook_menu()
73 function mkdru_menu() {
74 $items['admin/settings/mkdru'] = array(
75 'title' => 'Pazpar2 Metasearch Settings',
76 'description' => 'Settings for mkdru.',
77 'page callback' => 'drupal_get_form',
78 'page arguments' => array('mkdru_admin_settings'),
79 'access arguments' => array('administer site configuration'),
80 'type' => MENU_NORMAL_ITEM,
81 'file' => 'mkdru.admin.inc',
83 $items['admin/settings/mkdru-ding'] = array(
84 'title' => 'Pazpar2 Metasearch Ding Integration',
85 'description' => 'Search settings for mkdru instance integrated into Ding.',
86 'page callback' => 'drupal_get_form',
87 'page arguments' => array('mkdru_ding_settings'),
88 'access arguments' => array('administer site configuration'),
89 'type' => MENU_NORMAL_ITEM,
91 $items['ahah-mkdru-facet'] = array(
92 'page callback' => 'mkdru_add_facet_callback',
93 'access arguments' => array('create metasearch interface'),
94 'type' => MENU_CALLBACK,
100 * Implements hook_init()
102 function mkdru_init() {
103 // Applies our module specific CSS to all pages. This works best because
104 // all CSS is aggregated and cached so we reduce the number of HTTP
105 // requests and the size is negligible.
106 drupal_add_css(drupal_get_path('module', 'mkdru') .'/mkdru.css');
110 // Config form common to node and settings
111 // function mkdru_settings_form($form, &$form_state) {
112 function mkdru_settings_form(&$form_state) {
113 if (isset($form_state['values']['settings'])) {
114 $settings = $form_state['values']['settings'];
116 else if (isset($form_state['build_info']['args']['settings'])) {
117 $settings = $form_state['build_info']['args']['settings'];
120 $settings = variable_get('mkdru_defaults', NULL);
123 $form['#cache'] = TRUE;
125 $form['settings'] = array(
129 $form['settings']['pz2_path'] = array(
130 '#type' => 'textfield',
131 '#title' => t('Pazpar2/Service Proxy path'),
132 '#description' => t('Path that takes Pazpar2 commands via HTTP'),
134 '#default_value' => $settings['pz2_path'],
136 $form['settings']['use_sessions'] = array(
137 '#type' => 'checkbox',
138 '#title' => t('Session handling'),
139 '#description' => t('Disable for use with Service Proxy'),
140 '#default_value' => $settings['use_sessions'],
143 $form['settings']['sp'] = array(
144 '#type' => 'fieldset',
145 '#title' => t('Service Proxy specific settings'),
146 '#collapsible' => TRUE,
147 '#collapsed' => FALSE
149 $form['settings']['sp']['user'] = array(
150 '#type' => 'textfield',
151 '#title' => t('Service Proxy username'),
152 '#description' => t('Service Proxy username'),
153 '#required' => FALSE,
154 '#default_value' => $settings['sp']['user'],
156 $form['settings']['sp']['pass'] = array(
157 '#type' => 'password',
158 '#title' => t('Service Proxy password'),
159 '#description' => t('Service Proxy password'),
160 '#required' => FALSE,
161 '#default_value' => $settings['sp']['pass'],
164 $form['settings']['facets'] = array(
165 '#type' => 'fieldset',
166 '#title' => t('Facet settings'),
167 // Set up the wrapper so that AJAX will be able to replace the fieldset.
168 '#prefix' => '<div id="mkdru-facets-form-wrapper">',
169 '#suffix' => '</div>',
170 '#collapsible' => TRUE,
171 '#collapsed' => FALSE
174 foreach (array_keys($settings['facets']) as $facet) {
175 $form['settings']['facets'][$facet] = array(
176 '#type' => 'fieldset',
177 '#title' => $facet . ' ' . t('facet'),
178 '#collapsible' => TRUE,
179 '#collapsed' => FALSE
181 $form['settings']['facets'][$facet]['displayName'] = array(
182 '#type' => 'textfield',
183 '#title' => t('Facet name to display in UI'),
185 '#default_value' => $settings['facets'][$facet]['displayName'],
187 $form['settings']['facets'][$facet]['pz2Name'] = array(
188 '#type' => 'textfield',
189 '#title' => t('Name of termlist in Pazpar2'),
191 '#default_value' => $settings['facets'][$facet]['pz2Name'],
193 $form['settings']['facets'][$facet]['limiter'] = array(
194 '#type' => 'textfield',
195 '#title' => t('Query limiter string'),
196 '#default_value' => $settings['facets'][$facet]['limiter'],
199 $form['settings']['facets'][$facet]['max'] = array(
200 '#type' => 'textfield',
201 '#title' => t('Number of terms to display'),
203 '#default_value' => $settings['facets'][$facet]['max'],
207 $form['settings']['facets'][$facet]['orderWeight'] = array(
208 '#type' => 'textfield',
209 '#title' => t('Facet weight'),
210 '#default_value' => $settings['facets'][$facet]['orderWeight'],
215 $form['new_facet'] = array(
216 '#type' => 'fieldset',
217 '#title' => t('Add new facet...'),
219 '#collapsible' => TRUE,
220 '#collapsed' => FALSE
222 $form['new_facet']['canonical'] = array(
223 '#type' => 'textfield',
224 '#title' => t('Canonical name of new facet'),
226 $form['new_facet']['button'] = array(
228 '#value' => t('Add facet'),
229 '#description' => t('Configure additional facets based on Pazpar2/SP termlists'),
230 '#submit' => array('mkdru_add_facet_submit'),
232 'path' => 'ahah-mkdru-facet',
233 'wrapper' => 'mkdru-facets-form-wrapper',
239 function mkdru_add_facet_submit($form, &$form_state) {
240 // $newfacet = $form_state['values']['new_facet']['canonical'];
242 $form_state['values']['settings']['facets'][$newfacet] = NULL;
243 $form_state['rebuild'] = TRUE;
244 return $form_state['values'];
247 function mkdru_add_facet_callback() {
248 // Necessary to work with hook_form
249 module_load_include('inc', 'node', 'node.pages');
251 // Retrieve form from cache
252 $form_state = array('storage' => NULL, 'submitted' => FALSE);
253 $form_build_id = $_POST['form_build_id'];
254 $form = form_get_cache($form_build_id, $form_state);
256 // Run drupal_process_form to call submit handler and update $form_state
257 $args = $form['#parameters'];
258 $form_id = array_shift($args);
259 $form_state['post'] = $form['#post'] = $_POST;
260 $form['#programmed'] = $form['#redirect'] = FALSE;
261 drupal_process_form($form_id, $form, $form_state);
263 // Regenerate form so we can render the new facet part
264 $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
266 // Choose subset of form to redraw.
267 $facet_form = $form['settings']['facets'];
268 // Prevent duplicate wrappers.
269 unset($facet_form['#prefix'], $facet_form['#suffix']);
270 $output = theme('status_messages') . drupal_render($facet_form);
272 // Final rendering callback
273 drupal_json(array('status' => TRUE, 'data' => $output));
279 function mkdru_ding_settings(&$form_state) {
280 $form_state['build_info']['args']['settings'] = variable_get('mkdru_ding', NULL);
281 $form = drupal_retrieve_form('mkdru_settings_form', &$form_state);
282 $form['settings']['#title'] = t('Default search settings');
283 $form['submit'] = array(
285 '#value' => 'Save configuration',
289 function mkdru_ding_settings_submit($form, &$form_state) {
290 variable_set('mkdru_ding', $form_state[values][settings]);
291 drupal_set_message(t('The configuration options have been saved.'));
298 * Implements hook_form()
300 function mkdru_form(&$node, &$form_state) {
301 if (isset($node->settings)) {
302 // Second decode parameter indicates associative array
303 $form_state['build_info']['args']['settings'] = json_decode($node->settings, TRUE);
306 $form = drupal_retrieve_form('mkdru_settings_form', &$form_state);
307 $type = node_get_types('type', $node);
308 $form['title'] = array(
309 '#type' => 'textfield',
310 '#title' => check_plain($type->title_label),
311 '#required' => FALSE,
312 '#default_value' => $node->title,
320 * Implements hook_validate()
322 function mkdru_validate($node) {
327 * Implements hook_insert().
329 function mkdru_insert($node) {
330 $record['nid'] = $node->nid;
331 $record['vid'] = $node->vid;
332 $record['settings'] = json_encode($node->settings);
333 drupal_write_record('mkdru', &$record);
337 * Implements hook_update().
339 function mkdru_update($node) {
340 if ($node->revision) {
341 // New revision; treat it as a new record.
345 $record['nid'] = $node->nid;
346 $record['vid'] = $node->vid;
347 $record['settings'] = json_encode($node->settings);
348 drupal_write_record('mkdru', &$record, 'vid');
353 * Implements hook_nodeapi().
355 * When a node revision is deleted, we need to remove the corresponding record
356 * from our table. The only way to handle revision deletion is by implementing
359 function mkdru_nodeapi(&$node, $op, $teaser, $page) {
361 case 'delete revision':
362 db_query('DELETE FROM {mkdru} WHERE vid = %d', $node->vid);
368 * Implements hook_delete().
370 function mkdru_delete($node) {
371 // Deleting by nid covers all revisions.
372 db_query('DELETE FROM {mkdru} WHERE nid = %d', $node->nid);
379 * Implements hook_load()
381 function mkdru_load($node) {
382 return db_fetch_object(db_query('SELECT * FROM {mkdru} WHERE vid = %d', $node->vid));
386 * Implements hook_theme().
388 function mkdru_theme() {
390 'mkdru_form' => array(
391 'template' => 'mkdru-form',
392 'arguments' => array(),
394 'mkdru_results' => array(
395 'template' => 'mkdru-results',
396 'arguments' => array(),
399 'arguments' => array('node' => NULL),
401 'mkdru_block_search' => array(
402 'template' => 'mkdru-block-search',
403 'arguments' => array('nid' => NULL, 'path' => NULL),
405 'mkdru_block_facet' => array(
406 'template' => 'mkdru-block-facet',
407 'arguments' => array('class' => NULL)
413 * Theme function to include Javascript search client and deps
415 function theme_mkdru_js($node) {
416 $path = drupal_get_path('module', 'mkdru');
417 // Pazpar2 client library.
418 drupal_add_js(variable_get('pz2_js_path', 'pazpar2/js') . '/pz2.js', 'module', 'footer', TRUE, TRUE, FALSE);
419 // jQuery plugin for query string/history manipulation.
420 drupal_add_js($path . '/jquery.ba-bbq.js', 'module', 'footer', TRUE, TRUE, FALSE);
421 drupal_add_js($path . '/mkdru.theme.js', 'module', 'footer', TRUE, TRUE, FALSE);
422 drupal_add_js($path . '/mkdru.client.js', 'module', 'footer', TRUE, TRUE, FALSE);
423 drupal_add_js(array('mkdru' => $node->mkdru), 'setting');
424 drupal_add_js(array('mkdru' =>
426 'settings' => $node->settings,
432 * Implements hook_view()
434 function mkdru_view($node, $teaser = FALSE, $page = FALSE) {
435 $node->content['mkdru_js'] = array(
436 '#value' => theme('mkdru_js', $node),
439 $node->content['mkdru_form'] = array(
440 '#value' => theme('mkdru_form'),
443 $node->content['mkdru_results'] = array(
444 '#value' => theme('mkdru_results'),
451 * Implements hook_block()
453 function mkdru_block($op='list', $delta='sources', $edit=array()) {
457 // D6 has no setting for note type visibility, set
458 // the default to limit facet display to this type
460 if (arg(0) == "node" && is_numeric(arg(1))) {
461 $node = node_load(array("nid" => arg(1)));
462 return $node->type == "mkdru";
466 // NB: block caching is redundant for static content
467 $blocks['mkdru_sources']['info'] = t('mkdru - source facets');
468 $blocks['mkdru_sources']['cache'] = BLOCK_NO_CACHE;
469 $blocks['mkdru_sources']['visibility'] = 2;
470 $blocks['mkdru_sources']['pages'] = $visPHP;
471 $blocks['mkdru_subjects']['info'] = t('mkdru - subject facets');
472 $blocks['mkdru_subjects']['cache'] = BLOCK_NO_CACHE;
473 $blocks['mkdru_subjects']['visibility'] = 2;
474 $blocks['mkdru_subjects']['pages'] = $visPHP;
475 $blocks['mkdru_authors']['info'] = t('mkdru - author facets');
476 $blocks['mkdru_authors']['cache'] = BLOCK_NO_CACHE;
477 $blocks['mkdru_authors']['visibility'] = 2;
478 $blocks['mkdru_authors']['pages'] = $visPHP;
480 $result = db_query("SELECT title, nid FROM {node} WHERE type = 'mkdru';");
481 while ($node = db_fetch_object($result)) {
482 $blocks['mkdru_search_' . $node->nid]['info'] =
483 t('mkdru - search box for "' . $node->title . '"');
484 $blocks['mkdru_sources']['cache'] = BLOCK_NO_CACHE;
490 case 'mkdru_sources':
491 $block['subject'] = t('Source');
492 $block['content'] = theme('mkdru_block_facet', 'mkdru-facet-source');
494 case 'mkdru_subjects':
495 $block['subject'] = t('Subject');
496 $block['content'] = theme('mkdru_block_facet', 'mkdru-facet-subject');
498 case 'mkdru_authors':
499 $block['subject'] = t('Author');
500 $block['content'] = theme('mkdru_block_facet', 'mkdru-facet-author');
503 if (substr($delta, 0, 13) == 'mkdru_search_') {
504 $nid = substr($delta, 13);
505 $block['content'] = theme('mkdru_block_search', $nid, '/node/' . $nid);