'media_ahah_formatter_load', 'access arguments' => array('access content'), 'file' => 'media_ahah.inc', ); $items['media/metadata/js'] = array( 'page callback' => 'media_ahah_metadata_ahah', 'access arguments' => array('access content'), 'file' => 'media_ahah.inc', ); // Default settings, for content types that do not have their own. $items['admin/settings/media'] = array( 'title' => 'Media settings', 'description' => 'Configure Global Media settings, including default content type settings.', 'page callback' => 'drupal_get_form', 'page arguments' => array('media_settings_global', 'global'), 'access arguments' => array('administer media'), 'file' => 'media_settings.inc', 'weight' => 3, ); return $items; } /** * Implementation of hook_form_alter(). * @param $form * @param $form_state * @param $form_id */ function media_form_alter(&$form, $form_state, $form_id) { global $user; // Load content-type settings if ($form_id == 'node_type_form') { include_once('media_settings.inc'); media_settings_content_type($form, $form['#node_type']->type); } // Add the media browser on the node add/edit screen. if (strstr($form_id, 'node_form') ) { // Is the media browser enabled on this node type? Type-specific options override the default. if (variable_get('media_'. $form['type']['#value'] .'_override', NULL) !== NULL) { $enabled = variable_get('media_'. $form['type']['#value'] .'_enabled', NULL); } else { $enabled = variable_get('media_global_enabled', TRUE); } if ($enabled) { // Get the fields we need to enable on this module. $fields = media_active_fields_for_node_type($form['type']['#value']); // Iterate through each field and add a browser form. foreach ($fields as $field => $registration_ids) { // Add the media browser form. $form[$field]['media'] = media_build_browser_form($form_state, $registration_ids, $form['type']['#value'], $field, $user->uid); // Add .media and .replace class to the field CSS class attributes. $form[$field][0]['#attributes'] = array('class' => 'media replace'); } } } } /** * Implements hook_theme(). * Register theming functions * * @return array */ function media_theme() { return array( // The media file browser form. 'media_file_browser' => array( 'file' => 'media_theme.inc', 'arguments' => array('element' => NULL), ), // The default media file list form element. 'media_file_list' => array( 'file' => 'media_theme.inc', 'arguments' => array('element' => NULL), ), // The media browser pane. 'media_browser_pane' => array( 'file' => 'media_theme.inc', 'arguments' => array('form' => array()), ), ); } /* ***************************************** */ /* Media hook calls */ /* ***************************************** */ /** * Gets all of the modules which register with Media. * * @param array $ids * (Optional) If this contains an array of id strings, then return only the * specified ids. * @param boolean $reset * (Optional) If TRUE, then reset the static cache. * @return array * An array of registrations, keyed by implementing function name, in the * form of: * 'module' => The module implementing the hook. * 'uri' => The scheme the stream wrapper handles, default is 'public://'. * 'types' => The mime types this module handles, defaults to * (all). * 'name' => A human readable name, displayed on forms. * 'kind' => Kind of functionality: 'resource' or 'format'. * 'description' => A verbose description of functionality. * 'callbacks' => An array of key => functions called for data. * 'fields' => What fields does this functionality operate on? * 'validation' => @todo * 'display' => @todo */ function media_get_registered_modules($ids = NULL, $reset = FALSE) { static $registrations; // Only build cache the first time the function is called, or if we reset it. if (is_NULL($registrations) || $reset) { $registrations = array(); // Get all the modules which implement hook_media_register(). foreach (module_implements('media_register') as $module) { $function = $module .'_media_register'; // Get all the registrations defined by the module. $registration = $function(); // TODO: Fix this. Why are we calling $function twice (jmstacey 6/2/09)? // Iterate through each registration defined by the implementing module. foreach (array_keys($function()) as $key) { // Add the module name to each registration. // Default the 'module' key of the registration to the implementing module. $registration[$key]['module'] = $registration[$key]['module'] ? $registration[$key]['module'] : $module; // translate strings now $registration[$key]['name'] = t($registration[$key]['name']); $registration[$key]['description'] = t($registration[$key]['description']); // Default the 'uri' to public://. if (!$registraton[$key]['uri']) { $registration[$key]['uri'] = MEDIA_RESOURCE_URI_DEFAULT; } // Default 'types' to * (all). if (!$registration[$key]['types']) { $registration[$key]['types'] = MEDIA_TYPES_DEFAULT; } } // Add the new registrations to our total. $registrations = array_merge($registrations, $registration); } } // Return requested registrations. if ($ids) { foreach ($ids as $id) { $return[$id] = $registrations[$id]; } return $return; } return $registrations; } /* ***************************************** */ /* Media API Functions */ /* ***************************************** */ /** * Build a list of possible registration types. * 'resource' handles building file resource lists. * 'formatter' displays a list of file resources for the file browser. * 'attach' passes an FID to the registered module for handling. * * @return array */ function media_registration_kinds() { return array('resource', 'formatter'); } /** * Get all fields that can be enabled on a field type. * * @param string $field_type * The field type to get items for. * @param string $function_type * The kind of functionality being looked for. * @return array * Array of full registration objects. */ function media_get_fields($field_type, $function_type = 'resource') { static $data; // Do we have cached version? if ($data[$field_type][$function_type]) { return $data[$field_type][$function_type]; } $data = array(); // Get all the registered modules. foreach (media_get_registered_modules() as $id => $registration) { // Check to see if this registration supports this function type. if ($registration['kind'] == $function_type) { // Now look for the fields. if ($registration['fields']) { foreach ($registration['fields'] as $field) { // If this registration supports this field type, add it to the // returned array. if ($field == $field_type) { $data[$field_type][$function_type][$id] = $registration; } } } } } return $data[$field_type][$function_type]; } /** * Select registrations for use by matching against uri and file extension. * * @param array $registrations * Array of extensions. * @param string $uri * The kind of uri being used. * @param string $file_extension * The current file extension. * @return array * An array of applicable formatters. */ function media_get_applicable_formatters($registrations, $file_extension) { // Do we have a file extension? if ($file_extension) { foreach ($registrations as $id => $formatter) { // Does this formatter use any file type? If not, then we have to dig. if (!$formatter['types'] == MEDIA_TYPES_DEFAULT) { // We need to see if this file type is supported specifically. if (!in_array($file_extension, $registration['types'])) { // This registration is not useful. unset($registrations[$id]); } } } } return $registrations; } /* ***************************************** */ /* Media Internal Functions */ /* ***************************************** */ /** * Parsing function for the registrations to hand back the kinds of modules * registering. Used to select all formatters, resources, etc. * * @param string $kinds * Return all the matching registrations of this kind. * @return array * An array of matching registrations. */ function media_get_registration_kinds($kind = NULL) { $kinds = array(); // Get the registered modules. $registrations = media_get_registered_modules(); // Parse the registrations. foreach ($registrations as $id => $registration) { if ($kind) { // Get the kind that is being looked for. if ($registration['kind'][$kind]) { $kinds[$id] = $registration; } } else { $kinds[$id] = $registration; } } return $kinds; } /** * Return a set of formatters which can format the specified item. * * If $description is NULL, all formatters will be returned. A set of * registered modules can be passed in to narrow the formatter options. * * @param string $description * File extension to return. * @param array $registrations * (Optional) If specified, then match only against these registrations. * @return array * An array of formatter ids keyed by module. */ function media_registration_item_formatters($description = '*', $registrations = NULL) { $formatters = array(); // Get all the registrations if we don't have any. if (is_NULL($registrations)) { $registrations = media_get_registered_modules(); } // Iterate through each of the registered modules and find the formatters. foreach ($registrations as $id => $registration) { // Look for the formatter, or just take all (wildcard being *). if ((is_array($registration['kind']['formatter']['types']) && in_array($registration['kind']['formatter']['types'], $description)) || $description == '*' || $registration['kind']['formatter']['types'] == '*') { $formatters[$registration['module']] = $id; } } return $formatters; } /** * Parsing function for the registrations to hand back the kinds of modules * registering. * * @param string $type * Only hand back data for the specified type. * @return array * @TODO: finish this function. */ function media_registration_types($type = NULL) { // get the registered modules $registrations = media_get_registered_modules(); // parse the registrations foreach ($registrations as $registration) { // @TODO } } /** * Parsing function for the registrations to hand back the kinds of modules * registering. * * @param string $array * Name of the element we want to get data from. * @return array */ function media_registration_data($name) { $data = array(); // Get the registered modules. $registrations = media_get_registered_modules(); // Parse the registrations. foreach ($registrations as $id => $registration) { // Do we have this data in this registration? if ($registration[$name]) { // Get the item that was requested. $data[$registration['module']] = array( $id => array( $name => $registration[$name], 'description' => $registration['description'] ) ); } } return $data; } /** * Fetch all resources registered and call the specified callback. I * * Also add item to the media browser as a horizontal tab. * * @TODO Implement admin weighting here somehow. * * @param array $registration_ids * Array of registration ids to be loaded. * @param string $node_type * Drupal node type. * @param field $field * CCK field name. * @param int $uid * Drupal {user} id. * @return array */ function media_get_resources($registration_ids, $node_type, $field, $uid) { // Get all the registrations that define the resources. $registrations = media_get_registered_modules($registration_ids); foreach ($registrations as $id => $registration) { // Get the callback function. $function = $registration['callbacks']['resource']; if (function_exists($function)) { // Get the results of the callback function. $item = $function($node_type, $field, $uid); $tab_name = check_plain(key($item)); // Add a resource_id to the item. $item[$tab_name][key($item[$tab_name])]['resource_id'] = array( '#type' => 'value', '#value' => $id, ); // Add a resource module to the item so that we don't have to figure it out later $item[$tab_name][key($item[$tab_name])]['registered_module'] = array( '#type' => 'value', '#value' => $registration['module'], ); // Add tabs under the tab name. $items[$tab_name][key($item[$tab_name])] = $item[$tab_name][key($item[$tab_name])]; } } return $items; } /** * Get a list of fields for the requested node type. * * @param string $type_name * Drupal {node} type. * @param string $function * Either 'resource' or 'formatter'. * @return array * An array of field names. */ function media_active_fields_for_node_type($type_name, $function = 'resource') { // Need to know if the type-specific or global settings are going to be used. // At least one of them is enabled at this point. $type_override = variable_get('media_'. $type_name .'_override', FALSE); $items = array(); $type = _media_content_field_types($type_name); // extract the fields for this node type foreach ((array)$type['fields'] as $field_name => $field) { // Ignore the content-type specific per-field setting unless the override is set $fields_enabled = FALSE; if ($type_override) { $fields_enabled = variable_get('media_'. $type_name .'_'. $field['field_name'] .'_'. $function, FALSE); } else { //@TODO: Right now, if it's using the default it will be enabled for all fields. // Eventually it will probably be better to allow per-field controls at a global level as well. // However, this line will probably just work once the actual variables exist. $fields_enabled = variable_get('media_global_'. $field['field_name'] .'_'. $function, 'default'); // Handle the default special, because we want the default to be on for all fields but don't know what the fields are yet. if ($fields_enabled === 'default') { $fields_enabled = array(); foreach (media_registration_kinds() as $kind) { // get all the kinds that match this field if ($registrations = media_get_fields($field['type'], $kind)) { foreach ($registrations as $id => $registration) { $compound_id = $field['field_name'] .'--'. $id; $fields_enabled[$compound_id] = $compound_id; } } } } } if (!empty($fields_enabled)) { $items[] = $fields_enabled; } } $data = array(); foreach ($items as $item) { foreach ($item as $id => $value) { // we need to split the $id into $field_name and $media registration id if ($value) { $id = explode('--', $id); $data[$id[0]][] = $id[1]; } } } return $data; } /** * Sanitize the incoming name to be used for a html #id. * * @param string $drawer_name * @return string */ function media_create_id($drawer_name) { return str_replace(array(' ', "'", '"', "%", "<", ">"), '', $drawer_name); } /** * Get a list of content field types. * * Use CCK if available. * * @param string $type_name * A string representing the content type. * @return array * A form structured array is returned. */ function _media_content_field_types($type_name) { if (module_exists('content')) { $type = content_types($type_name); } else { // Get the specific content type. $type = (array)node_get_types('type', $type_name); } // Recognize the upload/attachment form and create an artificial field. // This should be the only one we ever have to do this for. if (module_exists('upload')) { $type['fields']['attachments'] = array( 'field_name' => 'attachments', 'type' => 'attachments', 'widget' => array( 'label' => $type['extra']['attachments']['label'], ), ); } return $type; } /* *************************************************** */ /* Media forms */ /* *************************************************** */ /** * Build data for the media browser display. * * @TODO Clean this form up and use a form theme function. * * Note: The FAPI docs say a submit element event defaults to 'click', * but as of d6.10, it defaults to 'mousedown', so we need to override. * 'event' => 'click', * * @param array $registration_ids * Array of registrations to call. * @param string $node_type * @param string $field * @param uid $uid * @return array * Drupal FAPI form array. */ function media_build_browser_form($form_state, $registration_ids, $node_type, $field, $uid) { static $id; // We need a static counter for our form element wrapper. $id += 1; // Load our css. $path = drupal_get_path('module', 'media'); drupal_add_css($path .'/media.css'); // Load our specific js for the file selector drupal_add_js($path .'/javascript/media.js'); // Load the md5 library so we can hash the upload filename for use in the meta form. drupal_add_js($path .'/javascript/jquery.md5.js'); $items = array(); $form = array(); $form['media_browser_activate'] = array( '#type' => 'markup', '#value' => '