From: Thierry Parmentelat Date: Tue, 6 Jan 2009 12:32:53 +0000 (+0000) Subject: Preparing to use a separate 6.x drupal X-Git-Tag: PLEWWW-4.3-1~146 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=c71ee653ea076d6b67c5d9ddb630b2604480f0b7;p=plewww.git Preparing to use a separate 6.x drupal * taking out everything that originally belonged to drupal * the new module temporarily moved in drupal.module * httpd config renamed as planetlab.conf --- diff --git a/CHANGELOG.txt b/CHANGELOG.txt deleted file mode 100644 index decbbf2..0000000 --- a/CHANGELOG.txt +++ /dev/null @@ -1,542 +0,0 @@ -// $Id: CHANGELOG.txt 144 2007-03-28 07:52:20Z thierry $ - -Drupal 4.7.3, 2006-08-02 ------------------------- -- fixed security issue (XSS), see SA-2006-011 - -Drupal 4.7.2, 2006-06-01 ------------------------- -- fixed critical upload issue, see SA-2006-007 -- fixed taxonomy XSS issue, see SA-2006-008 -- fixed a variety of small bugs. - -Drupal 4.7.1, 2006-05-24 ------------------------- -- fixed critical SQL issue, see SA-2006-005 -- fixed a serious upgrade related bug. -- fixed a variety of small bugs. - -Drupal 4.7.0, 2006-05-01 ------------------------- -- added free tagging support. -- added a site-wide contact form. -- theme system: - * added the PHPTemplate theme engine and removed the Xtemplate engine. - * converted the bluemarine theme from XTemplate to PHPTemplate. - * converted the pushbutton theme from XTemplate to PHPTemplate. -- usability: - * reworked the 'request new password' functionality. - * reworked the node and comment edit forms. - * made it easy to add nodes to the navigation menu. - * added site 'offline for maintenance' feature. - * added support for auto-complete forms (AJAX). - * added support for collapsible page sections (JS). - * added support for resizable text fields (JS). - * improved file upload functionality (AJAX). - * reorganized some settings pages. - * added friendly database error screens. - * improved styling of update.php. -- refactored the forms API. - * made it possible to alter, extend or theme forms. -- comment system: - * added support for "mass comment operations" to ease repetitive tasks. - * comment moderation has been removed. -- node system: - * reworked the revision functionality. - * removed the bookmarklet code. Third-party modules can now handle - this. -- upgrade system: - * allows contributed modules to plug into the upgrade system. -- profiles: - * added a block to display author information along with posts. - * added support for private profile fields. -- statistics module: - * added the ability to track page generation times. - * made it possible to block certain IPs/hostnames. -- block system: - * added support for theme-specific block regions. -- syndication: - * made the aggregator module parse Atom feeds. - * made the aggregator generate RSS feeds. - * added RSS feed settings. -- XML-RPC: - * replaced the XML-RPC library by a better one. -- performance: - * added 'loose caching' option for high-traffic sites. - * improved performance of path aliasing. - * added the ability to track page generation times. -- internationalization: - * improved Unicode string handling API. - * added support for PHP's multibyte string module. -- added support for PHP5's 'mysqli' extension. -- search module: - * made indexer smarter and more robust. - * added advanced search operators (e.g. phrase, node type, ...). - * added customizable result ranking. -- PostgreSQL support: - * removed dependency on PL/pgSQL procedural language. -- menu system: - * added support for external URLs. -- queue module: - * removed from core. -- HTTP handling: - * added support for a tolerant Base URL. - * output URIs relative to the root, without a base tag. - -Drupal 4.6.6, 2006-03-13 ------------------------- -- fixed bugs, including 4 security vulnerabilities. - -Drupal 4.6.5, 2005-12-12 ------------------------- -- fixed bugs: no critical bugs were identified. - -Drupal 4.6.4, 2005-11-30 ------------------------- -- fixed bugs, including 3 security vulnerabilities. - -Drupal 4.6.3, 2005-08-15 ------------------------- -- fixed bugs, including a critical "arbitrary PHP code execution" bug. - -Drupal 4.6.2, 2005-06-29 ------------------------- -- fixed bugs, including two critical "arbitrary PHP code execution" bugs. - -Drupal 4.6.1, 2005-06-01 ------------------------- -- fixed bugs, including a critical input validation bug. - -Drupal 4.6.0, 2005-04-15 ------------------------- -- PHP5 compliance -- search: - * added UTF-8 support to make it work with all languages. - * improved search indexing algorithm. - * improved search output. - * impose a throttle on indexing of large sites. - * added search block. -- syndication: - * made the ping module ping pingomatic.com which, in turn, will ping all the major ping services. - * made Drupal generate RSS 2.0 feeds. - * made RSS feeds extensible. - * added categories to RSS feeds. - * added enclosures to RSS feeds. -- flood control mechanism: - * added a mechanism to throttle certain operations. -- usability: - * refactored the block configuration pages. - * refactored the statistics pages. - * refactored the watchdog pages. - * refactored the throttle module configuration. - * refactored the access rules page. - * refactored the content administration page. - * introduced forum configuration pages. - * added a 'add child page' link to book pages. -- contact module: - * added a simple contact module that allows users to contact each other using e-mail. -- multi-site configuration: - * made it possible to run multiple sites from a single code base. -- added an image API: enables better image handling. -- block system: - * extended the block visibility settings. -- theme system: - * added new theme functions. -- database backend: - * the PEAR database backend is no longer supported. -- performance: - * improved performance of the forum topics block. - * improved performance of the tracker module. - * improved performance of the node pages. -- documentation: - * improved and extended PHPDoc/Doxygen comments. - -Drupal 4.5.8, 2006-03-13 ------------------------- -- fixed bugs, including 3 security vulnerabilities. - -Drupal 4.5.7, 2005-12-12 ------------------------- -- fixed bugs: no critical bugs were identified. - -Drupal 4.5.6, 2005-11-30 ------------------------- -- fixed bugs, including 3 security vulnerabilities. - -Drupal 4.5.5, 2005-08-15 ------------------------- -- fixed bugs, including a critical "arbitrary PHP code execution" bug. - -Drupal 4.5.4, 2005-06-29 ------------------------- -- fixed bugs, including two critical "arbitrary PHP code execution" bugs. - -Drupal 4.5.3, 2005-06-01 ------------------------- -- fixed bugs, including a critical input validation bug. - -Drupal 4.5.2, 2005-01-15 ------------------------- -- fixed bugs: a cross-site scripting (XSS) vulnerability has been fixed. - -Drupal 4.5.1, 2004-12-01 ------------------------- -- fixed bugs: no critical bugs were identified. - -Drupal 4.5.0, 2004-10-18 ------------------------- -- navigation: - * made it possible to add, delete, rename and move menu items. - * introduced tabs and subtabs for local tasks. - * reorganized the navigation menus. -- user management: - * added support for multiple roles per user. - * made it possible to add custom profile fields. - * made it possible to browse user profiles by field. -- node system: - * added support for node-level permissions. -- comment module: - * made it possible to leave contact information without having to register. -- upload module: - * added support for uploading documents (includes images). -- forum module: - * added support for sticky forum topics. - * made it possible to track forum topics. -- syndication: - * added support for RSS ping-notifications of http://technorati.com/. - * refactored the categorization of syndicated news items. - * added an URL alias for 'rss.xml'. - * improved date parsing. -- database backend: - * added support for multiple database connections. - * the PostgreSQL backend does no longer require PEAR. -- theme system: - * changed all GIFs to PNGs. - * reorganised the handling of themes, template engines, templates and styles. - * unified and extended the available theme settings. - * added theme screenshots. -- blocks: - * added 'recent comments' block. - * added 'categories' block. -- blogger API: - * added support for auto-discovery of blogger API via RSD. -- performance: - * added support for sending gzip compressed pages. - * improved performance of the forum module. -- accessibility: - * improved the accessibility of the archive module's calendar. - * improved form handling and error reporting. - * added HTTP redirects to prevent submitting twice when refreshing right after a form submission. -- refactored 403 (forbidden) handling and added support for custom 403 pages. -- documentation: - * added PHPDoc/Doxygen comments. -- filter system: - * added support for using multiple input formats on the site - * expanded the embedded PHP-code feature so it can be used everywhere - * added support for role-dependant filtering, through input formats -- UI translation: - * managing translations is now completely done through the administration interface - * added support for importing/exporting gettext .po files - -Drupal 4.4.3, 2005-06-01 ------------------------- -- fixed bugs, including a critical input validation bug. - -Drupal 4.4.2, 2004-07-04 ------------------------- -- fixed bugs: no critical bugs were identified. - -Drupal 4.4.1, 2004-05-01 ------------------------- -- fixed bugs: no critical bugs were identified. - -Drupal 4.4.0, 2004-04-01 ------------------------- -- added support for the MetaWeblog API and MovableType extensions. -- added a file API: enables better document management. -- improved the watchdog and search module to log search keys. -- news aggregator: - * added support for conditional GET. - * added OPML feed subscription list. - * added support for , , , , and . -- comment module: - * made it possible to disable the "comment viewing controls". -- performance: - * improved module loading when serving cached pages. - * made it possible to automatically disable modules when under heavy load. - * made it possible to automatically disable blocks when under heavy load. - * improved performance and memory footprint of the locale module. -- theme system: - * made all theme functions start with 'theme_'. - * made all theme functions return their output. - * migrated away from using the BaseTheme class. - * added many new theme functions and refactored existing theme functions. - * added avatar support to 'Xtemplate'. - * replaced theme 'UnConeD' by 'Chameleon'. - * replaced theme 'Marvin' by 'Pushbutton'. -- usability: - * added breadcrumb navigation to all pages. - * made it possible to add context-sensitive help to all pages. - * replaced drop-down menus by radio buttons where appropriate. - * removed the 'magic_quotes_gpc = 0' requirement. - * added a 'book navigation' block. -- accessibility: - * made themes degrade gracefully in absence of CSS. - * grouped form elements using '
' and '' tags. - * added '
\n"; - -} - -/** - * Format a radio button. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: required, return_value, value, attributes, title, description - * @return - * A themed HTML string representing the form item group. - */ -function theme_radio($element) { - _form_set_class($element, array('form-radio')); - $output = ''; - if (!is_null($element['#title'])) { - $output = ''; - } - return theme('form_element', NULL, $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/** - * Format a set of radio buttons. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, options, description, required and attributes. - * @return - * A themed HTML string representing the radio button set. - */ -function theme_radios($element) { - if ($element['#title'] || $element['#description']) { - return theme('form_element', $element['#title'], $element['#children'], $element['#description'], NULL, $element['#required'], form_get_error($element)); - } - else { - return $element['#children']; - } -} - -/** - * Format a password_confirm item. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, id, required, error. - * @return - * A themed HTML string representing the form item. - */ -function theme_password_confirm($element) { - return theme('form_element', $element['#title'], '
'. $element['#children']. '
', $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/* - * Expand a password_confirm field into two text boxes. - */ -function expand_password_confirm($element) { - $element['pass1'] = array('#type' => 'password', '#size' => 12, '#value' => $element['#value']['pass1']); - $element['pass2'] = array('#type' => 'password', '#size' => 12, '#value' => $element['#value']['pass2']); - $element['#validate'] = array('password_confirm_validate' => array()); - $element['#tree'] = TRUE; - - return $element; -} - -/** - * Validate password_confirm element. - */ -function password_confirm_validate($form) { - $pass1 = trim($form['pass1']['#value']); - if (!empty($pass1)) { - $pass2 = trim($form['pass2']['#value']); - if ($pass1 != $pass2) { - form_error($form, t('The specified passwords do not match.')); - } - } - elseif ($form['#required'] && !empty($_POST['edit'])) { - form_error($form, t('Password field is required.')); - } - - // Password field must be converted from a two-element array into a single - // string regardless of validation results. - form_set_value($form['pass1'], NULL); - form_set_value($form['pass2'], NULL); - form_set_value($form, $pass1); - - return $form; -} - -/** - * Format a date selection element. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, options, description, required and attributes. - * @return - * A themed HTML string representing the date selection boxes. - */ -function theme_date($element) { - $output = '
' . $element['#children'] . '
'; - return theme('form_element', $element['#title'], $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/** - * Roll out a single date element. - */ -function expand_date($element) { - // Default to current date - if (!isset($element['#value'])) { - $element['#value'] = array('day' => format_date(time(), 'custom', 'j'), - 'month' => format_date(time(), 'custom', 'n'), - 'year' => format_date(time(), 'custom', 'Y')); - } - - $element['#tree'] = TRUE; - - // Determine the order of day, month, year in the site's chosen date format. - $format = variable_get('date_format_short', 'm/d/Y'); - $sort = array(); - $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j')); - $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M')); - $sort['year'] = strpos($format, 'Y'); - asort($sort); - $order = array_keys($sort); - - // Output multi-selector for date - foreach ($order as $type) { - switch ($type) { - case 'day': - $options = drupal_map_assoc(range(1, 31)); - break; - case 'month': - $options = drupal_map_assoc(range(1, 12), 'map_month'); - break; - case 'year': - $options = drupal_map_assoc(range(1900, 2050)); - break; - } - $parents = $element['#parents']; - $parents[] = $type; - $element[$type] = array( - '#type' => 'select', - '#value' => $element['#value'][$type], - '#attributes' => $element['#attributes'], - '#options' => $options, - ); - } - - return $element; -} - -/** - * Validates the FAPI date type to stop dates like 30/Feb/2006 - */ -function date_validate($form) { - if (!checkdate($form['#value']['month'], $form['#value']['day'], $form['#value']['year'])) { - form_error($form, t('The specified date is invalid.')); - } -} - -/** - * Helper function for usage with drupal_map_assoc to display month names. - */ -function map_month($month) { - return format_date(gmmktime(0, 0, 0, $month, 2, 1970), 'custom', 'M', 0); -} - -/** - * Helper function to load value from default value for checkboxes - */ -function checkboxes_value(&$form) { - $value = array(); - foreach ((array)$form['#default_value'] as $key) { - $value[$key] = 1; - } - $form['#value'] = $value; -} - -/** - * If no default value is set for weight select boxes, use 0. - */ -function weight_value(&$form) { - if (isset($form['#default_value'])) { - $form['#value'] = $form['#default_value']; - } - else { - $form['#value'] = 0; - } -} - -/** - * Roll out a single radios element to a list of radios, - * using the options array as index. - */ -function expand_radios($element) { - if (count($element['#options']) > 0) { - foreach ($element['#options'] as $key => $choice) { - if (!isset($element[$key])) { - $element[$key] = array('#type' => 'radio', '#title' => $choice, '#return_value' => $key, '#default_value' => $element['#default_value'], '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#spawned' => TRUE); - } - } - } - return $element; -} - -/** - * Format a form item. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, description, required, error - * @return - * A themed HTML string representing the form item. - */ -function theme_item($element) { - return theme('form_element', $element['#title'], $element['#value'] . $element['#children'], $element['#description'], $element['#id'], $element['#required'], $element['#error']); -} - -/** - * Format a checkbox. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, return_value, description, required - * @return - * A themed HTML string representing the checkbox. - */ -function theme_checkbox($element) { - _form_set_class($element, array('form-checkbox')); - $checkbox = ''; - - if (!is_null($element['#title'])) { - $checkbox = ''; - } - - return theme('form_element', NULL, $checkbox, $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/** - * Format a set of checkboxes. - * - * @param $element - * An associative array containing the properties of the element. - * @return - * A themed HTML string representing the checkbox set. - */ -function theme_checkboxes($element) { - if ($element['#title'] || $element['#description']) { - return theme('form_element', $element['#title'], $element['#children'], $element['#description'], NULL, $element['#required'], form_get_error($element)); - } - else { - return $element['#children']; - } -} - -function expand_checkboxes($element) { - $value = is_array($element['#value']) ? $element['#value'] : array(); - $element['#tree'] = TRUE; - if (count($element['#options']) > 0) { - if (!isset($element['#default_value']) || $element['#default_value'] == 0) { - $element['#default_value'] = array(); - } - foreach ($element['#options'] as $key => $choice) { - if (!isset($element[$key])) { - $element[$key] = array('#type' => 'checkbox', '#processed' => TRUE, '#title' => $choice, '#return_value' => $key, '#default_value' => isset($value[$key]), '#attributes' => $element['#attributes']); - } - } - } - return $element; -} - -function theme_submit($element) { - return theme('button', $element); -} - -function theme_button($element) { - //Make sure not to overwrite classes - if (isset($element['#attributes']['class'])) { - $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class']; - } - else { - $element['#attributes']['class'] = 'form-'. $element['#button_type']; - } - - return '\n"; -} - -/** - * Format a hidden form field. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: value, edit - * @return - * A themed HTML string representing the hidden form field. - */ -function theme_hidden($element) { - return '\n"; -} - -/** - * Format a textfield. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, description, size, maxlength, required, attributes autocomplete_path - * @return - * A themed HTML string representing the textfield. - */ -function theme_textfield($element) { - $size = $element['#size'] ? ' size="' . $element['#size'] . '"' : ''; - $class = array('form-text'); - $extra = ''; - if ($element['#autocomplete_path']) { - drupal_add_js('misc/autocomplete.js'); - $class[] = 'form-autocomplete'; - $extra = ''; - } - _form_set_class($element, $class); - $output = ''; - return theme('form_element', $element['#title'], $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element)). $extra; -} - -/** - * Format a form. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: action, method, attributes, children - * @return - * A themed HTML string representing the form. - */ -function theme_form($element) { - // Anonymous div to satisfy XHTML compliance. - $action = $element['#action'] ? 'action="' . check_url($element['#action']) . '" ' : ''; - return '
\n
". $element['#children'] ."\n
\n"; -} - -/** - * Format a textarea. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, value, description, rows, cols, required, attributes - * @return - * A themed HTML string representing the textarea. - */ -function theme_textarea($element) { - $class = array('form-textarea'); - if ($element['#resizable'] !== false) { - drupal_add_js('misc/textarea.js'); - $class[] = 'resizable'; - } - - $cols = $element['#cols'] ? ' cols="'. $element['#cols'] .'"' : ''; - _form_set_class($element, $class); - return theme('form_element', $element['#title'], ''. check_plain($element['#value']) .'', $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/** - * Format HTML markup for use in forms. - * - * This is used in more advanced forms, such as theme selection and filter format. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: prefix, value, children and suffix. - * @return - * A themed HTML string representing the HTML markup. - */ - -function theme_markup($element) { - return $element['#value'] . $element['#children']; -} - -/** -* Format a password field. -* -* @param $element -* An associative array containing the properties of the element. -* Properties used: title, value, description, size, maxlength, required, attributes -* @return -* A themed HTML string representing the form. -*/ -function theme_password($element) { - $size = $element['#size'] ? ' size="'. $element['#size'] .'" ' : ''; - - _form_set_class($element, array('form-text')); - $output = ''; - - return theme('form_element', $element['#title'], $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/** - * Format a weight selection menu. - * - * @param $element - * An associative array containing the properties of the element. - * Properties used: title, delta, description - * @return - * A themed HTML string representing the form. - */ -function theme_weight($element) { - for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) { - $weights[$n] = $n; - } - $element['#options'] = $weights; - $element['#type'] = 'select'; - - return form_render($element); -} - -/** - * Format a file upload field. - * - * @param $title - * The label for the file upload field. - * @param $name - * The internal name used to refer to the field. - * @param $size - * A measure of the visible size of the field (passed directly to HTML). - * @param $description - * Explanatory text to display after the form item. - * @param $required - * Whether the user must upload a file to the field. - * @return - * A themed HTML string representing the field. - * - * For assistance with handling the uploaded file correctly, see the API - * provided by file.inc. - */ -function theme_file($element) { - _form_set_class($element, array('form-file')); - return theme('form_element', $element['#title'], '\n", $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); -} - -/** - * Sets a form element's class attribute. - * - * Adds 'required' and 'error' classes as needed. - * - * @param &$element - * The form element - * @param $name - * Array of new class names to be added - */ -function _form_set_class(&$element, $class = array()) { - if ($element['#required']) { - $class[] = 'required'; - } - if (form_get_error($element)){ - $class[] = 'error'; - } - if (isset($element['#attributes']['class'])) { - $class[] = $element['#attributes']['class']; - } - $element['#attributes']['class'] = implode(' ', $class); -} - -/** - * Remove invalid characters from an HTML ID attribute string. - * - * @param $id - * The ID to clean - * @return - * The cleaned ID - */ -function form_clean_id($id = NULL) { - $id = str_replace('][', '-', $id); - return $id; -} - -/** - * @} End of "defgroup form". - */ diff --git a/includes/image.inc b/includes/image.inc deleted file mode 100644 index cebb648..0000000 --- a/includes/image.inc +++ /dev/null @@ -1,303 +0,0 @@ - descriptive title. - */ -function image_get_available_toolkits() { - $toolkits = file_scan_directory('includes', 'image\..*\.inc$'); - - $output = array(); - foreach ($toolkits as $file => $toolkit) { - include_once "./$file"; - $function = str_replace('.', '_', $toolkit->name) .'_info'; - if (function_exists($function)) { - $info = $function(); - $output[$info['name']] = $info['title']; - } - } - $output['gd'] = t('Built-in GD2 toolkit'); - return $output; -} - -/** - * Retrieve the name of the currently used toolkit. - * - * @return String containing the name of the toolkit. - */ -function image_get_toolkit() { - static $toolkit; - if (!$toolkit) { - $toolkit = variable_get('image_toolkit', 'gd'); - $toolkit_file = './includes/image.'.$toolkit.'.inc'; - if ($toolkit != 'gd' && file_exists($toolkit_file)) { - include_once $toolkit_file; - } - elseif (!image_gd_check_settings()) { - $toolkit = false; - } - } - - return $toolkit; -} - -/** - * Invokes the given method using the currently selected toolkit. - * - * @param $method A string containing the method to invoke. - * @param $params An optional array of parameters to pass to the toolkit method. - * - * @return Mixed values (typically Boolean for successful operation). - */ -function image_toolkit_invoke($method, $params = array()) { - if ($toolkit = image_get_toolkit()) { - $function = 'image_'. $toolkit .'_'. $method; - if (function_exists($function)) { - return call_user_func_array($function, $params); - } - else { - watchdog('php', t("The selected image handling toolkit '%toolkit' can not correctly process '%function'.", array('%toolkit' => "$toolkit", '%function' => "$function")), WATCHDOG_ERROR); - return false; - } - } - else { - if ($method == 'settings') { - return image_gd_settings(); - } - } -} - - -/** - * Get details about an image. - * - * @return array containing information about the image - * 'width': image's width in pixels - * 'height': image's height in pixels - * 'extension': commonly used extension for the image - * 'mime_type': image's MIME type ('image/jpeg', 'image/gif', etc.) - * 'file_size': image's physical size (in bytes) - */ -function image_get_info($file) { - if (!is_file($file)) { - return false; - } - - $details = false; - $data = @getimagesize($file); - $file_size = @filesize($file); - - if (isset($data) && is_array($data)) { - $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png'); - $extension = array_key_exists($data[2], $extensions) ? $extensions[$data[2]] : ''; - $details = array('width' => $data[0], - 'height' => $data[1], - 'extension' => $extension, - 'file_size' => $file_size, - 'mime_type' => $data['mime']); - } - - return $details; -} - -/** - * Scales an image to the given width and height while maintaining aspect - * ratio. - * - * @param $source The filepath of the source image - * @param $destination The file path of the destination image - * @param $width The target width - * @param $height The target height - * - * @return True or false, based on success - */ -function image_scale($source, $destination, $width, $height) { - $info = image_get_info($source); - - // don't scale up - if ($width > $info['width'] && $height > $info['height']) { - return false; - } - - $aspect = $info['height'] / $info['width']; - if ($aspect < $height / $width) { - $width = (int)min($width, $info['width']); - $height = (int)round($width * $aspect); - } - else { - $height = (int)min($height, $info['height']); - $width = (int)round($height / $aspect); - } - - return image_toolkit_invoke('resize', array($source, $destination, $width, $height)); -} - -/** - * Resize an image to the given dimensions (ignoring aspect ratio). - * - * @param $source The filepath of the source image. - * @param $destination The file path of the destination image. - * @param $width The target width. - * @param $height The target height. - */ -function image_resize($source, $destination, $width, $height) { - return image_toolkit_invoke('resize', array($source, $destination, $width, $height)); -} - -/** - * Rotate an image by the given number of degrees. - * - * @param $source The filepath of the source image - * @param $destination The file path of the destination image - * @param $degrees The number of (clockwise) degrees to rotate the image - */ -function image_rotate($source, $destination, $degrees) { - return image_toolkit_invoke('rotate', array($source, $destination, $degrees)); -} - -/** - * Crop an image to the rectangle specified by the given rectangle. - * - * @param $source The filepath of the source image - * @param $destination The file path of the destination image - * @param $x The top left co-ordinate of the crop area (x axis value) - * @param $y The top left co-ordinate of the crop area (y axis value) - * @param $width The target width - * @param $height The target height - */ -function image_crop($source, $destination, $x, $y, $width, $height) { - return image_toolkit_invoke('crop', array($source, $destination, $x, $y, $width, $height)); -} - -/** - * GD2 toolkit functions - * With the minimal requirements of PHP 4.3 for Drupal, we use the built-in version of GD. - */ - -/** - * Retrieve settings for the GD2 toolkit (not used). - */ -function image_gd_settings() { - if (image_gd_check_settings()) { - return t('The built-in GD2 toolkit is installed and working properly.'); - } - else { - form_set_error('image_toolkit', t("The built-in GD image toolkit requires that the GD module for PHP be installed and configured properly. For more information see %url.", array('%url' => 'http://php.net/image'))); - return false; - } -} - -/** - * Verify GD2 settings (that the right version is actually installed). - * - * @return boolean - */ -function image_gd_check_settings() { - if ($check = get_extension_funcs('gd')) { - if (in_array('imagegd2', $check)) { - // GD2 support is available. - return true; - } - } - return false; -} - -/** - * Scale an image to the specified size using GD. - */ -function image_gd_resize($source, $destination, $width, $height) { - if (!file_exists($source)) { - return false; - } - - $info = image_get_info($source); - if (!$info) { - return false; - } - - $im = image_gd_open($source, $info['extension']); - if (!$im) { - return false; - } - - $res = imageCreateTrueColor($width, $height); - imageCopyResampled($res, $im, 0, 0, 0, 0, $width, $height, $info['width'], $info['height']); - $result = image_gd_close($res, $destination, $info['extension']); - - imageDestroy($res); - imageDestroy($im); - - return $result; -} - -/** - * Rotate an image the given number of degrees. - */ -function image_gd_rotate($source, $destination, $degrees, $bg_color = 0) { - if (!function_exists('imageRotate')) { - return false; - } - - $info = image_get_info($source); - if (!$info) { - return false; - } - - $im = image_gd_open($source, $info['extension']); - if (!$im) { - return false; - } - - $res = imageRotate($im, $degrees, $bg_color); - $result = image_gd_close($res, $destination, $info['extension']); - - return $result; -} - -/** - * Crop an image using the GD toolkit. - */ -function image_gd_crop($source, $destination, $x, $y, $width, $height) { - $info = image_get_info($source); - if (!$info) { - return false; - } - - $im = image_gd_open($source, $info['extension']); - $res = imageCreateTrueColor($width, $height); - imageCopy($res, $im, 0, 0, $x, $y, $width, $height); - $result = image_gd_close($res, $destination, $info['extension']); - - imageDestroy($res); - imageDestroy($im); - - return $result; -} - -/** - * GD helper function to create an image resource from a file. - */ -function image_gd_open($file, $extension) { - $extension = str_replace('jpg', 'jpeg', $extension); - $open_func = 'imageCreateFrom'. $extension; - if (!function_exists($open_func)) { - return false; - } - return $open_func($file); -} - -/** - * GD helper to write an image resource to a destination file. - */ -function image_gd_close($res, $destination, $extension) { - $extension = str_replace('jpg', 'jpeg', $extension); - $close_func = 'image'. $extension; - if (!function_exists($close_func)) { - return false; - } - return $close_func($res, $destination); -} - - diff --git a/includes/install.inc b/includes/install.inc deleted file mode 100644 index 7a12c31..0000000 --- a/includes/install.inc +++ /dev/null @@ -1,81 +0,0 @@ -name] = $row->schema_version; - } - } - - return $versions[$module]; -} - -/** - * Update the installed version information for a module. - * - * @param $module - * A module name. - * @param $version - * The new schema version. - */ -function drupal_set_installed_schema_version($module, $version) { - db_query("UPDATE {system} SET schema_version = %d WHERE name = '%s'", $version, $module); -} diff --git a/includes/locale.inc b/includes/locale.inc deleted file mode 100644 index 5c6d83e..0000000 --- a/includes/locale.inc +++ /dev/null @@ -1,1548 +0,0 @@ -lid, $code); - } - - // If only the language was added, and not a PO file import triggered - // the language addition, we need to inform the user on how to start - // a translation - if ($onlylanguage) { - drupal_set_message(t('The language %locale has been created, and can now be used to import a translation. More information is available in the help screen.', array('%locale' => theme('placeholder', t($name)), '%locale-help' => url('admin/help/locale')))); - } - else { - drupal_set_message(t('The language %locale has been created.', array('%locale' => theme('placeholder', t($name))))); - } - - watchdog('locale', t('The %language language (%locale) has been created.', array('%language' => theme('placeholder', $name), '%locale' => theme('placeholder', $code)))); -} - -/** - * User interface for the language management screen. - */ -function _locale_admin_manage_screen() { - $languages = locale_supported_languages(TRUE, TRUE); - - $options = array(); - $form['name'] = array('#tree' => TRUE); - foreach ($languages['name'] as $key => $lang) { - $options[$key] = ''; - $status = db_fetch_object(db_query("SELECT isdefault, enabled FROM {locales_meta} WHERE locale = '%s'", $key)); - if ($status->enabled) { - $enabled[] = $key; - } - if ($status->isdefault) { - $isdefault = $key; - } - if ($key == 'en') { - $form['name']['en'] = array('#value' => check_plain($lang)); - } - else { - $original = db_fetch_object(db_query("SELECT COUNT(*) AS strings FROM {locales_source}")); - $translation = db_fetch_object(db_query("SELECT COUNT(*) AS translation FROM {locales_target} WHERE locale = '%s' AND translation != ''", $key)); - - $ratio = ($original->strings > 0 && $translation->translation > 0) ? round(($translation->translation/$original->strings)*100., 2) : 0; - - $form['name'][$key] = array('#type' => 'textfield', - '#default_value' => $lang, - '#size' => 15, - '#maxlength' => 64, - ); - $form['translation'][$key] = array('#value' => "$translation->translation/$original->strings ($ratio%)"); - } - } - $form['enabled'] = array('#type' => 'checkboxes', - '#options' => $options, - '#default_value' => $enabled, - ); - $form['site_default'] = array('#type' => 'radios', - '#options' => $options, - '#default_value' => $isdefault, - ); - $form['submit'] = array('#type' => 'submit', '#value' => t('Save configuration')); - - return drupal_get_form('_locale_admin_manage_screen', $form, 'locale_admin_manage_screen'); -} - -/** - * Theme the locale admin manager form. - */ -function theme_locale_admin_manage_screen($form) { - foreach ($form['name'] as $key => $element) { - // Do not take form control structures. - if (is_array($element) && element_child($key)) { - $rows[] = array(check_plain($key), form_render($form['name'][$key]), form_render($form['enabled'][$key]), form_render($form['site_default'][$key]), ($key != 'en' ? form_render($form['translation'][$key]) : message_na()), ($key != 'en' ? l(t('delete'), 'admin/locale/language/delete/'. $key) : '')); - } - } - $header = array(array('data' => t('Code')), array('data' => t('English name')), array('data' => t('Enabled')), array('data' => t('Default')), array('data' => t('Translated')), array('data' => t('Operations'))); - $output = theme('table', $header, $rows); - $output .= form_render($form); - - return $output; -} - -/** - * Process locale admin manager form submissions. - */ -function _locale_admin_manage_screen_submit($form_id, $form_values) { - // Save changes to existing languages. - $languages = locale_supported_languages(FALSE, TRUE); - foreach($languages['name'] as $key => $value) { - if ($form_values['site_default'] == $key) { - $form_values['enabled'][$key] = 1; // autoenable the default language - } - $enabled = $form_values['enabled'][$key] ? 1 : 0; - if ($key == 'en') { - // Disallow name change for English locale. - db_query("UPDATE {locales_meta} SET isdefault = %d, enabled = %d WHERE locale = 'en'", ($form_values['site_default'] == $key), $enabled); - } - else { - db_query("UPDATE {locales_meta} SET name = '%s', isdefault = %d, enabled = %d WHERE locale = '%s'", $form_values['name'][$key], ($form_values['site_default'] == $key), $enabled, $key); - } - } - drupal_set_message(t('Configuration saved.')); - - // Changing the locale settings impacts the interface: - cache_clear_all(); - - return 'admin/locale/language/overview'; -} - -/** - * User interface for the language addition screen. - */ -function _locale_admin_manage_add_screen() { - $isocodes = _locale_prepare_iso_list(); - - $form = array(); - $form['language list'] = array('#type' => 'fieldset', - '#title' => t('Language list'), - '#collapsible' => TRUE, - ); - $form['language list']['langcode'] = array('#type' => 'select', - '#title' => t('Language name'), - '#default_value' => key($isocodes), - '#options' => $isocodes, - '#description' => t('Select your language here, or add it below, if you are unable to find it.'), - ); - $form['language list']['submit'] = array('#type' => 'submit', '#value' => t('Add language')); - - $output = drupal_get_form('locale_add_language_form', $form); - - $form = array(); - $form['custom language'] = array('#type' => 'fieldset', - '#title' => t('Custom language'), - '#collapsible' => TRUE, - ); - $form['custom language']['langcode'] = array('#type' => 'textfield', - '#title' => t('Language code'), - '#size' => 12, - '#maxlength' => 60, - '#required' => TRUE, - '#description' => t("Commonly this is an ISO 639 language code with an optional country code for regional variants. Examples include 'en', 'en-US' and 'zh-cn'.", array('%iso-codes' => 'http://www.w3.org/WAI/ER/IG/ert/iso639.htm')), - ); - $form['custom language']['langname'] = array('#type' => 'textfield', - '#title' => t('Language name in English'), - '#maxlength' => 64, - '#required' => TRUE, - '#description' => t('Name of the language. Will be available for translation in all languages.'), - ); - $form['custom language']['submit'] = array('#type' => 'submit', '#value' => t('Add custom language')); - - // Use the validation and submit functions of the add language form. - $output .= drupal_get_form('locale_custom_language_form', $form, 'locale_add_language_form'); - - return $output; -} - -/** - * Validate the language addition form. - */ -function locale_add_language_form_validate($form_id, $form_values) { - if ($duplicate = db_num_rows(db_query("SELECT locale FROM {locales_meta} WHERE locale = '%s'", $form_values['langcode'])) != 0) { - form_set_error(t('The language %language (%code) already exists.', array('%language' => theme('placeholder', check_plain($form_values['langname'])), '%code' => theme('placeholder', $form_values['langcode'])))); - } - - if (!isset($form_values['langname'])) { - $isocodes = _locale_get_iso639_list(); - if (!isset($isocodes[$form_values['langcode']])) { - form_set_error('langcode', t('Invalid language code.')); - } - } -} - -/** - * Process the language addition form submission. - */ -function locale_add_language_form_submit($form_id, $form_values) { - if (isset($form_values['langname'])) { - // Custom language form. - _locale_add_language($form_values['langcode'], $form_values['langname']); - } - else { - $isocodes = _locale_get_iso639_list(); - _locale_add_language($form_values['langcode'], $isocodes[$form_values['langcode']][0]); - } - - return 'admin/locale'; -} - -/** - * User interface for the translation import screen. - */ -function _locale_admin_import_screen() { - $languages = locale_supported_languages(FALSE, TRUE); - $languages = array_map('t', $languages['name']); - unset($languages['en']); - - if (!count($languages)) { - $languages = _locale_prepare_iso_list(); - } - else { - $languages = array( - t('Already added languages') => $languages, - t('Languages not yet added') => _locale_prepare_iso_list() - ); - } - - $form = array(); - $form['import'] = array('#type' => 'fieldset', - '#title' => t('Import translation'), - ); - $form['import']['file'] = array('#type' => 'file', - '#title' => t('Language file'), - '#size' => 50, - '#description' => t('A gettext Portable Object (.po) file.'), - ); - $form['import']['langcode'] = array('#type' => 'select', - '#title' => t('Import into'), - '#options' => $languages, - '#description' => t('Choose the language you want to add strings into. If you choose a language which is not yet set up, then it will be added.'), - ); - $form['import']['mode'] = array('#type' => 'radios', - '#title' => t('Mode'), - '#default_value' => 'overwrite', - '#options' => array('overwrite' => t('Strings in the uploaded file replace existing ones, new ones are added'), 'keep' => t('Existing strings are kept, only new strings are added')), - ); - $form['import']['submit'] = array('#type' => 'submit', '#value' => t('Import')); - $form['#attributes']['enctype'] = 'multipart/form-data'; - - return drupal_get_form('_locale_admin_import', $form); -} - -/** - * Process the locale import form submission. - */ -function _locale_admin_import_submit($form_id, $form_values) { - // Add language, if not yet supported - $languages = locale_supported_languages(TRUE, TRUE); - if (!isset($languages['name'][$form_values['langcode']])) { - $isocodes = _locale_get_iso639_list(); - _locale_add_language($form_values['langcode'], $isocodes[$form_values['langcode']][0], FALSE); - } - - // Now import strings into the language - $file = file_check_upload('file'); - if ($ret = _locale_import_po($file, $form_values['langcode'], $form_values['mode']) == FALSE) { - $message = t('The translation import of %filename failed.', array('%filename' => theme('placeholder', $file->filename))); - drupal_set_message($message, 'error'); - watchdog('locale', $message, WATCHDOG_ERROR); - } - - return 'admin/locale'; -} - -/** - * User interface for the translation export screen - */ -function _locale_admin_export_screen() { - $languages = locale_supported_languages(FALSE, TRUE); - $languages = array_map('t', $languages['name']); - unset($languages['en']); - - // Offer language specific export if any language is set up - if (count($languages)) { - $form = array(); - $form['export'] = array('#type' => 'fieldset', - '#title' => t('Export translation'), - '#collapsible' => TRUE, - ); - $form['export']['langcode'] = array('#type' => 'select', - '#title' => t('Language name'), - '#options' => $languages, - '#description' => t('Select the language you would like to export in gettext Portable Object (.po) format.'), - ); - $form['export']['submit'] = array('#type' => 'submit', '#value' => t('Export')); - $output = drupal_get_form('_locale_export_po', $form); - } - - // Complete template export of the strings - $form = array(); - $form['export'] = array('#type' => 'fieldset', - '#title' => t('Export template'), - '#collapsible' => TRUE, - '#description' => t('Generate a gettext Portable Object Template (.pot) file with all the interface strings from the Drupal locale database.'), - ); - $form['export']['submit'] = array('#type' => 'submit', '#value' => t('Export')); - $output .= drupal_get_form('_locale_export_pot', $form, '_locale_export_po'); - - return $output; -} - -/** - * Process a locale export form submissions. - */ -function _locale_export_po_submit($form_id, $form_values) { - _locale_export_po($form_values['langcode']); -} - -/** - * User interface for the string search screen - */ -function _locale_string_seek_form() { - // Get *all* languages set up - $languages = locale_supported_languages(FALSE, TRUE); - asort($languages['name']); unset($languages['name']['en']); - $languages['name'] = array_map('check_plain', $languages['name']); - - // Present edit form preserving previous user settings - $query = _locale_string_seek_query(); - $form = array(); - $form['search'] = array('#type' => 'fieldset', - '#title' => t('Search'), - ); - $form['search']['string'] = array('#type' => 'textfield', - '#title' => t('Strings to search for'), - '#default_value' => $query->string, - '#size' => 30, - '#maxlength' => 30, - '#description' => t('Leave blank to show all strings. The search is case sensitive.'), - ); - $form['search']['language'] = array('#type' => 'radios', - '#title' => t('Language'), - '#default_value' => ($query->language ? $query->language : 'all'), - '#options' => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages['name']), - ); - $form['search']['searchin'] = array('#type' => 'radios', - '#title' => t('Search in'), - '#default_value' => ($query->searchin ? $query->searchin : 'all'), - '#options' => array('all' => t('All strings in that language'), 'translated' => t('Only translated strings'), 'untranslated' => t('Only untranslated strings')), - ); - $form['search']['submit'] = array('#type' => 'submit', '#value' => t('Search')); - $form['#redirect'] = FALSE; - - return drupal_get_form('_locale_string_seek', $form); -} - -/** - * User interface for string editing. - */ -function _locale_string_edit($lid) { - $languages = locale_supported_languages(FALSE, TRUE); - unset($languages['name']['en']); - - $result = db_query('SELECT DISTINCT s.source, t.translation, t.locale FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE s.lid = %d', $lid); - $form = array(); - $form['translations'] = array('#tree' => TRUE); - while ($translation = db_fetch_object($result)) { - $orig = $translation->source; - - // Approximate the number of rows in a textfield with a maximum of 10. - $rows = min(ceil(str_word_count($orig) / 12), 10); - - $form['translations'][$translation->locale] = array( - '#type' => 'textarea', - '#title' => $languages['name'][$translation->locale], - '#default_value' => $translation->translation, - '#rows' => $rows, - ); - unset($languages['name'][$translation->locale]); - } - - // Handle erroneous lid. - if (!isset($orig)){ - drupal_set_message(t('String not found.')); - drupal_goto('admin/locale/string/search'); - } - - // Add original text. Assign negative weight so that it floats to the top. - $form['item'] = array('#type' => 'item', - '#title' => t('Original text'), - '#value' => check_plain(wordwrap($orig, 0)), - '#weight' => -1, - ); - - foreach ($languages['name'] as $key => $lang) { - $form['translations'][$key] = array( - '#type' => 'textarea', - '#title' => $lang, - '#rows' => $rows, - ); - } - - $form['lid'] = array('#type' => 'value', '#value' => $lid); - $form['submit'] = array('#type' => 'submit', '#value' => t('Save translations')); - - return drupal_get_form('_locale_string_edit', $form); -} - -/** - * Process string editing form submissions. - * Saves all translations of one string submitted from a form. - */ -function _locale_string_edit_submit($form_id, $form_values) { - $lid = $form_values['lid']; - foreach ($form_values['translations'] as $key => $value) { - $value = filter_xss_admin($value); - $trans = db_fetch_object(db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND locale = '%s'", $lid, $key)); - if (isset($trans->translation)) { - db_query("UPDATE {locales_target} SET translation = '%s' WHERE lid = %d AND locale = '%s'", $value, $lid, $key); - } - else { - db_query("INSERT INTO {locales_target} (lid, translation, locale) VALUES (%d, '%s', '%s')", $lid, $value, $key); - } - } - drupal_set_message(t('The string has been saved.')); - - // Refresh the locale cache. - locale_refresh_cache(); - // Rebuild the menu, strings may have changed. - menu_rebuild(); - - return 'admin/locale/string/search'; -} - -/** - * Delete a language string. - */ -function _locale_string_delete($lid) { - db_query('DELETE FROM {locales_source} WHERE lid = %d', $lid); - db_query('DELETE FROM {locales_target} WHERE lid = %d', $lid); - locale_refresh_cache(); - drupal_set_message(t('The string has been removed.')); - - drupal_goto('admin/locale/string/search'); -} - -/** - * Parses Gettext Portable Object file information and inserts into database - * - * @param $file Object contains properties of local file to be imported - * @param $lang Language code - * @param $mode should existing translations be replaced? - */ -function _locale_import_po($file, $lang, $mode) { - // If not in 'safe mode', increase the maximum execution time: - if (!ini_get('safe_mode')) { - set_time_limit(240); - } - - // Check if we have the language already in the database - if (!db_fetch_object(db_query("SELECT locale FROM {locales_meta} WHERE locale = '%s'", $lang))) { - drupal_set_message(t('The language selected for import is not supported.'), 'error'); - return FALSE; - } - - // Get strings from file (returns on failure after a partial import, or on success) - $status = _locale_import_read_po($file, $mode, $lang); - if ($status === FALSE) { - // error messages are set in _locale_import_read_po - return FALSE; - } - - // Get status information on import process - list($headerdone, $additions, $updates) = _locale_import_one_string('report', $mode); - - if (!$headerdone) { - drupal_set_message(t('The translation file %filename appears to have a missing or malformed header.', array('%filename' => theme('placeholder', $file->filename))), 'error'); - } - - // rebuild locale cache - cache_clear_all("locale:$lang"); - - // rebuild the menu, strings may have changed - menu_rebuild(); - - drupal_set_message(t('The translation was successfully imported. There are %number newly created translated strings and %update strings were updated.', array('%number' => $additions, '%update' => $updates))); - watchdog('locale', t('Imported %file into %locale: %number new strings added and %update updated.', array('%file' => theme('placeholder', $file->filename), '%locale' => theme('placeholder', $lang), '%number' => $additions, '%update' => $updates))); - return TRUE; -} - -/** - * Parses Gettext Portable Object file into an array - * - * @param $file Object with properties of local file to parse - * @author Jacobo Tarrio - */ -function _locale_import_read_po($file, $mode, $lang) { - - $message = theme('placeholder', $file->filename); - $fd = fopen($file->filepath, "rb"); // File will get closed by PHP on return - if (!$fd) { - drupal_set_message(t('The translation import failed, because the file %filename could not be read.', array('%filename' => $message)), 'error'); - return FALSE; - } - - $context = "COMMENT"; // Parser context: COMMENT, MSGID, MSGID_PLURAL, MSGSTR and MSGSTR_ARR - $current = array(); // Current entry being read - $plural = 0; // Current plural form - $lineno = 0; // Current line - - while (!feof($fd)) { - $line = fgets($fd, 10*1024); // A line should not be this long - $lineno++; - $line = trim(strtr($line, array("\\\n" => ""))); - - if (!strncmp("#", $line, 1)) { // A comment - if ($context == "COMMENT") { // Already in comment context: add - $current["#"][] = substr($line, 1); - } - elseif (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { // End current entry, start a new one - _locale_import_one_string($current, $mode, $lang); - $current = array(); - $current["#"][] = substr($line, 1); - $context = "COMMENT"; - } - else { // Parse error - drupal_set_message(t('The translation file %filename contains an error: "msgstr" was expected but not found on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - } - elseif (!strncmp("msgid_plural", $line, 12)) { - if ($context != "MSGID") { // Must be plural form for current entry - drupal_set_message(t('The translation file %filename contains an error: "msgid_plural" was expected but not found on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $line = trim(substr($line, 12)); - $quoted = _locale_import_parse_quoted($line); - if ($quoted === false) { - drupal_set_message(t('The translation file %filename contains a syntax error on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $current["msgid"] = $current["msgid"] ."\0". $quoted; - $context = "MSGID_PLURAL"; - } - elseif (!strncmp("msgid", $line, 5)) { - if ($context == "MSGSTR") { // End current entry, start a new one - _locale_import_one_string($current, $mode, $lang); - $current = array(); - } - elseif ($context == "MSGID") { // Already in this context? Parse error - drupal_set_message(t('The translation file %filename contains an error: "msgid" is unexpected on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $line = trim(substr($line, 5)); - $quoted = _locale_import_parse_quoted($line); - if ($quoted === false) { - drupal_set_message(t('The translation file %filename contains a syntax error on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $current["msgid"] = $quoted; - $context = "MSGID"; - } - elseif (!strncmp("msgstr[", $line, 7)) { - if (($context != "MSGID") && ($context != "MSGID_PLURAL") && ($context != "MSGSTR_ARR")) { // Must come after msgid, msgid_plural, or msgstr[] - drupal_set_message(t('The translation file %filename contains an error: "msgstr[]" is unexpected on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - if (strpos($line, "]") === false) { - drupal_set_message(t('The translation file %filename contains a syntax error on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $frombracket = strstr($line, "["); - $plural = substr($frombracket, 1, strpos($frombracket, "]") - 1); - $line = trim(strstr($line, " ")); - $quoted = _locale_import_parse_quoted($line); - if ($quoted === false) { - drupal_set_message(t('The translation file %filename contains a syntax error on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $current["msgstr"][$plural] = $quoted; - $context = "MSGSTR_ARR"; - } - elseif (!strncmp("msgstr", $line, 6)) { - if ($context != "MSGID") { // Should come just after a msgid block - drupal_set_message(t('The translation file %filename contains an error: "msgstr" is unexpected on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $line = trim(substr($line, 6)); - $quoted = _locale_import_parse_quoted($line); - if ($quoted === false) { - drupal_set_message(t('The translation file %filename contains a syntax error on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - $current["msgstr"] = $quoted; - $context = "MSGSTR"; - } - elseif ($line != "") { - $quoted = _locale_import_parse_quoted($line); - if ($quoted === false) { - drupal_set_message(t('The translation file %filename contains a syntax error on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - if (($context == "MSGID") || ($context == "MSGID_PLURAL")) { - $current["msgid"] .= $quoted; - } - elseif ($context == "MSGSTR") { - $current["msgstr"] .= $quoted; - } - elseif ($context == "MSGSTR_ARR") { - $current["msgstr"][$plural] .= $quoted; - } - else { - drupal_set_message(t('The translation file %filename contains an error: there is an unexpected string on line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - } - } - - // End of PO file, flush last entry - if (($context == "MSGSTR") || ($context == "MSGSTR_ARR")) { - _locale_import_one_string($current, $mode, $lang); - } - elseif ($context != "COMMENT") { - drupal_set_message(t('The translation file %filename ended unexpectedly at line %line.', array('%filename' => $message, '%line' => $lineno)), 'error'); - return FALSE; - } - -} - -/** - * Imports a string into the database - * - * @param $value Information about the string - * @author Jacobo Tarrio - */ -function _locale_import_one_string($value, $mode, $lang = NULL) { - static $additions = 0; - static $updates = 0; - static $headerdone = FALSE; - - // Report the changes made (called at end of import) - if ($value == 'report') { - return array($headerdone, $additions, $updates); - } - // Current string is the header information - elseif ($value['msgid'] == '') { - $hdr = _locale_import_parse_header($value['msgstr']); - - // Get the plural formula - if ($hdr["Plural-Forms"] && $p = _locale_import_parse_plural_forms($hdr["Plural-Forms"], $file->filename)) { - list($nplurals, $plural) = $p; - db_query("UPDATE {locales_meta} SET plurals = %d, formula = '%s' WHERE locale = '%s'", $nplurals, $plural, $lang); - } - else { - db_query("UPDATE {locales_meta} SET plurals = %d, formula = '%s' WHERE locale = '%s'", 0, '', $lang); - } - $headerdone = TRUE; - } - // Some real string to import - else { - $comments = filter_xss_admin(_locale_import_shorten_comments($value['#'])); - - // Handle a translation for some plural string - if (strpos($value['msgid'], "\0")) { - $english = explode("\0", $value['msgid'], 2); - $entries = array_keys($value['msgstr']); - for ($i = 3; $i <= count($entries); $i++) { - $english[] = $english[1]; - } - $translation = array_map('_locale_import_append_plural', $value['msgstr'], $entries); - $english = array_map('_locale_import_append_plural', $english, $entries); - foreach ($translation as $key => $trans) { - if ($key == 0) { - $plid = 0; - } - $loc = db_fetch_object(db_query("SELECT lid FROM {locales_source} WHERE source = '%s'", $english[$key])); - if ($loc->lid) { // a string exists - $lid = $loc->lid; - // update location field - db_query("UPDATE {locales_source} SET location = '%s' WHERE lid = %d", $comments, $lid); - $trans2 = db_fetch_object(db_query("SELECT lid, translation, plid, plural FROM {locales_target} WHERE lid = %d AND locale = '%s'", $lid, $lang)); - if (!$trans2->lid) { // no translation in current language - db_query("INSERT INTO {locales_target} (lid, locale, translation, plid, plural) VALUES (%d, '%s', '%s', %d, %d)", $lid, $lang, filter_xss_admin($trans), $plid, $key); - $additions++; - } // translation exists - else if ($mode == 'overwrite' || $trans2->translation == '') { - db_query("UPDATE {locales_target} SET translation = '%s', plid = %d, plural = %d WHERE locale = '%s' AND lid = %d", filter_xss_admin($trans), $plid, $key, $lang, $lid); - if ($trans2->translation == '') { - $additions++; - } - else { - $updates++; - } - } - } - else { // no string - db_query("INSERT INTO {locales_source} (location, source) VALUES ('%s', '%s')", $comments, filter_xss_admin($english[$key])); - $loc = db_fetch_object(db_query("SELECT lid FROM {locales_source} WHERE source = '%s'", $english[$key])); - $lid = $loc->lid; - db_query("INSERT INTO {locales_target} (lid, locale, translation, plid, plural) VALUES (%d, '%s', '%s', %d, %d)", $lid, $lang, filter_xss_admin($trans), $plid, $key); - if ($trans != '') { - $additions++; - } - } - $plid = $lid; - } - } - - // A simple translation - else { - $english = $value['msgid']; - $translation = $value['msgstr']; - $loc = db_fetch_object(db_query("SELECT lid FROM {locales_source} WHERE source = '%s'", $english)); - if ($loc->lid) { // a string exists - $lid = $loc->lid; - // update location field - db_query("UPDATE {locales_source} SET location = '%s' WHERE source = '%s'", $comments, $english); - $trans = db_fetch_object(db_query("SELECT lid, translation FROM {locales_target} WHERE lid = %d AND locale = '%s'", $lid, $lang)); - if (!$trans->lid) { // no translation in current language - db_query("INSERT INTO {locales_target} (lid, locale, translation) VALUES (%d, '%s', '%s')", $lid, $lang, filter_xss_admin($translation)); - $additions++; - } // translation exists - else if ($mode == 'overwrite') { //overwrite in any case - db_query("UPDATE {locales_target} SET translation = '%s' WHERE locale = '%s' AND lid = %d", filter_xss_admin($translation), $lang, $lid); - if ($trans->translation == '') { - $additions++; - } - else { - $updates++; - } - } // overwrite if empty string - else if ($trans->translation == '') { - db_query("UPDATE {locales_target} SET translation = '%s' WHERE locale = '%s' AND lid = %d", $translation, $lang, $lid); - $additions++; - } - } - else { // no string - db_query("INSERT INTO {locales_source} (location, source) VALUES ('%s', '%s')", $comments, $english); - $loc = db_fetch_object(db_query("SELECT lid FROM {locales_source} WHERE source = '%s'", $english)); - $lid = $loc->lid; - db_query("INSERT INTO {locales_target} (lid, locale, translation) VALUES (%d, '%s', '%s')", $lid, $lang, filter_xss_admin($translation)); - if ($translation != '') { - $additions++; - } - } - } - } -} - -/** - * Parses a Gettext Portable Object file header - * - * @param $header A string containing the complete header - * @return An associative array of key-value pairs - * @author Jacobo Tarrio - */ -function _locale_import_parse_header($header) { - $hdr = array(); - - $lines = explode("\n", $header); - foreach ($lines as $line) { - $line = trim($line); - if ($line) { - list($tag, $contents) = explode(":", $line, 2); - $hdr[trim($tag)] = trim($contents); - } - } - - return $hdr; -} - -/** - * Parses a Plural-Forms entry from a Gettext Portable Object file header - * - * @param $pluralforms A string containing the Plural-Forms entry - * @param $filename A string containing the filename - * @return An array containing the number of plurals and a - * formula in PHP for computing the plural form - * @author Jacobo Tarrio - */ -function _locale_import_parse_plural_forms($pluralforms, $filename) { - // First, delete all whitespace - $pluralforms = strtr($pluralforms, array(" " => "", "\t" => "")); - - // Select the parts that define nplurals and plural - $nplurals = strstr($pluralforms, "nplurals="); - if (strpos($nplurals, ";")) { - $nplurals = substr($nplurals, 9, strpos($nplurals, ";") - 9); - } - else { - return FALSE; - } - $plural = strstr($pluralforms, "plural="); - if (strpos($plural, ";")) { - $plural = substr($plural, 7, strpos($plural, ";") - 7); - } - else { - return FALSE; - } - - // Get PHP version of the plural formula - $plural = _locale_import_parse_arithmetic($plural); - - if ($plural !== FALSE) { - return array($nplurals, $plural); - } - else { - drupal_set_message(t('The translation file %filename contains an error: the plural formula could not be parsed.', array('%filename' => theme('placeholder', $filename))), 'error'); - return FALSE; - } -} - -/** - * Parses and sanitizes an arithmetic formula into a PHP expression - * - * While parsing, we ensure, that the operators have the right - * precedence and associativity. - * - * @param $string A string containing the arithmetic formula - * @return The PHP version of the formula - * @author Jacobo Tarrio - */ -function _locale_import_parse_arithmetic($string) { - // Operator precedence table - $prec = array("(" => -1, ")" => -1, "?" => 1, ":" => 1, "||" => 3, "&&" => 4, "==" => 5, "!=" => 5, "<" => 6, ">" => 6, "<=" => 6, ">=" => 6, "+" => 7, "-" => 7, "*" => 8, "/" => 8, "%" => 8); - // Right associativity - $rasc = array("?" => 1, ":" => 1); - - $tokens = _locale_import_tokenize_formula($string); - - // Parse by converting into infix notation then back into postfix - $opstk = array(); - $elstk = array(); - - foreach ($tokens as $token) { - $ctok = $token; - - // Numbers and the $n variable are simply pushed into $elarr - if (is_numeric($token)) { - $elstk[] = $ctok; - } - elseif ($ctok == "n") { - $elstk[] = '$n'; - } - elseif ($ctok == "(") { - $opstk[] = $ctok; - } - elseif ($ctok == ")") { - $topop = array_pop($opstk); - while (($topop != NULL) && ($topop != "(")) { - $elstk[] = $topop; - $topop = array_pop($opstk); - } - } - elseif ($prec[$ctok]) { - // If it's an operator, then pop from $oparr into $elarr until the - // precedence in $oparr is less than current, then push into $oparr - $topop = array_pop($opstk); - while (($topop != NULL) && ($prec[$topop] >= $prec[$ctok]) && !(($prec[$topop] == $prec[$ctok]) && $rasc[$topop] && $rasc[$ctok])) { - $elstk[] = $topop; - $topop = array_pop($opstk); - } - if ($topop) { - $opstk[] = $topop; // Return element to top - } - $opstk[] = $ctok; // Parentheses are not needed - } - else { - return false; - } - } - - // Flush operator stack - $topop = array_pop($opstk); - while ($topop != NULL) { - $elstk[] = $topop; - $topop = array_pop($opstk); - } - - // Now extract formula from stack - $prevsize = count($elstk) + 1; - while (count($elstk) < $prevsize) { - $prevsize = count($elstk); - for ($i = 2; $i < count($elstk); $i++) { - $op = $elstk[$i]; - if ($prec[$op]) { - $f = ""; - if ($op == ":") { - $f = $elstk[$i - 2] ."):". $elstk[$i - 1] .")"; - } - elseif ($op == "?") { - $f = "(". $elstk[$i - 2] ."?(". $elstk[$i - 1]; - } - else { - $f = "(". $elstk[$i - 2] . $op . $elstk[$i - 1] .")"; - } - array_splice($elstk, $i - 2, 3, $f); - break; - } - } - } - - // If only one element is left, the number of operators is appropriate - if (count($elstk) == 1) { - return $elstk[0]; - } - else { - return FALSE; - } -} - -/** - * Backward compatible implementation of token_get_all() for formula parsing - * - * @param $string A string containing the arithmetic formula - * @return The PHP version of the formula - * @author Gerhard Killesreiter - */ -function _locale_import_tokenize_formula($formula) { - $formula = str_replace(" ", "", $formula); - $tokens = array(); - for ($i = 0; $i < strlen($formula); $i++) { - if (is_numeric($formula[$i])) { - $num = $formula[$i]; - $j = $i + 1; - while($j < strlen($formula) && is_numeric($formula[$j])) { - $num .= $formula[$j]; - $j++; - } - $i = $j - 1; - $tokens[] = $num; - } - elseif ($pos = strpos(" =<>!&|", $formula[$i])) { // We won't have a space - $next = $formula[$i + 1]; - switch ($pos) { - case 1: - case 2: - case 3: - case 4: - if ($next == '=') { - $tokens[] = $formula[$i] .'='; - $i++; - } - else { - $tokens[] = $formula[$i]; - } - break; - case 5: - if ($next == '&') { - $tokens[] = '&&'; - $i++; - } - else { - $tokens[] = $formula[$i]; - } - break; - case 6: - if ($next == '|') { - $tokens[] = '||'; - $i++; - } - else { - $tokens[] = $formula[$i]; - } - break; - } - } - else { - $tokens[] = $formula[$i]; - } - } - return $tokens; -} - -/** - * Modify a string to contain proper count indices - * - * This is a callback function used via array_map() - * - * @param $entry An array element - * @param $key Index of the array element - */ -function _locale_import_append_plural($entry, $key) { - // No modifications for 0, 1 - if ($key == 0 || $key == 1) { - return $entry; - } - - // First remove any possibly false indices, then add new ones - $entry = preg_replace('/(%count)\[[0-9]\]/', '\\1', $entry); - return preg_replace('/(%count)/', "\\1[$key]", $entry); -} - -/** - * Generate a short, one string version of the passed comment array - * - * @param $comment An array of strings containing a comment - * @return Short one string version of the comment - */ -function _locale_import_shorten_comments($comment) { - $comm = ''; - while (count($comment)) { - $test = $comm . substr(array_shift($comment), 1) .', '; - if (strlen($comm) < 130) { - $comm = $test; - } - else { - break; - } - } - return substr($comm, 0, -2); -} - -/** - * Parses a string in quotes - * - * @param $string A string specified with enclosing quotes - * @return The string parsed from inside the quotes - */ -function _locale_import_parse_quoted($string) { - if (substr($string, 0, 1) != substr($string, -1, 1)) { - return FALSE; // Start and end quotes must be the same - } - $quote = substr($string, 0, 1); - $string = substr($string, 1, -1); - if ($quote == '"') { // Double quotes: strip slashes - return stripcslashes($string); - } - elseif ($quote == "'") { // Simple quote: return as-is - return $string; - } - else { - return FALSE; // Unrecognized quote - } -} - -/** - * Exports a Portable Object (Template) file for a language - * - * @param $language Selects a language to generate the output for - */ -function _locale_export_po($language) { - global $user; - - // Get language specific strings, or all strings - if ($language) { - $meta = db_fetch_object(db_query("SELECT * FROM {locales_meta} WHERE locale = '%s'", $language)); - $result = db_query("SELECT s.lid, s.source, s.location, t.translation, t.plid, t.plural FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE t.locale = '%s' ORDER BY t.plid, t.plural", $language); - } - else { - $result = db_query("SELECT s.lid, s.source, s.location, t.plid, t.plural FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid ORDER BY t.plid, t.plural"); - } - - // Build array out of the database results - $parent = array(); - while ($child = db_fetch_object($result)) { - if ($child->source != '') { - $parent[$child->lid]['comment'] = $child->location; - $parent[$child->lid]['msgid'] = $child->source; - if ($child->plid) { - $parent[$child->lid][$child->plid]['plural'] = $child->lid; - $parent[$child->lid][$child->plid]['translation'] = $child->translation; - $parent[$child->lid][$child->plid]['msgid'] = $child->source; - } - else { - $parent[$child->lid]['translation'] = $child->translation; - } - } - } - - // Generating Portable Object file for a language - if ($language) { - $filename = $language .'.po'; - $header .= "# $meta->name translation of ". variable_get('site_name', 'Drupal') ."\n"; - $header .= '# Copyright (c) '. date('Y') .' '. $user->name .' <'. $user->mail .">\n"; - $header .= "#\n"; - $header .= "msgid \"\"\n"; - $header .= "msgstr \"\"\n"; - $header .= "\"Project-Id-Version: PROJECT VERSION\\n\"\n"; - $header .= "\"POT-Creation-Date: ". date("Y-m-d H:iO") ."\\n\"\n"; - $header .= "\"PO-Revision-Date: ". date("Y-m-d H:iO") ."\\n\"\n"; - $header .= "\"Last-Translator: ". $user->name .' <'. $user->mail .">\\n\"\n"; - $header .= "\"Language-Team: ". $meta->name .' <'. $user->mail .">\\n\"\n"; - $header .= "\"MIME-Version: 1.0\\n\"\n"; - $header .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n"; - $header .= "\"Content-Transfer-Encoding: 8bit\\n\"\n"; - if ($meta->formula && $meta->plurals) { - $header .= "\"Plural-Forms: nplurals=". $meta->plurals ."; plural=". strtr($meta->formula, '$', '') .";\\n\"\n"; - } - $header .= "\n"; - watchdog('locale', t('Exported %locale translation file: %filename.', array('%locale' => theme('placeholder', $meta->name), '%filename' => theme('placeholder', $filename)))); - } - - // Generating Portable Object Template - else { - $filename = 'drupal.pot'; - $header .= "# LANGUAGE translation of PROJECT\n"; - $header .= "# Copyright (c) YEAR NAME \n"; - $header .= "#\n"; - $header .= "msgid \"\"\n"; - $header .= "msgstr \"\"\n"; - $header .= "\"Project-Id-Version: PROJECT VERSION\\n\"\n"; - $header .= "\"POT-Creation-Date: ". date("Y-m-d H:iO") ."\\n\"\n"; - $header .= "\"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\\n\"\n"; - $header .= "\"Last-Translator: NAME \\n\"\n"; - $header .= "\"Language-Team: LANGUAGE \\n\"\n"; - $header .= "\"MIME-Version: 1.0\\n\"\n"; - $header .= "\"Content-Type: text/plain; charset=utf-8\\n\"\n"; - $header .= "\"Content-Transfer-Encoding: 8bit\\n\"\n"; - $header .= "\"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n"; - $header .= "\n"; - watchdog('locale', t('Exported translation file: %filename.', array('%filename' => theme('placeholder', $filename)))); - } - - // Start download process - header("Content-Disposition: attachment; filename=$filename"); - header("Content-Type: text/plain; charset=utf-8"); - - print $header; - - foreach ($parent as $lid => $message) { - if (!isset($done[$lid])) { - if ($message['comment']) { - print '#: '. $message['comment'] ."\n"; - } - print 'msgid '. _locale_export_print($message['msgid']); - if (isset($message[1]['plural'])) { - print 'msgid_plural '. _locale_export_print($message[1]['msgid']); - if ($language) { - for ($i = 0; $i < $meta->plurals; $i++) { - print 'msgstr['. $i .'] '. _locale_export_print(_locale_export_remove_plural($message[${i}]['translation'])); - $done[$message[${i}]['plural']] = 1; - } - } - else { - print 'msgstr[0] ""'. "\n"; - print 'msgstr[1] ""'. "\n"; - $done[$message[0]['plural']] = 1; - $done[$message[1]['plural']] = 1; - } - } - else { - if ($language) { - print 'msgstr '. _locale_export_print($message['translation']); - } - else { - print 'msgstr ""'. "\n"; - } - } - print "\n"; - } - } - die(); -} - -/** - * Print out a string on multiple lines - */ -function _locale_export_print($str) { - $stri = addcslashes($str, "\0..\37\\\""); - $parts = array(); - - // Cut text into several lines - while ($stri != "") { - $i = strpos($stri, "\\n"); - if ($i === FALSE) { - $curstr = $stri; - $stri = ""; - } - else { - $curstr = substr($stri, 0, $i + 2); - $stri = substr($stri, $i + 2); - } - $curparts = explode("\n", _locale_export_wrap($curstr, 70)); - $parts = array_merge($parts, $curparts); - } - - if (count($parts) > 1) { - return "\"\"\n\"". implode("\"\n\"", $parts) ."\"\n"; - } - else { - return "\"$parts[0]\"\n"; - } -} - -/** - * Custom word wrapping for Portable Object (Template) files. - * - * @author Jacobo Tarrio - */ -function _locale_export_wrap($str, $len) { - $words = explode(' ', $str); - $ret = array(); - - $cur = ""; - $nstr = 1; - while (count($words)) { - $word = array_shift($words); - if ($nstr) { - $cur = $word; - $nstr = 0; - } - elseif (strlen("$cur $word") > $len) { - $ret[] = $cur . " "; - $cur = $word; - } - else { - $cur = "$cur $word"; - } - } - $ret[] = $cur; - - return implode("\n", $ret); -} - -/** - * Removes plural index information from a string - */ -function _locale_export_remove_plural($entry) { - return preg_replace('/(%count)\[[0-9]\]/', '\\1', $entry); -} - -/** - * List languages in search result table - */ -function _locale_string_language_list($translation) { - $languages = locale_supported_languages(FALSE, TRUE); - unset($languages['name']['en']); - $output = ''; - foreach ($languages['name'] as $key => $value) { - if (isset($translation[$key])) { - $output .= ($translation[$key] != '') ? $key .' ' : "$key "; - } - } - - return $output; -} - -/** - * Build object out of search criteria specified in request variables - */ -function _locale_string_seek_query() { - static $query = NULL; - - if (is_null($query)) { - $fields = array('string', 'language', 'searchin'); - $query = new StdClass; - if (is_array($_REQUEST['edit'])) { - foreach ($_REQUEST['edit'] as $key => $value) { - if (!empty($value) && in_array($key, $fields)) { - $query->$key = $value; - } - } - } - else { - foreach ($_REQUEST as $key => $value) { - if (!empty($value) && in_array($key, $fields)) { - $query->$key = strpos(',', $value) ? explode(',', $value) : $value; - } - } - } - } - return $query; -} - -/** - * Perform a string search and display results in a table - */ -function _locale_string_seek() { - // We have at least one criterion to match - if ($query = _locale_string_seek_query()) { - $join = "SELECT s.source, s.location, s.lid, t.translation, t.locale FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid "; - - $arguments = array(); - // Compute LIKE section - switch ($query->searchin) { - case 'translated': - $where = "WHERE (t.translation LIKE '%%%s%%' AND t.translation != '')"; - $orderby = "ORDER BY t.translation"; - $arguments[] = $query->string; - break; - case 'untranslated': - $where = "WHERE (s.source LIKE '%%%s%%' AND t.translation = '')"; - $orderby = "ORDER BY s.source"; - $arguments[] = $query->string; - break; - case 'all' : - default: - $where = "WHERE (s.source LIKE '%%%s%%' OR t.translation LIKE '%%%s%%')"; - $orderby = ''; - $arguments[] = $query->string; - $arguments[] = $query->string; - break; - } - - switch ($query->language) { - // Force search in source strings - case "en": - $sql = $join ." WHERE s.source LIKE '%%%s%%' ORDER BY s.source"; - $arguments = array($query->string); // $where is not used, discard its arguments - break; - // Search in all languages - case "all": - $sql = "$join $where $orderby"; - break; - // Some different language - default: - $sql = "$join $where AND t.locale = '%s' $orderby"; - $arguments[] = $query->language; - } - - $result = pager_query($sql, 50, 0, NULL, $arguments); - - $header = array(t('String'), t('Locales'), array('data' => t('Operations'), 'colspan' => '2')); - $arr = array(); - while ($locale = db_fetch_object($result)) { - $arr[$locale->lid]['locales'][$locale->locale] = $locale->translation; - $arr[$locale->lid]['location'] = $locale->location; - $arr[$locale->lid]['source'] = $locale->source; - } - foreach ($arr as $lid => $value) { - $rows[] = array(array('data' => check_plain(truncate_utf8($value['source'], 150, FALSE, TRUE)) .'
'. $value['location'] .''), array('data' => _locale_string_language_list($value['locales']), 'align' => 'center'), array('data' => l(t('edit'), "admin/locale/string/edit/$lid"), 'class' => 'nowrap'), array('data' => l(t('delete'), "admin/locale/string/delete/$lid"), 'class' => 'nowrap')); - } - - $request = array(); - if (count($query)) { - foreach ($query as $key => $value) { - $request[$key] = (is_array($value)) ? implode(',', $value) : $value; - } - } - - if (count($rows)) { - $output .= theme('table', $header, $rows); - } - if ($pager = theme('pager', NULL, 50, 0, $request)) { - $output .= $pager; - } - } - - return $output; -} - -// --------------------------------------------------------------------------------- -// List of some of the most common languages (administration only) - -/** - * Prepares the language code list for a select form item with only the unsupported ones - */ -function _locale_prepare_iso_list() { - $languages = locale_supported_languages(FALSE, TRUE); - $isocodes = _locale_get_iso639_list(); - foreach ($isocodes as $key => $value) { - if (isset($languages['name'][$key])) { - unset($isocodes[$key]); - continue; - } - if (count($value) == 2) { - $tname = t($value[0]); - $isocodes[$key] = ($tname == $value[1]) ? $tname : "$tname ($value[1])"; - } - else { - $isocodes[$key] = t($value[0]); - } - } - asort($isocodes); - return $isocodes; -} - -/** - * Some of the common languages with their English and native names - * - * Based on ISO 639 and http://people.w3.org/rishida/names/languages.html - */ -function _locale_get_iso639_list() { - return array( - "aa" => array("Afar"), - "ab" => array("Abkhazian", "аҧсуа бызшәа"), - "ae" => array("Avestan"), - "af" => array("Afrikaans"), - "ak" => array("Akan"), - "am" => array("Amharic", "አማርኛ"), - "ar" => array("Arabic", "العربية"), - "as" => array("Assamese"), - "av" => array("Avar"), - "ay" => array("Aymara"), - "az" => array("Azerbaijani", "azərbaycan"), - "ba" => array("Bashkir"), - "be" => array("Belarusian", "Беларуская"), - "bg" => array("Bulgarian", "Български"), - "bh" => array("Bihari"), - "bi" => array("Bislama"), - "bm" => array("Bambara", "Bamanankan"), - "bn" => array("Bengali"), - "bo" => array("Tibetan"), - "br" => array("Breton"), - "bs" => array("Bosnian", "Bosanski"), - "ca" => array("Catalan", "Català"), - "ce" => array("Chechen"), - "ch" => array("Chamorro"), - "co" => array("Corsican"), - "cr" => array("Cree"), - "cs" => array("Czech", "Čeština"), - "cu" => array("Old Slavonic"), - "cv" => array("Welsh", "Cymraeg"), - "cy" => array("Welch"), - "da" => array("Danish", "Dansk"), - "de" => array("German", "Deutsch"), - "dv" => array("Maldivian"), - "dz" => array("Bhutani"), - "ee" => array("Ewe", "Ɛʋɛ"), - "el" => array("Greek", "Ελληνικά"), - "en" => array("English"), - "eo" => array("Esperanto"), - "es" => array("Spanish", "Español"), - "et" => array("Estonian", "Eesti"), - "eu" => array("Basque", "Euskera"), - "fa" => array("Persian", "فارسی"), - "ff" => array("Fulah", "Fulfulde"), - "fi" => array("Finnish", "Suomi"), - "fj" => array("Fiji"), - "fo" => array("Faeroese"), - "fr" => array("French", "Français"), - "fy" => array("Frisian", "Frysk"), - "ga" => array("Irish", "Gaeilge"), - "gd" => array("Scots Gaelic"), - "gl" => array("Galician", "Galego"), - "gn" => array("Guarani"), - "gu" => array("Gujarati"), - "gv" => array("Manx"), - "ha" => array("Hausa"), - "he" => array("Hebrew", "עברית"), - "hi" => array("Hindi", "हिन्दी"), - "ho" => array("Hiri Motu"), - "hr" => array("Croatian", "Hrvatski"), - "hu" => array("Hungarian", "Magyar"), - "hy" => array("Armenian", "Հայերեն"), - "hz" => array("Herero"), - "ia" => array("Interlingua"), - "id" => array("Indonesian", "Bahasa Indonesia"), - "ie" => array("Interlingue"), - "ig" => array("Igbo"), - "ik" => array("Inupiak"), - "is" => array("Icelandic", "Íslenska"), - "it" => array("Italian", "Italiano"), - "iu" => array("Inuktitut"), - "ja" => array("Japanese", "日本語"), - "jv" => array("Javanese"), - "ka" => array("Georgian"), - "kg" => array("Kongo"), - "ki" => array("Kikuyu"), - "kj" => array("Kwanyama"), - "kk" => array("Kazakh", "Қазақ"), - "kl" => array("Greenlandic"), - "km" => array("Cambodian"), - "kn" => array("Kannada", "ಕನ್ನಡ"), - "ko" => array("Korean", "한국어"), - "kr" => array("Kanuri"), - "ks" => array("Kashmiri"), - "ku" => array("Kurdish", "Kurdî"), - "kv" => array("Komi"), - "kw" => array("Cornish"), - "ky" => array("Kirghiz", "Кыргыз"), - "la" => array("Latin", "Latina"), - "lb" => array("Luxembourgish"), - "lg" => array("Luganda"), - "ln" => array("Lingala"), - "lo" => array("Laothian"), - "lt" => array("Lithuanian", "Lietuviškai"), - "lv" => array("Latvian", "Latviešu"), - "mg" => array("Malagasy"), - "mh" => array("Marshallese"), - "mi" => array("Maori"), - "mk" => array("Macedonian", "Македонски"), - "ml" => array("Malayalam", "മലയാളം"), - "mn" => array("Mongolian"), - "mo" => array("Moldavian"), - "mr" => array("Marathi"), - "ms" => array("Malay", "Bahasa Melayu"), - "mt" => array("Maltese", "Malti"), - "my" => array("Burmese"), - "na" => array("Nauru"), - "nd" => array("North Ndebele"), - "ne" => array("Nepali"), - "ng" => array("Ndonga"), - "nl" => array("Dutch", "Nederlands"), - "no" => array("Norwegian", "Norsk"), - "nr" => array("South Ndebele"), - "nv" => array("Navajo"), - "ny" => array("Chichewa"), - "oc" => array("Occitan"), - "om" => array("Oromo"), - "or" => array("Oriya"), - "os" => array("Ossetian"), - "pa" => array("Punjabi"), - "pi" => array("Pali"), - "pl" => array("Polish", "Polski"), - "ps" => array("Pashto", "پښتو"), - "pt" => array("Portuguese", "Português"), - "qu" => array("Quechua"), - "rm" => array("Rhaeto-Romance"), - "rn" => array("Kirundi"), - "ro" => array("Romanian", "Română"), - "ru" => array("Russian", "Русский"), - "rw" => array("Kinyarwanda"), - "sa" => array("Sanskrit"), - "sc" => array("Sardinian"), - "sd" => array("Sindhi"), - "se" => array("Northern Sami"), - "sg" => array("Sango"), - "sh" => array("Serbo-Croatian"), - "si" => array("Singhalese"), - "sk" => array("Slovak", "Slovenčina"), - "sl" => array("Slovenian", "Slovenščina"), - "sm" => array("Samoan"), - "sn" => array("Shona"), - "so" => array("Somali"), - "sq" => array("Albanian", "Shqip"), - "sr" => array("Serbian", "Српски"), - "ss" => array("Siswati"), - "st" => array("Sesotho"), - "su" => array("Sudanese"), - "sv" => array("Swedish", "Svenska"), - "sw" => array("Swahili", "Kiswahili"), - "ta" => array("Tamil", "தமிழ்"), - "te" => array("Telugu", "తెలుగు"), - "tg" => array("Tajik"), - "th" => array("Thai", "ภาษาไทย"), - "ti" => array("Tigrinya"), - "tk" => array("Turkmen"), - "tl" => array("Tagalog"), - "tn" => array("Setswana"), - "to" => array("Tonga"), - "tr" => array("Turkish", "Türkçe"), - "ts" => array("Tsonga"), - "tt" => array("Tatar", "Tatarça"), - "tw" => array("Twi"), - "ty" => array("Tahitian"), - "ug" => array("Uighur"), - "uk" => array("Ukrainian", "Українська"), - "ur" => array("Urdu", "اردو"), - "uz" => array("Uzbek", "o'zbek"), - "ve" => array("Venda"), - "vi" => array("Vietnamese", "Tiếng Việt"), - "wo" => array("Wolof"), - "xh" => array("Xhosa", "isiXhosa"), - "yi" => array("Yiddish"), - "yo" => array("Yoruba", "Yorùbá"), - "za" => array("Zhuang"), - "zh-hans" => array("Chinese, Simplified", "简体中文"), - "zh-hant" => array("Chinese, Traditional", "繁體中文"), - "zu" => array("Zulu", "isiZulu"), - ); -} diff --git a/includes/menu.inc b/includes/menu.inc deleted file mode 100644 index c5fdd45..0000000 --- a/includes/menu.inc +++ /dev/null @@ -1,1362 +0,0 @@ - $item['description'])). - * - 'children' - A linear list of the menu ID's of this item's children. - * - * Menu ID 0 is the "root" of the menu. The children of this item are the - * menus themselves (they will have no associated path). Menu ID 1 will - * always be one of these children; it is the default "Navigation" menu. - */ -function menu_get_menu() { - global $_menu; - global $user; - global $locale; - - if (!isset($_menu['items'])) { - // _menu_build() may indirectly call this function, so prevent infinite loops. - $_menu['items'] = array(); - - $cid = "menu:$user->uid:$locale"; - if ($cached = cache_get($cid)) { - $_menu = unserialize($cached->data); - } - else { - _menu_build(); - // Cache the menu structure for this user, to expire after one day. - cache_set($cid, serialize($_menu), time() + (60 * 60 * 24)); - } - - // Make sure items that cannot be cached are added. - _menu_append_contextual_items(); - - // Reset the cached $menu in menu_get_item(). - menu_get_item(NULL, NULL, TRUE); - } - - return $_menu; -} - -/** - * Return the local task tree. - * - * Unlike the rest of the menu structure, the local task tree cannot be cached - * nor determined too early in the page request, because the user's current - * location may be changed by a menu_set_location() call, and the tasks shown - * (just as the breadcrumb trail) need to reflect the changed location. - */ -function menu_get_local_tasks() { - global $_menu; - - // Don't cache the local task tree, as it varies by location and tasks are - // allowed to be dynamically determined. - if (!isset($_menu['local tasks'])) { - // _menu_build_local_tasks() may indirectly call this function, so prevent - // infinite loops. - $_menu['local tasks'] = array(); - $pid = menu_get_active_nontask_item(); - if (!_menu_build_local_tasks($pid)) { - // If the build returned FALSE, the tasks need not be displayed. - $_menu['local tasks'][$pid]['children'] = array(); - } - } - - return $_menu['local tasks']; -} - -/** - * Retrieves the menu item specified by $mid, or by $path if $mid is not given. - * - * @param $mid - * The menu ID of the menu item to retrieve. - * @param $path - * The internal path of the menu item to retrieve. Defaults to NULL. Only - * used if $mid is not set. - * @param $reset - * Optional flag that resets the static variable cache of the menu tree, if - * set to TRUE. Default is FALSE. - * - * @return - * The menu item found in the site menu, or an empty array if none could be - * found. - */ -function menu_get_item($mid, $path = NULL, $reset = FALSE) { - static $menu; - - if (!isset($menu) || $reset) { - $menu = menu_get_menu(); - } - - if (isset($mid)) { - return $menu['items'][$mid]; - } - - if (isset($path)) { - return $menu['items'][$menu['path index'][$path]]; - } - - return array(); -} - -/** - * Retrieves the menu ID and title of all root menus. - * - * @return - * Array containing all menus (but not menu items), in the form mid => title. - */ -function menu_get_root_menus() { - $menu = menu_get_menu(); - $root_menus = array(); - - foreach ($menu['items'][0]['children'] as $mid) { - $root_menus[$mid] = $menu['items'][$mid]['title']; - } - - return $root_menus; -} - -/** - * Change the current menu location of the user. - * - * Frequently, modules may want to make a page or node act as if it were - * in the menu tree somewhere, even though it was not registered in a - * hook_menu() implementation. If the administrator has rearranged the menu, - * the newly set location should respect this in the breadcrumb trail and - * expanded/collapsed status of menu items in the tree. This function - * allows this behavior. - * - * @param $location - * An array specifying a complete or partial breadcrumb trail for the - * new location, in the same format as the return value of hook_menu(). - * The last element of this array should be the new location itself. - * - * This function will set the new breadcrumb trail to the passed-in value, - * but if any elements of this trail are visible in the site tree, the - * trail will be "spliced in" to the existing site navigation at that point. - */ -function menu_set_location($location) { - global $_menu; - $temp_id = min(array_keys($_menu['items'])) - 1; - $prev_id = 0; - - // Don't allow this function to change the actual current path, just the - // position in the menu tree. - $location[count($location) - 1]['path'] = $_GET['q']; - - foreach (array_reverse($location) as $item) { - if (isset($_menu['path index'][$item['path']])) { - $mid = $_menu['path index'][$item['path']]; - if (isset($_menu['visible'][$mid])) { - // Splice in the breadcrumb at this location. - if ($prev_id) { - $_menu['items'][$prev_id]['pid'] = $mid; - } - $prev_id = 0; - break; - } - else { - // A hidden item; show it, but only temporarily. - $_menu['items'][$mid]['type'] |= MENU_VISIBLE_IN_BREADCRUMB; - if ($prev_id) { - $_menu['items'][$prev_id]['pid'] = $mid; - } - $prev_id = $mid; - } - } - else { - $item['type'] |= MENU_VISIBLE_IN_BREADCRUMB; - if ($prev_id) { - $_menu['items'][$prev_id]['pid'] = $temp_id; - } - $_menu['items'][$temp_id] = $item; - $_menu['path index'][$item['path']] = $temp_id; - - $prev_id = $temp_id; - $temp_id--; - } - } - - if ($prev_id) { - // Didn't find a home, so attach this to the main navigation menu. - $_menu['items'][$prev_id]['pid'] = 1; - } - - $final_item = array_pop($location); - menu_set_active_item($final_item['path']); -} - -/** - * Execute the handler associated with the active menu item. - * - * This is called early in the page request. The active menu item is at - * this point determined exclusively by the URL. The handler that is called - * here may, as a side effect, change the active menu item so that later - * menu functions (that display the menus and breadcrumbs, for example) - * act as if the user were in a different location on the site. - */ -function menu_execute_active_handler() { - if (_menu_site_is_offline()) { - return MENU_SITE_OFFLINE; - } - - $menu = menu_get_menu(); - - // Determine the menu item containing the callback. - $path = $_GET['q']; - while ($path && !isset($menu['callbacks'][$path])) { - $path = substr($path, 0, strrpos($path, '/')); - } - - if (!isset($menu['callbacks'][$path])) { - return MENU_NOT_FOUND; - } - - if (!function_exists($menu['callbacks'][$path]['callback'])) { - return MENU_NOT_FOUND; - } - - if (!_menu_item_is_accessible(menu_get_active_item())) { - return MENU_ACCESS_DENIED; - } - - // We found one, and are allowed to execute it. - $arguments = isset($menu['callbacks'][$path]['callback arguments']) ? $menu['callbacks'][$path]['callback arguments'] : array(); - $arg = substr($_GET['q'], strlen($path) + 1); - if (strlen($arg)) { - $arguments = array_merge($arguments, explode('/', $arg)); - } - - return call_user_func_array($menu['callbacks'][$path]['callback'], $arguments); -} - -/** - * Returns the ID of the active menu item. - */ -function menu_get_active_item() { - return menu_set_active_item(); -} - -/** - * Sets the path of the active menu item. - */ -function menu_set_active_item($path = NULL) { - static $stored_mid; - - if (!isset($stored_mid) || isset($path)) { - $menu = menu_get_menu(); - if (!isset($path)) { - $path = $_GET['q']; - } - else { - $_GET['q'] = $path; - } - - while ($path && !isset($menu['path index'][$path])) { - $path = substr($path, 0, strrpos($path, '/')); - } - $stored_mid = isset($menu['path index'][$path]) ? $menu['path index'][$path] : 0; - - // Search for default local tasks to activate instead of this item. - $continue = TRUE; - while ($continue) { - $continue = FALSE; - if (isset($menu['items'][$stored_mid]['children'])) { - foreach ($menu['items'][$stored_mid]['children'] as $cid) { - if ($menu['items'][$cid]['type'] & MENU_LINKS_TO_PARENT) { - $stored_mid = $cid; - $continue = TRUE; - } - } - } - } - - // Reset the cached $menu in menu_get_item(). - menu_get_item(NULL, NULL, TRUE); - } - - return $stored_mid; -} - -/** - * Returns the ID of the current menu item or, if the current item is a - * local task, the menu item to which this task is attached. - */ -function menu_get_active_nontask_item() { - $mid = menu_get_active_item(); - - // Find the first non-task item: - while ($mid) { - $item = menu_get_item($mid); - - if (!($item['type'] & MENU_IS_LOCAL_TASK)) { - return $mid; - } - - $mid = $item['pid']; - } -} - -/** - * Returns the title of the active menu item. - */ -function menu_get_active_title() { - if ($mid = menu_get_active_nontask_item()) { - $item = menu_get_item($mid); - return $item['title']; - } -} - -/** - * Returns the help associated with the active menu item. - */ -function menu_get_active_help() { - $path = $_GET['q']; - $output = ''; - - if (!_menu_item_is_accessible(menu_get_active_item())) { - // Don't return help text for areas the user cannot access. - return; - } - - foreach (module_list() as $name) { - if (module_hook($name, 'help')) { - if ($temp = module_invoke($name, 'help', $path)) { - $output .= $temp . "\n"; - } - if (module_hook('help', 'page')) { - if (substr($path, 0, 6) == "admin/") { - if (module_invoke($name, 'help', 'admin/help#' . substr($path, 6))) { - $output .= theme("more_help_link", url('admin/help/' . substr($path, 6))); - } - } - } - } - } - return $output; -} - -/** - * Returns an array of rendered menu items in the active breadcrumb trail. - */ -function menu_get_active_breadcrumb() { - - // No breadcrumb for the front page. - if (drupal_is_front_page()) { - return array(); - } - - $links[] = l(t('Home'), variable_get('site_frontpage', 'node')); - - $trail = _menu_get_active_trail(); - foreach ($trail as $mid) { - $item = menu_get_item($mid); - if ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB) { - $links[] = menu_item_link($mid); - } - } - - // The last item in the trail is the page title; don't display it here. - array_pop($links); - - return $links; -} - -/** - * Returns true when the menu item is in the active trail. - */ -function menu_in_active_trail($mid) { - $trail = _menu_get_active_trail(); - - return in_array($mid, $trail); -} - -/** - * Returns true when the menu item is in the active trail within a - * specific subsection of the menu tree. - * - * @param $mid - * The menu item being considered. - * @param $pid - * The root of the subsection of the menu tree in which to look. - */ -function menu_in_active_trail_in_submenu($mid, $pid) { - $trail = _menu_get_active_trail_in_submenu($pid); - - if (!$trail) { - return FALSE; - } - - return in_array($mid, $trail); -} - -/** - * Populate the database representation of the menu. - * - * This need only be called at the start of pages that modify the menu. - */ -function menu_rebuild() { - // Clear the page cache, so that changed menus are reflected for anonymous users. - cache_clear_all(); - // Also clear the menu cache. - cache_clear_all('menu:', TRUE); - - _menu_build(); - - if (module_exist('menu')) { - $menu = menu_get_menu(); - - // Fill a queue of new menu items which are modifiable. - $new_items = array(); - foreach ($menu['items'] as $mid => $item) { - if ($mid < 0 && ($item['type'] & MENU_MODIFIABLE_BY_ADMIN)) { - $new_items[$mid] = $item; - } - } - - $old_count = -1; - // Save the new items updating the pids in each iteration - while (($c = count($new_items)) && ($c != $old_count)) { - $old_count = count($new_items); - foreach($new_items as $mid => $item) { - // If the item has a valid parent, save it - if ($item['pid'] >= 0) { - // The new menu ID gets passed back by reference as $item['mid'] - menu_save_item($item); - // Fix parent IDs for the children of the menu item just saved - if ($item['children']) { - foreach ($item['children'] as $child) { - if (isset($new_items[$child])) { - $new_items[$child]['pid'] = $item['mid']; - } - } - } - // remove the item - unset($new_items[$mid]); - } - } - } - // Rebuild the menu to account for the changes. - _menu_build(); - } - - // Reset the cached $menu in menu_get_item(). - menu_get_item(NULL, NULL, TRUE); - -} - -/** - * Generate the HTML for a menu tree. - * - * @param $pid - * The parent id of the menu. - * - * @ingroup themeable - */ -function theme_menu_tree($pid = 1) { - if ($tree = menu_tree($pid)) { - return "\n
    \n". $tree ."\n
