Index: api.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/api/api.module,v retrieving revision 1.88.2.6 diff -u -p -r1.88.2.6 api.module --- api.module 23 Jun 2009 07:04:23 -0000 1.88.2.6 +++ api.module 4 Jul 2009 09:43:39 -0000 @@ -179,12 +179,28 @@ function api_menu() { 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); - $items['api/autocomplete'] = array( + $items['api/autocomplete/%/%'] = array( 'page callback' => 'api_autocomplete', + 'page arguments' => array(2, 3), 'access callback' => $access_callback, 'access arguments' => $access_arguments, 'type' => MENU_CALLBACK, ); + $items['api/opensearch/%'] = array( + 'page callback' => 'api_opensearch', + 'page arguments' => array(2), + 'access callback' => $access_callback, + 'access arguments' => $access_arguments, + 'type' => MENU_CALLBACK, + ); + $items['api/suggest/%/%'] = array( + 'page callback' => 'api_suggest', + 'page arguments' => array(2, 3), + 'access callback' => $access_callback, + 'access arguments' => $access_arguments, + 'type' => MENU_CALLBACK, + ); + $items['admin/settings/api'] = array( 'title' => 'API reference', 'description' => 'Configure branches for documentation.', @@ -580,6 +596,13 @@ function api_theme() { function api_init() { drupal_add_css(drupal_get_path('module', 'api') .'/api.css'); drupal_add_js(drupal_get_path('module', 'api') .'/api.js'); + + // Add OpenSearch autodiscovery links. + foreach (array_keys(api_get_branches()) as $branch_name) { + $title = t('Drupal API @branch', array('@branch' => $branch_name)); + $url = url('api/opensearch/'. $branch_name, array('absolute' => TRUE)); + drupal_set_html_head(''); + } } function api_block($op, $delta = NULL, $edit = array()) { @@ -797,10 +820,19 @@ function api_search_listing($branch_name /** * Prepare a listing of potential documentation matches for a branch. + * + * @param $branch_name + * A branch name. + * @param ... + * The string to search for. */ -function api_autocomplete($branch_name, $search = '') { +function api_autocomplete($branch_name) { $matches = array(); - $result = db_query_range("SELECT title FROM {api_documentation} WHERE title LIKE '%%%s%%' AND branch_name = '%s' ORDER BY LENGTH(title)", $search, $branch_name, 0, 20); + // Search strings containing slashes result in multiple args that need to be + // rebuilt. + $search = func_get_args(); + array_shift($search); + $result = _api_fuzzy_search($branch_name, implode('/', $search), 20); while ($r = db_fetch_object($result)) { $matches[$r->title] = check_plain($r->title); } @@ -808,6 +840,91 @@ function api_autocomplete($branch_name, } /** + * Create an OpenSearch plugin for a branch. + * + * @param $branch_name + * A branch name. + * + * @see https://developer.mozilla.org/en/Creating_OpenSearch_plugins_for_Firefox + */ +function api_opensearch($branch_name) { + $valid = api_get_branches(); + if (!isset($valid[$branch_name])) { + return drupal_not_found(); + } + + drupal_set_header('Content-Type: text/xml; charset=utf-8'); + + $short_name = t('Drupal API @branch', array('@branch' => $branch_name)); + $description = t('Drupal @branch API documentation', array('@branch' => $branch_name)); + if ($image = theme_get_setting('favicon')) { + // Get rid of base_path that theme_get_setting() added. + $image = substr($image, strlen(base_path())); + } + else { + // Fall back on default favicon if the theme didn't provide one. + $image = 'misc/favicon.ico'; + } + $image = url($image, array('absolute' => TRUE)); + $search_url = url('api/search/'. $branch_name, array('absolute' => TRUE)) .'/{searchTerms}'; + $suggest_url = url('api/suggest/'. $branch_name, array('absolute' => TRUE)) .'/{searchTerms}'; + $search_form_url = url('api', array('absolute' => TRUE)); + $self_url = url($_GET['q'], array('absolute' => TRUE)); + + print << +$short_name +$description +UTF-8 +$image + + + +$search_form_url + +EOD; +} + +/** + * Prepare a listing of potential documentation matches for a branch for + * OpenSearch. + * + * @param $branch_name + * A branch name. + * @param ... + * The string to search for. + * + * @see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0 + */ +function api_suggest($branch_name) { + $matches = array(); + $search = func_get_args(); + array_shift($search); + $result = _api_fuzzy_search($branch_name, implode('/', $search), 10); + while ($r = db_fetch_object($result)) { + $matches[] = $r->title; + } + print drupal_json(array($search, $matches)); +} + +/** + * Search the database and return the query result handle. + * + * @param $branch_name + * A branch name. + * @param $search + * The string to search for. + * @param $limit + * Maximum number of search results to provide. + */ +function _api_fuzzy_search($branch_name, $search, $limit = 10) { + // Escape underscore to produce more accurate results. + $search = str_replace('_', '\_', $search); + return db_query_range("SELECT title FROM {api_documentation} WHERE title LIKE '%%%s%%' AND branch_name = '%s' ORDER BY LENGTH(title)", $search, $branch_name, 0, $limit); +} + +/** * Menu callback; displays the main documentation page. */ function api_page_branch($branch_name) {