'am/loader', 'callback' => 'am_load_popup', 'access' => user_access('access am'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'am/list', 'callback' => 'am_list_nodes', 'callback arguments' => array(arg(2),arg(3)), 'access' => user_access('access am'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'am/fieldinfo', 'callback' => 'am_fieldinfo', 'callback arguments' => array(arg(2)), 'access' => user_access('access am'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'am/save', 'callback' => 'am_save', 'access' => user_access('access am'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'am/load', 'title' => t('Asset Manager'), 'callback' => 'am_loader', 'access' => user_access('access am'), 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'am/node_load', 'title' => t('Asset Manager'), 'callback' => 'am_node_load', 'access' => user_access('access am'), 'type' => MENU_CALLBACK, ); } else { $items[] = array( 'path' => 'admin/settings/am', 'title' => t('Asset Manager'), 'description' => t('Configure asset manager settings.'), 'callback' => 'drupal_get_form', 'callback arguments' => 'am_settings', 'access' => user_access('administer am'), ); } return $items; } /** * Outputs AM popup. * * @param $type * The type of popup. This is currently only for tinymce support. * * @return none */ function am_loader($type) { if($type == 'tinymce') { // I'd prefer not to hard code for tinymce here, but I can't figure out a better solution $tinymce_path = drupal_get_path('module', 'tinymce'); $tinymce_js = $tinymce_path .'/tinymce/jscripts/tiny_mce/tiny_mce_popup.js'; drupal_add_js($tinymce_js); $path = drupal_get_path('module', 'am'); $editor_js = $path .'/am_tinymce.js'; drupal_add_js($editor_js); drupal_add_js('am_tinymce = true;', 'inline'); } am_load_popup($type); } /** * Implementation of hook_perm * * @param none * * @return array() * Returns array of permissions */ function am_perm() { return array('access am', 'administer am'); } /** * Outputs json object with list of nodes matching $type and/or $tid. * * @param $type * The node type to search on. If not defined then return empty json array. * * @param $tid * The taxonomy term id. If not specified then return all nodes matching the $type. * * @return none */ function am_list_nodes($type,$tid) { $nodes = array(); if ($tid == 0) { $tid = 'undefined'; } if ($type == 'null' || $type == 'undefined') { print drupal_to_js(array()); exit; } if (is_numeric($tid)) { $found = am_select_nodes(array($tid),'or','all', $type, 500); } else { $found = db_query("SELECT * FROM {node} WHERE type='%s' AND status=1 ORDER BY created DESC LIMIT 0,500", $type); } if (db_num_rows($found)) { while ($node = db_fetch_object($found)) { $node = node_load($node->nid); $node->content = node_view(drupal_clone($node), TRUE, FALSE, FALSE); $type = explode('/', $node->field_image[0]['filemime']); $nodes[] = array( 'nid' => $node->nid, 'title' => $node->title, 'thumb' => theme('imagecache', 'am_thumb', $node->field_image[0]['filepath'], $node->title, $node->title), 'type' => ucwords($node->type) . ': ' . strtolower($type[1]), 'content' => theme('imagecache', 'am_preview', $node->field_image[0]['filepath'], $node->title, $node->title), ); } } print drupal_to_js(array('nodes' => $nodes)); exit; } /** * Outputs json object with node type / name. * * @param $type * The node type to search on. If not defined then return empty json array. * * @return none */ function am_fieldinfo($type = NULL) { $return = array(); $all_fields = node_get_types(); if ($type) { $field = content_fields($type); foreach ($field['referenceable_types'] as $type => $allowed) { if ($allowed) { $return[$type] = $all_fields[$type]->name; } } } else { // hardcoded allowed types for now $allowed = array('image', 'photo'); foreach ($all_fields as $type => $values) { if (in_array($type, $allowed)) { $return[$type] = $values->name; } } } print drupal_to_js(array('types' => $return)); exit; } /** * Builds popup page html. Prints the output based on the themed sections of the page * * @param none * * @return none */ function am_load_popup() { // Setup page header drupal_set_title("Asset Manager"); jquery_form_add(); drupal_add_js(drupal_get_path('module','am') . '/am_loader.js'); /* TODO: * This is the correct way to add this css file, but I don't want to use the rest of the css * from the system settings and default theme html so we just manually put this in the * am_window.tpl.php template file. */ //drupal_add_css(drupal_get_path('module','am') . '/am_window.css'); print theme('am_popup'); } /** * Build the form * * @param none * * @return $form * The form array. */ function am_filter_form() { $form = array(); $options = array(); $form['node-type-filter'] = array( '#type' => 'select', '#title' => t('Node Type'), '#options' => $options, '#description' => t('Select Node Type to filter'), '#multiple' => FALSE, '#attributes' => array('id' => 'node-type-filter', 'class' => 'input'), '#weight' => -9, ); $form['node-channel-filter'] = taxonomy_form(variable_get('am_vid', 0)); $form['node-channel-filter']['#attributes'] = array('id' => 'node-channel-filter', 'class' => 'input'); $form['node-channel-filter']['#multiple'] = FALSE; $form['node-channel-filter']['#size'] = 1; $form['node-channel-filter']['#weight'] = -10; $form['node-channel-filter']['#description'] = t('Select Channel to filter'); $form['node-name-filter'] = array( '#name' => 'name-filter', '#type' => 'textfield', '#title' => t('Filter'), '#description' => t('Filter your search by title'), '#id' => 'node-name-filter', '#attributes' => array('class' => 'input'), '#weight' => -8, ); return $form; } function am_select_form() { $form = array(); // ATTIKS $presets = array(); $result = db_query('SELECT presetid, presetname FROM {imagecache_preset} ORDER BY presetname'); while ($row = db_fetch_array($result)) { $presets[$row['presetname']] = $row['presetname']; } $form['imagecachepresets'] = array( '#type' => 'select', '#title' => t('Image cache preset'), '#options' => $presets, '#description' => t('The namespace of an imagecache preset.'), '#multiple' => FALSE, '#attributes' => array('id' => 'imagecachepresets', 'class' => 'input'), ); $form['select'] = array( '#type' => 'submit', '#value' => 'Select for use', '#attributes' => array('class' => 'btn') ); return $form; } /** * Implementation of hook_form_alter. Set the #action to point to our am/save so we can save * the node via AJAX. * * @param $form_id * The form id * * @param $form * The form we are altering. * * @return $form * The form array. */ function am_form_alter($form_id, &$form) { if (substr($_REQUEST['q'],0,9) == 'am/loader' && $form_id == $form['type']['#value'] . '_node_form') { $form['#action'] = '/am/save'; //Ugh. Hackfest 2007. This is fucked and we need to fix it. unset($form['log']); unset($form['author']); unset($form['options']); unset($form['menu']); unset($form['path']); unset($form['comment_settings']); unset($form['preview']); } } /** * Implementation of hook_settings() * * @param none * * @return $form * The form array. */ function am_settings() { $form = array(); $options = array(); // Build list of available vocabularies for filtering $vocabs = taxonomy_get_vocabularies(); foreach ($vocabs as $vocabulary) { $options[$vocabulary->vid] = $vocabulary->name; } if ($options) { $form['am_vid'] = array( '#type' => 'select', '#multiple' => FALSE, '#title' => t('Asset Manager Vocabulary'), '#default_value' => variable_get('am_vid', 0), '#options' => $options, '#size' => 9, '#description' => t('Which vocabularies should the Asset Manager use?'), ); } $form = system_settings_form($form); return $form; } /** * Saves the node via the drupal_execute. Outputs a json data structure with result. * * TODO: needs to update status with failure. * * @param none * * @return none */ function am_save() { global $user; $form_values = $_POST; $type = substr($_POST['form_id'], 0, strlen($_POST['form_id']) - 10); $title = $form_values['title']; $node = array('type' => $type, 'name' => $user->name); $result = drupal_execute($_POST['form_id'], $_POST, $node); list($trashme,$nid) = explode('/', $result); if ($nid) { $return = array( 'status' => TRUE, 'data' => array( 'nid' => $nid, 'title' => $title, 'message' => theme('status_messages'), ) ); } else { $return = array( 'status' => FALSE, 'data' => array( 'nid' => 0, 'title' => 'error', 'message' => theme('error_messages'), ) ); } print drupal_to_js((object)$return); exit; } /** * Searches nodes for taxonomy. Based on taxonomy_select_nodes. * * @param none * * @return none */ function am_select_nodes($tids = array(), $operator = 'or', $depth = 0, $type = NULL, $max = 25) { $order = 'n.created DESC'; if (count($tids) > 0) { // For each term ID, generate an array of descendant term IDs to the right depth. $descendant_tids = array(); if ($depth === 'all') { $depth = NULL; } foreach ($tids as $index => $tid) { $term = taxonomy_get_term($tid); $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth); $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree)); } if ($operator == 'or' && !empty($descendant_tids)) { $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids)); $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE ' . ($str_tids?'tn.tid IN ('. $str_tids .') AND':'') . ' n.status = 1 '; $sql .= empty($type) ? '' : " AND n.type = '" . $type . "' "; $sql .= ' ORDER BY n.created DESC'; } else { $joins = ''; $wheres = ''; foreach ($descendant_tids as $index => $tids) { if (!empty($tids)) { $dtids = is_array($tids) ? implode(',', $tids) : $tids; $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid '; $wheres .= ' AND tn'. $index .'.tid IN ('. $dtids .')'; } } $wheres .= empty($type) ? '' : " AND n.type = '" . $type . "' "; $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order; } $sql .= $max > 0 ? ' LIMIT 0, ' . $max : NULL; $result = db_query($sql); } return $result; } /** * Outputs json array with themed node content for previewing / listing in the AM popup. * * @param $nid * Node ID for theming * * @return none */ function am_node_load($nid, $cachepreset) { if (is_numeric($nid)) { $node = (array)node_load($nid); $node = theme('am_content', $node, $cachepreset); $nodes = '[AM|' . 'nid=' . $node['nid'] . '|title=' . $node['title'] . '|imagecachepreset=' . $cachepreset . ']'; print drupal_to_js($nodes); exit; /* $node = (array)node_load($nid); $node = theme('am_content', $node, $cachepreset); print drupal_to_js($node); */ } } /****************************************************************************** * Widget Section * *****************************************************************************/ /** * Implementation of hook_widget_info. * Specifies the label and that it is a widget for the nodereference field type * * @param none * * @return $form * The widget array. */ function am_widget_info() { return array( 'amfield' => array( 'label' => 'Asset Manager Field', 'field types' => array('nodereference'), ), ); } /** * Implementation of hook_widget(). */ function am_widget($op, &$node, $field, &$items) { switch ($op) { case 'default value': return array(); case 'prepare form values': foreach ($items as $delta => $item) { if (!empty($items[$delta]['nid'])) { $items[$delta]['default node_name'] = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $items[$delta]['nid'])); $items[$delta]['default node_name'] .= ' [nid:'. $items[$delta]['nid'] .']'; } } break; case 'form': $form = array(); drupal_add_js(drupal_get_path('module','am') . '/am.js'); $form[$field['field_name']] = array('#tree' => TRUE); $form[$field['field_name']][0]['node_name'] = array( '#type' => 'textfield', '#title' => t($field['widget']['label']), '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], '#default_value' => $items[0]['default node_name'], '#required' => $field['required'], '#description' => $field['widget']['description'], '#attributes' => array('class' => 'am-field'), '#suffix' => l('Asset Manager', 'am/loader/' . substr($field['field_name'],6), array('class' => 'am-loader')), ); return $form; case 'validate': foreach ($items as $delta => $item) { $error_field = $field['field_name'].']['.$delta.'][node_name'; if (!empty($item['node_name'])) { preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $item['node_name'], $matches); if (!empty($matches)) { // explicit nid list(, $title, $nid) = $matches; if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) { form_set_error($error_field, t('Title mismatch. Please check your selection.')); } } } } return; case 'process form values': foreach ($items as $delta => $item) { $nid = 0; if (!empty($item['node_name'])) { preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $item['node_name'], $matches); if (!empty($matches)) { $nid = $matches[2]; } else { $nids = _nodereference_potential_references($field, FALSE, $item['node_name'], TRUE); $nid = (!empty($nids)) ? array_shift(array_keys($nids)) : 0; } } // Remove the widget's data representation so it isn't saved. unset($items[$delta]['node_name']); if (!empty($nid)) { $items[$delta]['nid'] = $nid; $items[$delta]['error_field'] = $field['field_name'].']['.$delta.'][node_name'; } elseif ($delta > 0) { // Don't save empty fields when they're not the first value (keep '0' otherwise) unset($items[$delta]); } } break; } } /****************************************************************************** * Theming Functions * *****************************************************************************/ /** * Theme the node content for preview display in the AM * * TODO: Need to out put based on what kind of node we are theming. * * @param $node * Node object for theming * * @return $node * Node array with themed content */ function theme_am_content(&$node, $cachepreset) { if (isset($node['field_image'][0]['filepath'])) { $path = $node['field_image'][0]['filepath']; } else { $path = file_create_path($node['images']['_original']); } $node['content'] = theme('imagecache', $cachepreset, $path, $node->title, $node->title); return $node; } /** * Theme the main popup window. * * @param $content * Data for the content div. * * @return * The rendered html. */ function theme_am_popup($content = '') { $vars = array( 'content' => $content, 'filter' => drupal_get_form('am_filter_form'), 'head' => drupal_get_html_head(), 'messages' => theme('status_messages'), // TODO: need to change this to be able to be dynamically selected in addition to // having a setting for "default" node add type. 'node_add' => drupal_get_form('image_node_form', array('type' => 'image')), 'scripts' => drupal_get_js(), 'select' => drupal_get_form('am_select_form'), 'styles' => drupal_get_css(), 'title' => drupal_get_title(), ); $template = drupal_get_path('module', 'am') . '/am_window.tpl.php'; return _phptemplate_render($template, $vars); } /** * Returns the rendered html for the finder div * * @param $content * * @return $output * Returns rendered html */ function theme_am_finder($content) { $output = '
' . "\n"; $output .= $content; $output .= '
' . "\n"; return $output; } /** * Returns the rendered html for the node form div * * @param $content * * @return $output * The form array. */ function theme_am_node_add($content = '') { $output = '
' . "\n"; $output .= '
' . "\n"; $output .= $content; $output .= '
' . "\n"; return $output; } /** * Returns the rendered html for the node preview area * * @param none * * @return $form * The form array. */ function theme_am_node_preview($content = 'Select Node To Preview', $channel = NULL) { $output = '
' . "\n"; $output .= '
' . "\n"; $output .= $content; $output .= '
' . "\n"; $output .= '
' . "\n"; return $output; } /* TEMP: am_results Kitten Sniper, Image: jpg
Kitten Suicide, Image: jpg
Kitten Hold Up, Image: jpg
Kitten Machine Gun, Image: jpg
Kitten Sniper, Image: jpg
Kitten Suicide, Image: jpg
*/ // ATTIKS filter hooks /** * Implementation of hook_filter(). */ function am_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list' : return array (0 => t('Inline AM')); case 'description' : return t('Add formatted AM to your posts.'); case 'process' : foreach (am_get_macros($text) as $unexpanded_macro => $macro) { $expanded_macro = am_render_macro($macro); $text = str_replace($unexpanded_macro, $expanded_macro, $text); } return $text; default : return $text; } } /** * Implementation of hook_filter_tips(). */ function am_filter_tips($delta, $format, $long = false) { if ($long) { return t('Inline AM is allowed. Use the link or the WYSIWYG editor button to insert the proper format.'); } else { return t('Inline AM is allowed.'); } } /** * Return all macros as an array. */ function am_get_macros($text) { $m = array (); preg_match_all('/ \[ ( [^\[\]]+ )* \] /x', $text, $matches); $tag_match = (array) array_unique($matches[1]); // Don't process duplicates. foreach ($tag_match as $macro) { $current_macro = '[' . $macro . ']'; $param = array_map('trim', explode('|', $macro)); $func_name = array_shift($param); // The first macro param is assumed to be the function name. //$num_params = count($param); // Get the number of parameters if ($func_name == 'AM') { $vars = array (); foreach ($param as $p) { $pos = strpos($p, '='); $varname = substr($p, 0, $pos); $varvalue = substr($p, $pos +1); $vars[$varname] = $varvalue; } // the full unaltered filter string is the key for the array of filter attributes $m[$current_macro] = $vars; } } return $m; } /** * build html from atrributes array. * * @param $attr * Array of attributes parsed from filter macro. */ // Format of inline string. // [AM|nid=32|title=aze|imagecachepreset=am_preview] function am_render_macro($attr = array ()) { $node = node_load($attr['nid']); // watchdog ('debug', $node->nid, $node); // watchdog ('debug', $node->field_image[0]['filepath'], $node); // watchdog ('debug', $attr['imagecachepreset'], $node); if (isset($node->field_image[0]['filepath'])) { $path = $node->field_image[0]['filepath']; } else { $path = file_create_path($node['images']['_original']); } $cachepreset = $attr['imagecachepreset']; if ($cachepreset == '') { $cachepreset = 'am_preview'; } $title = $attr['title']; if ($title == '') { $title = $node->title; } return theme('imagecache', $cachepreset, $path, $title, $title); }