\n"; - } -} - -/** - * Returns a rendered menu tree. - * - * @param $pid - * The parent id of the menu. - */ -function menu_tree($pid = 1) { - $menu = menu_get_menu(); - $output = ''; - - if (isset($menu['visible'][$pid]) && $menu['visible'][$pid]['children']) { - foreach ($menu['visible'][$pid]['children'] as $mid) { - $type = isset($menu['visible'][$mid]['type']) ? $menu['visible'][$mid]['type'] : NULL; - $children = isset($menu['visible'][$mid]['children']) ? $menu['visible'][$mid]['children'] : NULL; - $output .= theme('menu_item', $mid, menu_in_active_trail($mid) || ($type & MENU_EXPANDED) ? theme('menu_tree', $mid) : '', count($children) == 0); - } - } - - return $output; -} - -/** - * Generate the HTML output for a single menu item. - * - * @param $mid - * The menu id of the item. - * @param $children - * A string containing any rendered child items of this menu. - * @param $leaf - * A boolean indicating whether this menu item is a leaf. - * - * @ingroup themeable - */ -function theme_menu_item($mid, $children = '', $leaf = TRUE) { - return '
  • '. menu_item_link($mid) . $children ."
  • \n"; -} - -/** - * Generate the HTML representing a given menu item ID. - * - * @param $item - * The menu item to render. - * @param $link_item - * The menu item which should be used to find the correct path. - * - * @ingroup themeable - */ -function theme_menu_item_link($item, $link_item) { - return l($item['title'], $link_item['path'], isset($item['description']) ? array('title' => $item['description']) : array()); -} - -/** - * Returns the rendered link to a menu item. - * - * @param $mid - * The menu item id to render. - */ -function menu_item_link($mid) { - $item = menu_get_item($mid); - $link_item = $item; - - while ($link_item['type'] & MENU_LINKS_TO_PARENT) { - $link_item = menu_get_item($link_item['pid']); - } - - return theme('menu_item_link', $item, $link_item); -} - -/** - * Returns the rendered local tasks. The default implementation renders - * them as tabs. - * - * @ingroup themeable - */ -function theme_menu_local_tasks() { - $output = ''; - - if ($primary = menu_primary_local_tasks()) { - $output .= "
      \n". $primary ."
    \n"; - } - if ($secondary = menu_secondary_local_tasks()) { - $output .= "
      \n". $secondary ."
    \n"; - } - - return $output; -} - -/** - * Returns the rendered HTML of the primary local tasks. - */ -function menu_primary_local_tasks() { - $local_tasks = menu_get_local_tasks(); - $pid = menu_get_active_nontask_item(); - $output = ''; - - if (count($local_tasks[$pid]['children'])) { - foreach ($local_tasks[$pid]['children'] as $mid) { - $output .= theme('menu_local_task', $mid, menu_in_active_trail($mid), TRUE); - } - } - - return $output; -} - -/** - * Returns the rendered HTML of the secondary local tasks. - */ -function menu_secondary_local_tasks() { - $local_tasks = menu_get_local_tasks(); - $pid = menu_get_active_nontask_item(); - $output = ''; - - if (count($local_tasks[$pid]['children'])) { - foreach ($local_tasks[$pid]['children'] as $mid) { - if (menu_in_active_trail($mid) && count($local_tasks[$mid]['children']) > 1) { - foreach ($local_tasks[$mid]['children'] as $cid) { - $output .= theme('menu_local_task', $cid, menu_in_active_trail($cid), FALSE); - } - } - } - } - - return $output; -} - -/** - * Generate the HTML representing a given menu item ID as a tab. - * - * @param $mid - * The menu ID to render. - * @param $active - * Whether this tab or a subtab is the active menu item. - * @param $primary - * Whether this tab is a primary tab or a subtab. - * - * @ingroup themeable - */ -function theme_menu_local_task($mid, $active, $primary) { - if ($active) { - return '
  • '. menu_item_link($mid) ."
  • \n"; - } - else { - return '
  • '. menu_item_link($mid) ."
  • \n"; - } -} - -/** - * Returns an array containing the primary links. - * Can optionally descend from the root of the Primary links menu towards the - * current node for a specified number of levels and return that submenu. - * Used to generate a primary/secondary menu from different levels of one menu. - * - * @param $start_level - * This optional parameter can be used to retrieve a context-sensitive array - * of links at $start_level levels deep into the Primary links menu. - * The default is to return the top-level links. - * @param $pid - * The parent menu ID from which to search for children. Defaults to the - * menu_primary_menu setting. - * @return An array containing the themed links as the values. The keys of - * the array contain some extra encoded information about the results. - * The format of the key is {level}-{num}{-active}. - * level is the depth within the menu tree of this list. - * num is the number within this array, used only to make the key unique. - * -active is appended if this element is in the active trail. - */ -function menu_primary_links($start_level = 1, $pid = 0) { - if (!module_exist('menu')) { - return NULL; - } - if (!$pid) { - $pid = variable_get('menu_primary_menu', 0); - } - if (!$pid) { - return NULL; - } - - if ($start_level < 1) { - $start_level = 1; - } - - if ($start_level > 1) { - $trail = _menu_get_active_trail_in_submenu($pid); - if (!$trail) { - return NULL; - } - else { - $pid = $trail[$start_level - 1]; - } - } - - $menu = menu_get_menu(); - $links = array(); - if ($pid && is_array($menu['visible'][$pid]) && isset($menu['visible'][$pid]['children'])) { - $count = 1; - foreach ($menu['visible'][$pid]['children'] as $cid) { - $index = "menu-$start_level-$count"; - if (menu_in_active_trail_in_submenu($cid, $pid)) { - $index .= "-active"; - } - $links[$index] = menu_item_link($cid); - $count++; - } - } - - // Special case - provide link to admin/menu if primary links is empty. - if (empty($links) && $start_level == 1 && $pid == variable_get('menu_primary_menu', 0)) { - $links['1-1'] = l(t('edit primary links'),'admin/menu'); - } - - return $links; -} - -/** - * Returns an array containing the secondary links. - * Secondary links can be either a second level of the Primary links - * menu or generated from their own menu. - */ -function menu_secondary_links() { - $msm = variable_get('menu_secondary_menu', 0); - if ($msm == 0) { - return NULL; - } - - if ($msm == variable_get('menu_primary_menu', 0)) { - return menu_primary_links(2, $msm); - } - - return menu_primary_links(1, $msm); -} - -/** - * Returns the themed HTML for primary and secondary links. - * Note that this function is overridden by most core themes because - * those themes display links in "link | link" format, not from a list. - * Also note that by default links rendered with this function are - * displayed with the same CSS as is used for the local tasks. - * If a theme wishes to render links from a ul it is expected that - * the theme will provide suitable CSS. - * - * @param $links - * An array containing links to render. - * @return - * A string containing the themed links. - * - * @ingroup themeable - */ -function theme_menu_links($links) { - if (!count($links)) { - return ''; - } - $level_tmp = explode('-', key($links)); - $level = $level_tmp[0]; - $output = "