empty the filter cache to correct image paths that are pointing to the old address. Note that this will only work for images that have been inserted using filter tags.', array('!empty-cache' => url('img_assist/cache/clear'))); case 'img_assist/template': return '
%image
%caption
'; } } /** * Implementation of hook_theme(). */ function img_assist_theme() { return array( 'img_assist_inline' => array( 'arguments' => array('node' => NULL, 'size' => NULL, 'attributes' => NULL), ), 'img_assist_filter' => array( 'arguments' => array('text' => NULL), ), 'img_assist_popup' => array( 'arguments' => array('content' => NULL, 'attributes' => NULL), ), 'img_assist_page' => array( 'arguments' => array('content' => NULL, 'attributes' => NULL), ), 'img_assist_legacy' => array(), ); } /** * Implementation of hook_menu(). */ function img_assist_menu() { $items = array(); $items['img_assist/cache/clear'] = array( 'title' => 'Empty cache', 'page callback' => 'img_assist_cache_clear', 'access arguments' => array('administer site configuration'), 'type' => MENU_CALLBACK, ); $items['img_assist/load'] = array( 'title' => 'Image assist', 'page callback' => 'img_assist_loader', 'access arguments' => array('access img_assist'), 'type' => MENU_CALLBACK, ); // Page callbacks called internally by img_assist/load. $items['img_assist/header'] = array( 'title' => 'Image assist header', 'page callback' => 'img_assist_header', 'page arguments' => array(2), 'access arguments' => array('access img_assist'), 'type' => MENU_CALLBACK, ); $items['img_assist/thumbs'] = array( 'title' => 'Image assist thumbnails', 'page callback' => 'img_assist_thumbs', 'access arguments' => array('access img_assist'), 'type' => MENU_CALLBACK, ); $items['img_assist/upload'] = array( 'title' => 'Image assist upload', 'page callback' => 'img_assist_upload', 'access arguments' => array('access img_assist'), 'type' => MENU_CALLBACK, ); $items['img_assist/properties'] = array( 'title' => 'Image assist properties', 'page callback' => 'img_assist_properties', 'access arguments' => array('access img_assist'), 'type' => MENU_CALLBACK, ); // Popup images page. $items['img_assist/popup'] = array( 'title' => 'Popup image', 'page callback' => 'img_assist_popup', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); // Insert callback (only for inserting HTML, not filter tag). $items['img_assist/insert_html'] = array( 'title' => 'Insert callback', 'page callback' => 'img_assist_insert_html', 'access arguments' => array('access img_assist'), 'type' => MENU_CALLBACK, ); $items['admin/settings/img_assist'] = array( 'title' => 'Image assist', 'description' => 'Change settings for the Image assist module.', 'page callback' => 'drupal_get_form', 'page arguments' => array('img_assist_admin_settings'), 'access arguments' => array('administer site configuration'), ); return $items; } /** * Implementation of hook_init(). */ function img_assist_init() { $path = drupal_get_path('module', 'img_assist'); if (arg(0) == 'img_assist') { // Suppress Administration menu. module_invoke('admin_menu', 'suppress'); drupal_add_css($path .'/img_assist_popup.css', 'module', 'all', FALSE); } else { drupal_add_js($path .'/img_assist.js'); if (variable_get('img_assist_page_styling', 'yes') == 'yes') { drupal_add_css($path .'/img_assist.css'); } } } /** * Implementation of hook_perm(). */ function img_assist_perm() { return array('access img_assist', 'access all images', 'access advanced options', 'use original size'); } /** * Implementation of hook_elements(). */ function img_assist_elements() { $type['textarea'] = array( '#process' => 'img_assist_textarea' ); return $type; } /** * Add JavaScript settings for generating the image link underneath textareas. */ function img_assist_textarea($element) { static $initialized = FALSE; if (!user_access('access img_assist')) { return $element; } $link = variable_get('img_assist_link', 'icon'); if ($link == 'icon' || $link == 'text') { if (_img_assist_textarea_match($element['#id']) && _img_assist_page_match() && !strstr($_GET['q'], 'img_assist')) { if (!$initialized) { // Add settings. $settings['link'] = $link; if ($link == 'icon') { $settings['icon'] = drupal_get_path('module', 'img_assist') .'/add-image.jpg'; } drupal_add_js(array('img_assist' => $settings), 'setting'); $initialized = TRUE; } // Attach behavior. // @todo Some browsers do not support underscores in CSS classes. if (!isset($element['#attributes']['class'])) { $element['#attributes']['class'] = 'img_assist'; } else { $element['#attributes']['class'] .= ' img_assist'; } } } return $element; } /** * Implementation of hook_block(). * * Generates a block that references the other places the current image is used. * The block is only visible when looking at the full view of an image. */ function img_assist_block($op = 'list', $delta = 0) { if ($op == 'list') { $blocks[0]['info'] = t('Image reference'); return $blocks; } else if ($op == 'view') { switch ($delta) { case 0: // Since blocks aren't passed node objects (which makes sense) we need // to determine if we are viewing a node and grab its nid. if (arg(0) == 'node' && is_numeric(arg(1))) { $block['subject'] = t('This image appears in...'); $block['content'] = img_assist_get_references(arg(1)); return $block; } break; } } } /** * Implementation of hook_settings(). */ function img_assist_admin_settings() { require_once drupal_get_path('module', 'img_assist') .'/includes/img_assist.token.inc'; // Access settings. $form['access'] = array( '#type' => 'fieldset', '#title' => t('Access settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['access']['img_assist_paths_type'] = array( '#type' => 'radios', '#title' => t('Display Image assist on paths'), '#default_value' => variable_get('img_assist_paths_type', 2), '#options' => array(t('on specific paths'), t('not on specific paths'), t('all paths')), ); $form['access']['img_assist_paths'] = array( '#type' => 'textarea', '#title' => t('Paths'), '#default_value' => variable_get('img_assist_paths', "node/*\ncomment/*"), '#cols' => 40, '#rows' => 5, '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '')), ); $form['access']['img_assist_textareas_type'] = array( '#type' => 'radios', '#title' => t('Display Image assist on text areas'), '#default_value' => variable_get('img_assist_textareas_type', 2), '#options' => array(t('Show on every textarea except the listed textareas.'), t('Show on only the listed textareas.'), t('Show on all textareas.')), ); $form['access']['img_assist_textareas'] = array( '#type' => 'textarea', '#title' => t('Text areas'), '#default_value' => variable_get('img_assist_textareas', "edit-body\nedit-comment"), '#cols' => 40, '#rows' => 5, '#description' => t("Enter one text area form-id per line. Form-id's are used by Drupal to typify them, which allows themers and coders to modify certain form fields, but not all. Find form-id's using this method: view the source of the webpage, then search for the string that's just above the text area and you'll see the form-id nearby. The '*' character is a wildcard. For example, you can specify all CCK fields as %cck-example.", array('%cck-example' => 'edit-field-*')), ); $form['access']['img_assist_link'] = array( '#type' => 'select', '#title' => t('Textarea image link'), '#default_value' => variable_get('img_assist_link', 'icon'), '#options' => array('icon' => t('Show icon'), 'text' => t('Show text link'), 'none' => t('Do not show a link')), '#description' => t('Choose what to show under the textareas for which Image assist is enabled.'), ); // Prepare select options for image browser views. $options = array(); views_include('admin'); $views = views_get_all_views(); $base_tables = views_fetch_base_tables(); foreach ($views as $view) { // Exclude malformed views (@see views/admin.inc). if (!empty($view->disabled) || empty($view->display)) { continue; } // Exclude views considered unusable for IA. if (!($view->base_table == 'node' || $view->base_table == 'files')) { continue; } $options[$view->name] = ($view->get_title() == '') ? $view->name : $view->get_title(); } $form['access']['img_assist_views'] = array( '#type' => 'select', '#multiple' => TRUE, '#title' => t('Image browser views'), '#default_value' => variable_get('img_assist_views', drupal_map_assoc(array('img_assist_browser'))), '#options' => $options, '#required' => TRUE, '#description' => t('Select the views to use for selecting images.'), ); if (module_exists('taxonomy')) { $vocs = array(0 => '<'. t('none') .'>'); foreach (taxonomy_get_vocabularies() as $vid => $voc) { $vocs[$vid] = $voc->name; } if (count($vocs) > 1) { $form['access']['img_assist_vocabs'] = array( '#type' => 'select', '#multiple' => TRUE, '#title' => t('Select the vocabularies to use for Image assist'), '#default_value' => variable_get('img_assist_vocabs', array()), '#options' => $vocs, '#description' => t('Select the vocabularies you want to be able to filter thumbnails by. This setting changes the behavior of Image assist at startup from loading all image thumbnails to displaying a list of image names until a filter is chosen.'), ); } } // Image settings. $form['image'] = array( '#type' => 'fieldset', '#title' => t('Image generation settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['image']['img_assist_max_size'] = array( '#type' => 'textfield', '#title' => t('Maximum inline image size allowed'), '#default_value' => variable_get('img_assist_max_size', '640x640'), '#size' => 9, '#maxlength' => 9, '#description' => t('Enter the number of maximum image dimensions to display with Image assist. This is a way to prevent users from breaking your layouts. This is applied when the filter tag is processed, so it will affect existing images. If an existing image exceeds these dimensions, a smaller derivative of the image will be substituted (or a smaller version will be created if you have allowed Image assist to create its own derivatives).'), ); if (function_exists('image_get_sizes')) { $max_size = explode('x', variable_get('img_assist_max_size', '640x640')); $oversize_count = 0; foreach (image_get_sizes() as $key => $size) { $dimensions = $size['width'] .'x'. $size['height']; if ((!empty($size['width']) && $size['width'] <= $max_size[0]) || (!empty($size['height']) && $size['height'] <= $max_size[1])) { $derivatives[$dimensions] = $size['label']; } elseif ($key == IMAGE_THUMBNAIL) { // Thumbnail option is shown even if it is larger than maximum size. $derivatives[$dimensions] = $size['label']; } else { $oversize_count++; } $allsizes[$key] = $size['label']; } $form['image']['img_assist_popup_label'] = array( '#type' => 'select', '#title' => t('Popup size'), '#default_value' => variable_get('img_assist_popup_label', IMAGE_PREVIEW), '#options' => $allsizes, '#description' => t('Select the size of the image that is popped up.'), ); $oversize_alert = ($oversize_count) ? '
'. format_plural($oversize_count, '1 image size is not being shown because it exceeds the the maximum inline image size setting (see above).', '@count image sizes are not being shown because they exceed the the maximum inline image size setting (see above).') .'' : ''; $form['image']['img_assist_default_label'] = array( '#type' => 'select', '#title' => t('Default size for inline images'), '#default_value' => variable_get('img_assist_default_label', '100x100'), '#options' => $derivatives, '#description' => t('Select a derivative to be used by default for inline images.') . $oversize_alert, ); } $form['image']['img_assist_create_derivatives'] = array( '#type' => 'checkboxes', '#title' => t('Creation of image derivatives'), '#default_value' => variable_get('img_assist_create_derivatives', array()), '#options' => array( 'properties' => t('Create 200x200 images for the image properties window (useful if the thumbnail size is small).'), 'custom_advanced' => t('Allow users with %access permission to create custom size inline images.', array('%access' => 'access advanced options')), 'custom_all' => t('Allow all users to create custom size inline images.'), ), '#description' => t('These options allow Image assist to generate its custom image sizes (in the same manner as image.module) when a user would prefer a different size from the default image sizes defined in the image.module settings.'), ); // Other properties. $form['properties'] = array( '#type' => 'fieldset', '#title' => t('Image property dialog settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['properties']['img_assist_default_link_behavior'] = array( '#type' => 'select', '#title' => t('Default link behavior'), '#default_value' => variable_get('img_assist_default_link_behavior', 'none'), '#options' => array('none' => t('Not a link'), 'node' => t('Link to image page'), 'popup' => t('Open in popup window'), 'url' => t('Go to URL')), '#description' => t('The link behavior can be overridden when inserting images by users with the proper permissions, but these defaults will still be used for everyone else.'), ); $form['properties']['img_assist_default_link_url'] = array( '#type' => 'textfield', '#title' => t('Default URL'), '#default_value' => variable_get('img_assist_default_link_url', 'http://'), '#size' => 30, '#maxlength' => 255, '#description' => t('The default URL is used when Go to URL is choosen as the link behavior.'), ); $form['properties']['img_assist_default_insert_mode'] = array( '#type' => 'select', '#title' => t('Default insert mode'), '#default_value' => variable_get('img_assist_default_insert_mode', 'none'), '#options' => array('filtertag' => t('Filter Tag'), 'html' => t('HTML Code')), '#description' => t('The insert behavior can be overridden by users with the %permission permission when inserting images. Warning: If images are inserted as HTML, Image Assist is not able to correct a link or image URL afterwards. Please also note that users will not be able to edit already inserted images when using HTML code and the TinyMCE plugin.', array('%permission' => t('access advanced options'))), ); $form['properties']['img_assist_load_title'] = array( '#type' => 'radios', '#title' => t('Preset caption title'), '#default_value' => variable_get('img_assist_load_title', 1), '#options' => array(t('Disabled'), t('Enabled')), '#description' => t('If enabled, the title from the image will be loaded as the bolded caption by default.'), ); $token_installed = module_exists('token'); $token_instructions = (!$token_installed ? t('Requires the !token module.', array('!token' => l('Token', 'http://drupal.org/project/token'))) : t('See below for a list of available replacement patterns.')); $form['properties']['img_assist_title_pattern'] = array( '#type' => 'textfield', '#title' => t('Caption title pattern'), '#default_value' => variable_get('img_assist_title_pattern', '[title]'), '#size' => 60, '#maxlength' => 255, '#description' => t('The pattern to generate the bolded caption title from.') .' '. $token_instructions, '#disabled' => !$token_installed, ); $form['properties']['img_assist_load_description'] = array( '#type' => 'radios', '#title' => t('Preset caption text'), '#default_value' => variable_get('img_assist_load_description', 1), '#options' => array(t('Disabled'), t('Enabled')), '#description' => t('If enabled, the body text from the image will be loaded as the caption by default.'), ); $form['properties']['img_assist_description_pattern'] = array( '#type' => 'textfield', '#title' => t('Caption text pattern'), '#default_value' => variable_get('img_assist_description_pattern', '[body]'), '#size' => 60, '#maxlength' => 255, '#description' => t('The pattern to generate the caption text from.') .' '. $token_instructions, '#disabled' => !$token_installed, ); if ($token_installed) { $form['properties']['token_help'] = array( '#title' => t('Replacement patterns'), '#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['properties']['token_help'][] = array( '#value' => theme('token_help', 'node'), ); } if (module_exists('content')) { $options = array(); $info = _content_type_info(); foreach ($info['content types']['image']['fields'] as $field) { $options[$field['field_name']] = t($field['widget']['label']) .' ('. $field['field_name'] .')'; } $form['properties']['img_assist_display_properties'] = array( '#type' => 'checkboxes', '#title' => t('Image properties shown'), '#default_value' => variable_get('img_assist_display_properties', array()), '#options' => $options, '#description' => t('All selected CCK fields from the Image node will be displayed in the Image Assist pop-up window.'), ); if (empty($options)) { $form['properties']['img_assist_display_properties']['#description'] .= '
'. t('Note: The Image content-type does not contain any CCK fields currently.', array('!content-type' => url('admin/content/node-type/image/fields'))); } } // Image display settings. $form['display'] = array( '#type' => 'fieldset', '#title' => t('Image display settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['display']['img_assist_page_styling'] = array( '#type' => 'select', '#title' => t('Include img_assist.css on all pages for styling inline images?'), '#default_value' => variable_get('img_assist_page_styling', 'yes'), '#options' => array('yes' => t('yes'), 'no' => t('no')), '#description' => t('Advanced users can customize their theme\'s CSS file so that inclusion of the img_assist.css file will not be necessary. See notes at the bottom of img_assist.css for details.'), ); return system_settings_form($form); } /** * Validate Image Assist settings. */ function img_assist_admin_settings_validate($form, &$form_state) { // img_assist_max_size must contain a value for width and height. if (!preg_match('/\d+x\d+/', $form_state['values']['img_assist_max_size'])) { form_set_error('img_assist_max_size', t('Allowed maximum inline image size has to indicate width and height, for example %example.', array('%example' => '200x300'))); } } /** * Implementation of hook_filter(). */ function img_assist_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list': return array(0 => t('Inline images')); case 'description': return t('Add images to your posts with Image assist.'); case 'process': $processed = FALSE; foreach (img_assist_get_macros($text) as $unexpanded_macro => $macro) { $expanded_macro = img_assist_render_image($macro); $text = str_replace($unexpanded_macro, $expanded_macro, $text); $processed = TRUE; } return $processed ? theme('img_assist_filter', $text) : $text; default: return $text; } } /** * Implementation of hook_filter_tips(). */ function img_assist_filter_tips($delta, $format, $long = FALSE) { return t('Images can be added to this post.'); } /** * Implementation of hook_nodeapi(). * * - Clear input filter cache. * - Keep track of where images are used. * - Catch nids of recently uploaded images. */ function img_assist_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { switch ($op) { case 'update': if ($node->type == 'image') { // Clear the input filter cache to force all node content to be rebuilt. // This is to make sure all image paths are up to date. cache_clear_all(NULL, 'cache_filter'); } // break is intentionally left out. case 'insert': // Update the image map. img_assist_map_save($node); break; case 'delete': img_assist_map_delete($node); break; } } /** * Menu callback; clears relevant caches, then redirects to the previous page. * * @see devel_cache_clear() */ function img_assist_cache_clear() { // clear core tables $core = array('cache_filter', 'cache_page'); foreach ($core as $table) { cache_clear_all('*', $table, TRUE); } drupal_set_message('Cache cleared.'); drupal_goto('admin/settings/img_assist'); } /** * @defgroup img_assist_pages Image Assist Pages * @{ * All but img_assist_loader() are in frames. */ /** * Output main img_assist interface HTML. * * @todo Remove hard-coded TinyMCE integration. */ function img_assist_loader() { $path = drupal_get_path('module', 'img_assist'); $caller = arg(2) ? arg(2) : 'textarea'; drupal_add_js($path . '/img_assist_popup.js'); if (module_exists('wysiwyg') && ($editor = wysiwyg_get_editor($caller))) { if ($editor['name'] == 'tinymce') { drupal_add_js($editor['library path'] . '/tiny_mce_popup.js'); } } elseif (module_exists('tinymce') && $caller == 'tinymce') { drupal_add_js(drupal_get_path('module', 'tinymce') . '/tinymce/jscripts/tiny_mce/tiny_mce_popup.js'); } else { $caller = 'textarea'; } drupal_add_js($path . '/img_assist_' . $caller . '.js'); $output = ''."\n"; $output .= "\n"; $output .= "\n"; $output .= ''. t('Add image') ."\n"; $output .= drupal_get_js(); $output .= "\n\n"; $output .= '' . "\n"; $output .= '' . "\n"; $output .= '' . "\n"; $output .= "\n"; $output .= "\n"; echo $output; exit; } /** * Fetch the number of nodes for terms of given vocabulary ids. * * Note that this does not count nodes of subterms, as opposed to * taxonomy_term_count_nodes(). * * @param $vids * An array of taxonomy vocabulary ids. * * @return * An array keyed by term ids with the count of nodes for each term. */ function _img_assist_term_count_nodes($vids) { $count = array(); $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS count FROM {term_node} t INNER JOIN {node} n ON t.vid = n.vid INNER JOIN {term_data} td ON td.tid = t.tid WHERE n.status = 1 AND td.vid IN (' . db_placeholders($vids) . ') GROUP BY t.tid'), implode(',', $vids)); while ($term = db_fetch_object($result)) { $count[$term->tid] = $term->count; } return $count; } function img_assist_header($mode) { // Mode may be 'uploading', 'properties' or 'browse'. $output = drupal_get_form('img_assist_header_form', $mode); echo theme('img_assist_page', $output, array('id' => 'img_assist_header', 'onload' => 'parent.initHeader();', 'class' => 'img_assist')); exit; } function img_assist_header_form(&$form_state, $mode) { global $user; // Upload image. if ($mode == 'uploading') { $form[] = array('#value' => '
'); $form[] = array('#value' => ''. t('Upload: ') .''. t('Fill in the form below to upload a new image.')); $form[] = array('#value' => '
'); $form['startover'] = array( '#type' => 'button', '#value' => t('Start Over'), '#button_type' => 'button', '#attributes' => array('onclick' => 'parent.onClickStartOver();'), ); $form[] = array('#value' => '
'); } elseif ($mode == 'properties') { $form[] = array('#value' => '
'); $form[] = array('#value' => ''. t('Properties: ') .''. t('Change how the image is displayed.')); $form[] = array('#value' => '
'); $form['startover'] = array( '#type' => 'button', '#value' => t('Start Over'), '#button_type' => 'button', '#attributes' => array('onclick' => 'parent.onClickStartOver()'), ); $form[] = array('#value' => '
'); } // Browse images. else { $form[] = array('#value' => '
'); $form[] = array('#value' => ''. t('Browse Images: ') .''); $views = variable_get('img_assist_views', drupal_map_assoc(array('img_assist_browser'))); foreach ($views as $view_name => $view_title) { if ($view_name == 'img_assist_browser') { // @todo execute() performs a full query, we just need the count here. // Get my images and count. $myimages = views_get_view('img_assist_browser'); $myimages->set_arguments(array($user->uid)); $myimages->get_total_rows = TRUE; // Required for overridden default view. $myimages->execute(); $options['img_assist_browser/' . $user->uid] = t('My Images') ." ($myimages->total_rows)"; // Get all images and count. if (user_access('access all images')) { $allimages = views_get_view('img_assist_browser'); $allimages->set_arguments(array('all')); $allimages->get_total_rows = TRUE; // Required for overridden default view. $allimages->execute(); $options['img_assist_browser/all'] = t('All Images') ." ($allimages->total_rows)"; } // Get category list. if (module_exists('taxonomy') && $vocabs = variable_get('img_assist_vocabs', array())) { $term_counts = _img_assist_term_count_nodes($vocabs); // Get all images or only user's images depending on permissions. $user_arg = (user_access('access all images')) ? 'all' : $user->uid; foreach ($vocabs as $vid) { $vocab = taxonomy_vocabulary_load($vid); $terms = taxonomy_get_tree($vid); if ($terms) { foreach ($terms as $key => $value) { $tid = $value->tid; $name = $value->name; $count = (isset($term_counts[$tid]) ? $term_counts[$tid] : 0); $options[$vocab->name]["img_assist_browser/$user_arg/" . $tid] = "$name ($count)"; } } } } } else { $view = views_get_view($view_name); $view->execute(); $view_title = ($view->get_title() == '') ? $view_name : $view->get_title(); $options[$view_name] = "$view_title ($view->total_rows)"; } } $form['browse'] = array( '#type' => 'select', '#default_value' => 'img_assist_browser/' . $user->uid, '#options' => $options, '#attributes' => array('onchange' => 'parent.onChangeBrowseBy(this)'), ); if (user_access('create images')) { $form['upload'] = array( '#type' => 'button', '#prefix' => ' '. t('or') .' ', '#value' => t('Upload'), '#suffix' => ' '. t('a new image'), '#button_type' => 'button', '#attributes' => array('onclick' => 'parent.onClickUpload()'), ); } $form[] = array('#value' => '
'); $form['cancel'] = array( '#type' => 'button', '#value' => t('Cancel'), '#button_type' => 'button', '#attributes' => array('onclick' => 'parent.cancelAction()'), ); $form[] = array('#value' => '
'); } return $form; } /** * Interface for adding images. Uses the regular image node form. */ function img_assist_upload() { global $user; module_load_include('inc', 'node', 'node.pages'); if (module_exists('image') && user_access('create images')) { // On other img_assist_pages I've added the javascript using the body onload // attribute, but for this page will also need the collapse functions and // setting the body onload interferes with this. To solve this, I'm forced // use the $(document).ready call. I should probably switch all the pages to // this format to be more Drupal friendly, but at the same time I don't know // if it really matters. If a user doesn't have Javascript, she can't use // img_assist at all. $output = "\n"; // Define an empty node and fetch an image node form $node = array('uid' => $user->uid, 'name' => $user->name, 'type' => 'image'); $output .= drupal_get_form('image_node_form', $node); } else { if (!module_exists('image')) { $output = t('The image module must be enabled to use Image assist.'); } else { $output = t('Your account does not have image uploading privileges.'); } } echo theme('img_assist_page', $output, array('id' => 'img_assist_upload', 'class' => 'img_assist')); exit; } /** * Implementation of hook_form_alter(). * * Reroute submit button callback to our own handler to be able to redirect * the user after saving the node. * * @see img_assist_node_form_submit() */ function img_assist_form_alter(&$form, &$form_state, $form_id) { if ($form_id == 'image_node_form' && arg(0) == 'img_assist') { $form['buttons']['submit']['#submit'] = array('img_assist_node_form_submit'); } // If a view uses exposed filters in the image browser, we need to modify #action. elseif ($form_id == 'views_exposed_form' && arg(0) == 'img_assist') { $form['#action'] = url($_GET['q']); } } /** * Submit callback for image_node_form. */ function img_assist_node_form_submit($form, &$form_state) { // Execute regular node submit handler. node_form_submit($form, $form_state); if ($form_state['nid']) { // Send to different url. $form_state['redirect'] = 'img_assist/properties/'. $form_state['nid']; } } /** * Load the thumbnail display pane. * * Loads a View displaying the thumbnails. The view name is picked from the * third path argument and any remaining arguments are used as arguments to the * view. * Module developers may add options to img_assist_header_form using * hook_form_alter() if they wish to use custom views and/or arguments. */ function img_assist_thumbs() { global $user; if (module_exists('image') && module_exists('views')) { $view_name = ((arg(2) != '') ? arg(2) : 'img_assist_browser'); // Get view arguments from path. $args = explode('/', $_GET['q']); $args = array_slice($args, 3); // Check sanity and permissions for the 'img_assist_browser' view. if ($view_name == 'img_assist_browser') { if (empty($args[0]) || !user_access('access all images')) { $args[0] = $user->uid; } if (isset($args[1])) { $args[1] = (int) $args[1]; } } $view = views_get_view($view_name); if ($view) { $view_output = $view->execute_display(NULL, $args); if (empty($view_output)) { $output = t('No images were found. Please upload a new image or browse images by a different category.'); } else { $output = $view_output; } } else { $output = t('Error: The specified view was not found.'); } } else { $output = t('The Image and Views modules must be enabled to use Image assist.'); } echo theme('img_assist_page', $output, array('id' => 'img_assist_thumbs', 'onload' => 'parent.initThumbs();', 'class' => 'img_assist')); exit; } /** * Load the image properties pane. */ function img_assist_properties() { $nid = arg(2); // Update is put into a hidden field so the javascript can see it. $update = (arg(3)) ? 1 : 0; if (is_numeric($nid) && ($node = node_load($nid)) && $node->type == 'image' && node_access('view', $node)) { $output = drupal_get_form('img_assist_properties_form', $node, $update); } else { $output = t('Image ID not found'); } echo theme('img_assist_page', $output, array('id' => 'img_assist_properties', 'onload' => 'parent.initProperties();', 'class' => 'img_assist')); exit; } /** * Convert a node field value to text for usage in a textfield. */ function img_assist_sanitize($text) { return check_plain(trim(preg_replace("/[\r\n]+/", ' ', strip_tags($text)))); } /** * Construct the image properties form. */ function img_assist_properties_form($form_state, $node, $update) { require_once drupal_get_path('module', 'img_assist') .'/includes/img_assist.token.inc'; $image_info = image_get_info(file_create_path($node->images[IMAGE_ORIGINAL])); $image_info['aspect_ratio'] = $image_info['height'] / $image_info['width']; // Select (or generate) a preview image. $img_assist_create_derivatives = variable_get('img_assist_create_derivatives', array()); if (!empty($img_assist_create_derivatives['properties'])) { $properties_size['label'] = t('Properties'); $properties_size['key'] = 'img_assist_properties'; $properties_size['width'] = 200; $properties_size['height'] = 200; } else { $properties_size['key'] = IMAGE_THUMBNAIL; } $properties_image = img_assist_display($node, $properties_size); // Get actual image size. $properties_size = image_get_info(file_create_path($node->images[$properties_size['key']])); // Create an array of image derivative choices // // The name for each option is actually the size in pixels, not the derivative // name. This is necessary so that // - the Javascript that process this page and inserts code to your textarea // or editor will know the size to make the image placeholder (in a WYSIWYG // editor) // - the code that processes the img_assist filter tags can work with standard // sizes and custom sizes in the same way. // The WYSIWYG placeholder, however, is the most important reason to keep the // img_assist tags this way. This way users can even resize images in the // editor, and if they aren't allow to create custom sizes the filter will // pick the existing derivative that is closest to the size of the WYSIWYG // placeholder. For users not familiar with pixel sizes or names like // 'thumbnail' and 'preview', this is a nice visual way to size images. // The size selection dropdown could even be hidden using the stylesheet, // making the insertion of images even more of a visual process. And for // administrators and those with the proper permissions, images don't have to // snap to the nearest standard size. You can create any arbitrary size you // choose. $max_size = explode('x', variable_get('img_assist_max_size', '640x640')); foreach (image_get_sizes(NULL, $image_info['aspect_ratio']) as $key => $size) { // Sizes are strings, may contain '' for 0; convert to integers. settype($size['width'], 'int'); settype($size['height'], 'int'); $added_to_derivatives = FALSE; if ($key == IMAGE_ORIGINAL) { if (user_access('use original size') && $image_info['width'] <= $max_size[0] && $image_info['height'] <= $max_size[1]) { $derivatives[$image_info['width'] .'x'. $image_info['height']] = $size['label']; $added_to_derivatives = TRUE; } } elseif ($size['width'] <= $max_size[0] && $size['height'] <= $max_size[1]) { $derivatives[$size['width'] .'x'. $size['height']] = $size['label']; $added_to_derivatives = TRUE; } if (!$added_to_derivatives) { // The thumbnail option will be shown even if it is larger than the // maximum size. if ($key == IMAGE_THUMBNAIL) { $derivatives[$size['width'] .'x'. $size['height']] = $size['label']; } } } // Add a choice for 'other' if the user has the proper permission to create // custom sizes. if (!empty($img_assist_create_derivatives['custom_advanced']) && user_access('access advanced options')) { $derivatives['other'] = t('Other'); } // Use 'preview' size by default. $default_size = image_get_info(file_create_path($node->images[IMAGE_PREVIEW])); $default_width = $default_size['width']; $default_height = $default_size['height']; // Calculate the aspect ratio to keep in a hidden field // // When 'other' is chosen, the custom size will always follow the aspect ratio. // It doesn't really matter what this value is here because the actual custom // image will be created when the filter tag is processed. The size, of course, // is a bounding box. If it a user stretches an image placeholder out of // proportion in the WYSIWYG editor, the image will never be out of proportion // on the processed page. $aspect_ratio = ($default_height > 0 ? round($default_width / $default_height, 6) : 1); // Create the form. $form[] = array('#value' => '
'); $form[] = array('#value' => ''); $form[] = array('#value' => '
'); $form[] = array('#value' => $properties_image); $form[] = array('#value' => ''. check_plain($node->title) .''); // Image node properties fieldset. $form['properties'] = array('#type' => 'fieldset', '#title' => t('Image properties')); $form['properties'][] = array('#value' => '
'. t('Size') .':
'. strtr('@widthx@height px', array('@width' => $image_info['width'], '@height' => $image_info['height'])) .'
'); $rendered = node_build_content($node); foreach (array_filter(variable_get('img_assist_display_properties', array())) as $field) { if (isset($node->content[$field])) { $form['properties'][] = array('#value' => drupal_render($node->content[$field])); } } $form[] = array('#value' => '
'); $token_installed = module_exists('token'); if (variable_get('img_assist_load_title', 1)) { $title = img_assist_sanitize($token_installed ? token_replace(variable_get('img_assist_title_pattern', '[title]'), 'node', $node) : $node->title); } if (variable_get('img_assist_load_description', 1)) { $description = img_assist_sanitize($token_installed ? token_replace(variable_get('img_assist_description_pattern', '[body]'), 'node', $node) : $node->body); } $form['title'] = array( '#type' => 'textfield', '#title' => t('Title (optional)'), '#default_value' => isset($title) ? $title : '', '#size' => 50, '#maxlength' => 255, '#description' => NULL, '#attributes' => array('onblur' => 'parent.updateCaption()'), ); $form['desc'] = array( '#type' => 'textfield', '#title' => t('Description (optional)'), '#default_value' => isset($description) ? $description : '', '#size' => 50, '#maxlength' => 255, '#description' => NULL, '#attributes' => array('onblur' => 'parent.updateCaption()'), ); // Size. $form[] = array('#value' => '
'); $form[] = array('#value' => '
'); $form[] = array('#value' => ''); $form['size_label'] = array( '#type' => 'select', '#default_value' => variable_get('img_assist_default_label', '100x100'), '#options' => $derivatives, '#attributes' => array('onchange' => 'parent.onChangeSizeLabel()'), ); $form[] = array('#value' => '
'); $form['width'] = array( '#type' => 'textfield', '#default_value' => $default_width, '#size' => 4, '#maxlength' => 4, '#attributes' => array('onblur' => 'parent.onChangeWidth()'), ); $form[] = array('#value' => ' x '); $form['height'] = array( '#type' => 'textfield', '#default_value' => $default_height, '#size' => 4, '#maxlength' => 4, '#attributes' => array('onblur' => 'parent.onChangeHeight()'), ); $form[] = array('#value' => '
'); $form[] = array('#value' => '
'); // Alignment. $form['align'] = array( '#type' => 'select', '#title' => t('Alignment'), '#default_value' => variable_get('img_assist_default_alignment', 'left'), '#options' => array('left' => t('left'), 'right' => t('right'), 'none' => t('none'), 'center' => t('center')), '#prefix' => '
', '#suffix' => '
', ); $form[] = array('#value' => '
'); // Link. if (user_access('access advanced options')) { $form[] = array('#value' => ''); } else { $form['link'] = array( '#type' => 'hidden', '#value' => variable_get('img_assist_default_link_behavior', 'none'), ); $form['url'] = array( '#type' => 'hidden', '#value' => variable_get('img_assist_default_link_url', 'http://'), ); $form['link_options_visible'] = array( '#type' => 'hidden', '#value' => 0, ); } // Default link url is needed for JS to indicate if an url has been entered. $form['default_url'] = array( '#type' => 'hidden', '#value' => variable_get('img_assist_default_link_url', 'http://'), ); // Insert Mode (HTML or Filter Tag). if (user_access('access advanced options')) { $form[] = array('#value' => '
'); $form['insertmode'] = array( '#type' => 'select', '#title' => t('Insert mode'), '#default_value' => variable_get('img_assist_default_insert_mode', 'filtertag'), '#options' => array('filtertag' => t('Filter Tag'), 'html' => t('HTML Code')), ); $form[] = array('#value' => '
'); } else { $form['insertmode'] = array( '#type' => 'hidden', '#value' => variable_get('img_assist_default_insert_mode', 'filtertag'), ); } // Hidden Fields. $form['nid'] = array( '#type' => 'hidden', '#value' => $node->nid, ); $form['update'] = array( '#type' => 'hidden', '#value' => $update, ); $form['aspect'] = array( '#type' => 'hidden', '#value' => $aspect_ratio, ); // Buttons. $form['buttons'] = array( '#prefix' => '
', '#suffix' => '
', ); $form['#attributes']['onsubmit'] = 'return parent.insertImage();'; $form['buttons']['insert'] = array( '#type' => 'submit', '#value' => ($update) ? t('Update') : t('Insert'), '#attributes' => array('style' => 'float: left;'), ); $form['buttons']['cancel'] = array( '#type' => 'button', '#value' => t('Cancel'), '#button_type' => 'button', '#attributes' => array('onclick' => 'return parent.cancelAction();', 'style' => 'float: right;'), ); $form[] = array('#value' => '
'); $form['#attributes']['name'] = 'img_assist'; return $form; } function img_assist_properties_form_validate($form, &$form_state) { $html = img_assist_render_image($form_state['values']); img_assist_set_htmlcode($html); drupal_goto('img_assist/insert_html'); } /** * Store image tag or HTML in session. * * Used for saving HTML code so it can be inserted instead of the filter tags. * * @param string $htmlcode * A filter tag or HTML code. If omitted, session variable is emptied. * * @return string * A previously stored value in the user session. */ function img_assist_set_htmlcode($htmlcode = NULL) { if (isset($htmlcode)) { $_SESSION['htmlcode'] = urlencode($htmlcode); } else { $html = urldecode($_SESSION['htmlcode']); $_SESSION['htmlcode'] = ''; return $html; } } function img_assist_insert_html() { $output = drupal_get_form('img_assist_insert_html_form'); echo theme('img_assist_page', $output, array('id' => 'img_assist_insert_html', 'onload' => 'parent.insertImage();', 'class' => 'img_assist')); } function img_assist_insert_html_form() { $htmlcode = img_assist_set_htmlcode(); $form[] = array( '#id' => 'finalhtmlcode', '#type' => 'hidden', '#value' => $htmlcode, ); $form['insertmode'] = array( '#type' => 'hidden', '#value' => 'html2', ); return $form; } /** * @} End of "defgroup img_assist_pages". */ /** * @defgroup img_assist_image Image Assist Image Generation * @{ * Functions used in image.module vs. img_assist.module (simplified): * * image.module: * - image_display() * - is called for galleries, image nodes, image blocks, etc * (everytime in image is shown) * - returns * - can be passed a specific standard size only * - may call _image_build_derivatives() * - calls theme_image() to create the tag * _image_build_derivatives() * - rebuilds all standard image sizes for a particular node * * img_assist.module: (more complicated, but more flexible) * - image_display() * - is called for thumbnails browsing, inline images, etc (everytime in image is shown) * - returns * - can be passed EITHER a specific standard size only OR a custom size * - may call _image_build_derivatives() * - calls theme_image() to create the tag * _image_build_derivatives() * - rebuilds only a specfic image size (standard or custom size) */ /** * Create an IMG tag for an image. * * This is nearly identical to image_display, but * - it uses a more efficient regenerate images routine * - the size attribute can be a custom size OR a standard size */ function img_assist_display(&$node, $size = NULL, $attributes = array()) { // Custom size should include values for label, width, and height. if (is_array($size) && !empty($size['key']) && !empty($size['width']) && !empty($size['height'])) { $label = $size['key']; } // Standard size. elseif ($size) { // Size can be an array without the width and/or height. if (is_array($size)) { // Size is no longer an array. $size = $size['key']; } $label = $size; } // Assign preview size if no size specified. else { $label = IMAGE_THUMBNAIL; } // Regenerate images if necessary. $regen = FALSE; if (!isset($node->images[$label])) { $regen = TRUE; } elseif (!is_file(file_create_path($node->images[$label]))) { $regen = TRUE; } elseif (filemtime(file_create_path($node->images[$label])) < variable_get('image_updated', 0)) { $regen = TRUE; } else { // If $size is not an array, try to find the corresponding predefined size. // _image_build_derivatives() blindly assigns the *original* image file to // all derivative image sizes that are smaller than the original image size. // Without re-assigning the actual derivative size definition, img_assist // would assume that this derivative size does not exist, delete the // *original* file and subsequently fail to generate derivative images. // Also, when one predefined size has changed, the derivative sizes need to // be updated. if (!is_array($size)) { foreach (image_get_sizes() as $std_size) { if (isset($std_size['key']) && $std_size['key'] == $label) { $size = $std_size; break; } } } if (is_array($size)) { $info = image_get_info(file_create_path($node->images[$label])); if (($info['width'] != $size['width']) && ($info['height'] != $size['height'])) { $regen = TRUE; } } } if ($regen) { _img_assist_build_derivatives($node, $size); } return image_display($node, $label); } /** * Generate a image derivative * * @see _image_build_derivatives() in image.module * * @param $node * @param $size * An array containing the keys 'label', 'width', 'height'. */ function _img_assist_build_derivatives(&$node, $size = NULL) { // Verify the image module and toolkit settings. if (!_image_check_settings()) { return FALSE; } $info = image_get_info(file_create_path($node->images[IMAGE_ORIGINAL])); // Custom size. if (is_array($size) && !empty($size['key']) && !empty($size['width']) && !empty($size['height'])) { $sizes = array($size['key'] => $size); } // Standard size. elseif ($size) { // Size can be an array without the width and/or height. if (is_array($size)) { $size = $size['key']; } $sizes = image_get_sizes(); $sizes = array($size => $sizes[$size]); } // No size given: rebuild derivatives for all standard sizes. else { $sizes = image_get_sizes(); } foreach ($sizes as $key => $size) { $size['key'] = $key; _img_assist_remove($node, $size); if (is_array($size) && ($size['label']) && ($size['width']) && ($size['height'])) { if ($info['width'] > $size['width'] || $info['height'] > $size['height']) { $source = file_create_path($node->images[IMAGE_ORIGINAL]); $destination = _image_filename(basename($source), $key, FALSE); $destination_path = file_create_path($destination); if (!image_scale($source, $destination_path, $size['width'], $size['height'])) { drupal_set_message(t('Unable to create %label image', array('%label' => $size['label'])), 'error'); } else { // Set default file permissions for webserver-generated files. @chmod($destination_path, 0664); $node->images[$key] = $destination; _image_insert($node, $key, $destination_path); } } else { $node->images[$key] = $node->images[IMAGE_ORIGINAL]; } } } } function _img_assist_remove($node, $size) { $result = db_query("SELECT * FROM {files} f INNER JOIN {image} i ON f.fid = i.fid WHERE i.nid = %d AND f.filename = '%s'", $node->nid, $size['key']); while ($file = db_fetch_object($result)) { // Never delete original image. if ($file->filepath != $node->images[IMAGE_ORIGINAL]) { // Delete image file. file_delete(file_create_path($file->filepath)); // Delete file reference in database. db_query("DELETE FROM {files} WHERE fid = %d AND filename = '%s'", $file->fid, $size['key']); db_query("DELETE FROM {image} WHERE nid = %d AND fid = '%d'", $node->nid, $file->fid); } } } /** * Return image HTML. */ function img_assist_render_image($attributes = array()) { global $user; if ($attributes['nid']) { $node = node_load($attributes['nid']); // Get size. $width = $attributes['width']; $height = $attributes['height']; if ($width || $height) { // Check to ensure that the dimensions don't exceed the max set in the // img_assist settings. $max_size = explode('x', variable_get('img_assist_max_size', '640x640')); $width = ($width <= $max_size[0]) ? $width : $max_size[0]; $height = ($height <= $max_size[1]) ? $height : $max_size[1]; // Get width and height of original size. $original_size = image_get_info(file_create_path($node->images[IMAGE_ORIGINAL])); if ($width == $original_size['width'] && $height == $original_size['height']) { // Nothing to process, this is the original image size. $closest_std_size = IMAGE_ORIGINAL; $create_custom = FALSE; } else { // Get width and height of preview size. $preview_size = image_get_info(file_create_path($node->images[IMAGE_PREVIEW])); $preview_width = $preview_size['width']; $preview_height = $preview_size['height']; if ($preview_width && $preview_height) { // Get aspect ratio from preview image dimensions. $aspect_ratio = round($preview_width / $preview_height, 6); // Get new width and height for this inline image. // If height is either left out or larger than width then // width is the controlling factor. if (!$height || round($width / $aspect_ratio) <= $height) { $height = round($width / $aspect_ratio); } // Else, width is either left out or larger than height so // height is controlling factor. else { $width = round($height * $aspect_ratio); } // Compare new width and height to existing image derivative sizes. $diag_size_new = sqrt(pow($width, 2) + pow($height, 2)); $closest_difference = 9999; foreach (image_get_sizes() as $key => $stdsize) { $width_std = $stdsize['width']; $height_std = $stdsize['height']; // Get default width and height, taking the aspect ratio into account. if (round($width_std / $aspect_ratio) <= $height_std) { // Width is controlling factor. $height_std = round($width_std / $aspect_ratio); } else { // Height is controlling factor. $width_std = round($height_std * $aspect_ratio); } // Get the diagonal size of this standard image. $diag_size_std = sqrt(pow($width_std, 2) + pow($height_std, 2)); $difference = abs($diag_size_new - $diag_size_std); if ($difference < $closest_difference) { $closest_std_size = $key; $closest_difference = $difference; } } // Find out if desired width/height is the same (or extremely close) // to the size of a default image derivative; if so, we will use the // default size image instead of generating our own image. if ($closest_difference < 3) { $create_custom = FALSE; } else { $img_assist_create_derivatives = variable_get('img_assist_create_derivatives', array()); // If all users are allowed to create custom sized images. if ($img_assist_create_derivatives['custom_all']) { $create_custom = TRUE; } elseif ($img_assist_create_derivatives['custom_advanced']) { // Note: The following line is NOT the right way to do this. // The user acount passed to user_access() should be the user who // CREATED this node, not the CURRENT user. I'm not sure how to // get the user who created the node, because this function // doesn't have access to the node object. I could probably figure // out some hack, but I think I'm going to completely rethink the // 'img_assist_create_derivatives' option. When I started it this // method made sense, but the more I've worked on this, the more // confusing it gets. if (user_access('access advanced options', $user)) { $create_custom = TRUE; } else { $create_custom = TRUE; } } else { $create_custom = FALSE; } } } } if ($create_custom) { $size['label'] = t('Custom'); // Add width and height to make it possible to have multiple custom // sizes of the same image. $size['key'] = 'img_assist_custom-' . $width . 'x' . $height; $size['width'] = $width; $size['height'] = $height; } else { $size['key'] = $closest_std_size; } } // Default to thumbnail if width and/or height is missing. else { $size = image_get_sizes(); $size = $size[IMAGE_THUMBNAIL]; $size['key'] = IMAGE_THUMBNAIL; } return theme('img_assist_inline', $node, $size, $attributes); } // Legacy img_assist filter tag. elseif ($attributes['fid']) { $img = img_assist_load_image($attributes['fid'], FALSE); $image = array_shift($img); $width = $attributes['width'] ? $attributes['width'] : $image->width; $height = $attributes['height'] ? $attributes['height'] : $image->height; $src = file_create_url($image->filepath); $class = $attributes['class'] ? $attributes['class'] : 'image'; $img_template = theme('img_assist_legacy'); $img_template = strtr($img_template, array('%caption' => $attributes['caption'], '%node-link' => url('node/'. $image->nid), '%nid' => $image->nid, '%img-link' => $image->filepath, '%alt' => check_plain($attributes['alt']), '%width' => $width, '%height' => $height, '%src' => $src, '%image-class' => $class)); return $img_template; } } function img_assist_popup() { $nid = arg(2); if (is_numeric($nid) && ($node = node_load($nid)) && $node->type == 'image' && node_access('view', $node)) { drupal_set_title(check_plain($node->title)); $size = variable_get('img_assist_popup_label', IMAGE_PREVIEW); $size = array('key' => $size); $content = img_assist_display($node, $size); $attributes = array('id' => 'img_assist_popup'); echo theme('img_assist_popup', $content, $attributes); exit; } else { return drupal_access_denied(); } } /** * @} End of "defgroup img_assist_image". */ /** * @defgroup img_assist_reference Image Assist Image Referencing Routines * @{ */ /** * Update the map table * * Look for any images linked in this content and keep a reference of them. */ function img_assist_map_save($node) { $content = $node->body; // If CCK is used, image macros can be found in fields other than the body. // Get all the fields that use text filtering and extract their content: if (function_exists('content_types')) { $type = content_types($node->type); if (!empty($type['fields'])) { foreach ($type['fields'] as $field) { // Distinguish between plain text fields and filtered fields: if (!empty($field['text_processing'])) { if (count($node->{$field['field_name']})) { foreach ($node->{$field['field_name']} as $field_instance) { $content .= $field_instance['value']; } } } } } } // Get all the macros from the content: $macros = (array)img_assist_get_macros($content); // Save the image references: db_query('DELETE FROM {img_assist_map} WHERE nid = %d', $node->nid); $nids = array(); foreach ($macros as $m) { if (!isset($nids[$m['nid']]) && is_numeric($m['nid'])) { db_query('INSERT INTO {img_assist_map} (nid, iid) VALUES(%d, %d)', $node->nid, $m['nid']); $nids[$m['nid']] = $m['nid']; } } } /** * Delete references to a non-existant node. * * If a node is being deleted update the map table. The node can either be an * image node or a node containing one ore more images. Note: nodes that link * to image nodes that are deleted will still be broken. */ function img_assist_map_delete($node) { db_query('DELETE FROM {img_assist_map} WHERE nid = %d OR iid = %d', $node->nid, $node->nid); } /** * Load the image map for a given nid. */ function img_assist_map_load($nid) { $imagemap = array(); $result = db_query('SELECT * FROM {image} i INNER JOIN {img_assist_map} iam ON i.nid = iam.iid WHERE i.nid = %d', $nid); while ($data = db_fetch_object($result)) { $imagemap[] = $data->nid; } return $imagemap; } /** * Return a list of node links for a given nid. */ function img_assist_get_references($nid, $limit = 10) { $and_clause = array(); $images = img_assist_map_load($nid); foreach ($images as $id) { $and_clause[] = 'n.nid = '. $id; } $and_clause = implode(' OR ', $and_clause); if ($images) { return node_title_list(db_query_range(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n WHERE n.status = 1 AND $and_clause ORDER BY n.nid DESC"), 0, (int) $limit)); } } /** * @} End of "defgroup img_assist_reference". */ /** * @defgroup img_assist_macro Image Assist Filter macro parsing * @{ */ /** * Return all img_assist macros as an array. */ function img_assist_get_macros($text) { $m = array(); preg_match_all('/ \[ ( [^\[\]]+ )* \] /x', $text, $matches); // Don't process duplicates. $tag_match = (array) array_unique($matches[1]); foreach ($tag_match as $macro) { $current_macro = '['. $macro .']'; $param = array_map('trim', explode('|', $macro)); // The first macro param is assumed to be the function name. $func_name = array_shift($param); if ($func_name == 'img_assist') { $vars = array(); foreach ($param as $p) { $pos = strpos($p, '='); $varname = trim(substr($p, 0, $pos)); $varvalue = substr($p, $pos + 1); $vars[$varname] = trim($varvalue); } // The full unaltered filter string is the key for the array of filter // attributes. $m[$current_macro] = $vars; } } return $m; } /** * Determine if img_assist can render the current page. * @see block_list(). * * @return * TRUE if can render, FALSE if not allowed. */ function _img_assist_page_match() { $must_match = variable_get('img_assist_paths_type', 2); if ($must_match == 2) { return TRUE; } else { $paths = variable_get('img_assist_paths', "node/*\ncomment/*"); $path = drupal_get_path_alias($_GET['q']); $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\($|\|)/'), array('|', '.*', '\1'. variable_get('site_frontpage', 'node') .'\2'), preg_quote($paths, '/')) .')$/'; $match = preg_match($regexp, $path); return $match != $must_match; } } /** * Determine if img_assist can render the current textarea. * @see block_list(). * * @return * TRUE if can render, FALSE if not allowed. */ function _img_assist_textarea_match($formid) { $must_match = variable_get('img_assist_textareas_type', 2); if ($must_match == 2) { return TRUE; } else { $formids = variable_get('img_assist_textareas', "edit-body\nedit-comment"); $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/'), array('|', '.*'), preg_quote($formids, '/')) .')$/'; // Compare with the form id. $page_match = preg_match($regexp, $formid); // When $must_match has a value of 0, img_assist is displayed on // all pages except those listed in img_assist_textareas. When set to 1, it // is displayed only on those textareas listed in img_assist_textareas. $page_match = !($must_match xor $page_match); return $page_match; } } /** * @} End of "defgroup img_assist_macro". */ /** * @defgroup img_assist_theme Image Assist Theme functions * @{ * * @ingroup themeable */ function theme_img_assist_inline($node, $size, $attributes) { $caption = ''; if ($attributes['title'] && $attributes['desc']) { $caption = ''. $attributes['title'] .': '. $attributes['desc']; } elseif ($attributes['title']) { $caption = ''. $attributes['title'] .''; } elseif ($attributes['desc']) { $caption = $attributes['desc']; } // Change the node title because img_assist_display() uses the node title for // alt and title. $node->title = strip_tags($caption); $img_tag = img_assist_display($node, $size); // Always define an alignment class, even if it is 'none'. $output = ''; $link = $attributes['link']; $url = ''; // Backwards compatibility: Also parse link/url in the format link=url,foo. if (strpos($link, ',') !== FALSE) { list($link, $url) = explode(',', $link, 2); } elseif (isset($attributes['url'])) { $url = $attributes['url']; } if ($link == 'node') { $output .= l($img_tag, 'node/'. $node->nid, array('html' => TRUE)); } elseif ($link == 'popup') { $popup_size = variable_get('img_assist_popup_label', IMAGE_PREVIEW); $info = image_get_info(file_create_path($node->images[$popup_size])); $width = $info['width']; $height = $info['height']; $popup_url = file_create_url($node->images[variable_get('img_assist_popup_label', IMAGE_PREVIEW)]); $output .= l($img_tag, $popup_url, array('attributes' => array('onclick' => "launch_popup({$node->nid}, {$width}, {$height}); return false;", 'target' => '_blank'), 'html' =>TRUE)); } elseif ($link == 'url') { $output .= l($img_tag, $url, array('html' => TRUE)); } else { $output .= $img_tag; } if ($caption) { if ($attributes['align'] != 'center') { $info = image_get_info(file_create_path($node->images[$size['key']])); // Reduce the caption width slightly so the variable width of the text // doesn't ever exceed image width. $width = $info['width'] - 2; $output .= ''. $caption .''; } else { $output .= ''. $caption .''; } } $output .= ''; return $output; } function theme_img_assist_filter($text) { // The div tag added to the end of each node is necessary to clear the // floating properties of inline images immediately after a node's content. return $text .'
'; } function theme_img_assist_popup($content, $attributes = NULL) { $title = drupal_get_title(); $output = '' . "\n"; $output .= "\n"; $output .= "\n"; $output .= ''. $title ."\n"; $output .= drupal_get_html_head(); $output .= drupal_get_css(); $output .= "\n"; $output .= '\n"; $output .= "\n"; $output .= l($content, '', array('attributes' => array('onclick' => 'javascript:window.close();'), 'html' => TRUE)); $output .= "\n"; $output .= ''; $output .= ''; return $output; } function theme_img_assist_page($content, $attributes = NULL) { $title = drupal_get_title(); $output = ''."\n"; $output .= ''."\n"; $output .= "\n"; $output .= ''. $title ."\n"; // Note on CSS files from Benjamin Shell: // Stylesheets are a problem with image assist. Image assist works great as a // TinyMCE plugin, so I want it to LOOK like a TinyMCE plugin. However, it's // not always a TinyMCE plugin, so then it should like a themed Drupal page. // Advanced users will be able to customize everything, even TinyMCE, so I'm // more concerned about everyone else. TinyMCE looks great out-of-the-box so I // want image assist to look great as well. My solution to this problem is as // follows: // If this image assist window was loaded from TinyMCE, then include the // TinyMCE popups_css file (configurable with the initialization string on the // page that loaded TinyMCE). Otherwise, load drupal.css and the theme's // styles. This still leaves out sites that allow users to use the TinyMCE // plugin AND the Add Image link (visibility of this link is now a setting). // However, on my site I turned off the text link since I use TinyMCE. I think // it would confuse users to have an Add Images link AND a button on the // TinyMCE toolbar. // // Note that in both cases the img_assist.css file is loaded last. This // provides a way to make style changes to img_assist independently of how it // was loaded. $output .= drupal_get_html_head(); $output .= drupal_get_js(); $output .= "\n\n"; // Ensure that img_assist.js is imported last. $path = drupal_get_path('module', 'img_assist') .'/img_assist_popup.css'; $output .= "\n"; $output .= "\n"; $output .= '\n"; $output .= theme_status_messages(); $output .= "\n"; $output .= $content; $output .= "\n"; $output .= ''; $output .= ''; return $output; } /** * @} End of "defgroup img_assist_theme". */ /** * Implementation of hook_wysiwyg_plugin(). */ function img_assist_wysiwyg_plugin($editor, $version) { switch ($editor) { case 'tinymce': if ($version > 3) { return array( 'img_assist' => array( 'path' => drupal_get_path('module', 'img_assist') .'/drupalimage/editor_plugin.js', 'buttons' => array('img_assist' => t('Image Assist')), 'url' => 'http://drupal.org/project/img_assist', 'extended_valid_elements' => array('img[class|src|border=0|alt|title|width|height|align|name|style]'), 'load' => TRUE, ), ); } break; } } /** * Implementation of hook_views_api(). */ function img_assist_views_api() { return array( 'api' => 2, 'path' => drupal_get_path('module', 'img_assist') .'/includes', ); } /** * @defgroup img_assist_legacy Image Assist Legacy functions * @{ * Used for backwards compatibility with original img_assist module. */ /** * Load all images into a static array. */ function img_assist_load_images($tid = NULL, $uid = NULL) { static $image; if ($tid) { foreach ($tid as $key => $term) { if ($term == 0) { unset($tid[$key]); } } $image = NULL; } $where = ''; if ($uid > 0) { $image = NULL; $where = 'AND n.uid = '. db_escape_string($uid); } if (!$image) { $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, r.teaser, i.*, f.* FROM {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid INNER JOIN {image} i ON n.nid = i.nid AND n.type = 'image' INNER JOIN {files} f ON f.fid = i.fid ". $where ." ORDER BY n.changed DESC")); while ($node = db_fetch_object($result)) { $node->filepath = file_create_path($node->filepath); $dim = getimagesize($node->filepath, $info); $node->width = $dim[0]; $node->height = $dim[1]; $image[$node->nid][$node->filename] = $node; if ($tid) { $tid2 = array(); foreach (taxonomy_node_get_terms($node) as $term) { $tid2[] = $term->tid; } if (array_intersect($tid, $tid2) == $tid) { $img[$node->nid][$node->filename] = $node; } } } $image = ($tid) ? $img : $image; // Note: If we didn't use "LIKE 'image/%%'" here we could load other files. // Might be interesting to expand on this someday. if ($image) { $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, r.teaser, i.*, f.* FROM {image} i, {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid INNER JOIN {files} f ON f.fid = i.fid WHERE i.nid = n.nid AND f.filemime LIKE 'image/%%' AND n.nid NOT IN (". implode(array_keys($image), ', ') .") ". $where ." ORDER BY n.changed DESC")); while ($node = db_fetch_object($result)) { $node->filepath = file_create_path($node->filepath); $dim = getimagesize($node->filepath, $info); $node->width = $dim[0]; $node->height = $dim[1]; $image[$node->nid][IMAGE_THUMBNAIL] = $node; $image[$node->nid][IMAGE_ORIGINAL] = $node; if ($tid) { $tid2 = array(); foreach (taxonomy_node_get_terms($node) as $term) { $tid2[] = $term->tid; } if (array_intersect($tid, $tid2) == $tid) { $img[$node->nid][IMAGE_THUMBNAIL] = $node; $img[$node->nid][IMAGE_ORIGINAL] = $node; } } } $image = ($tid) ? $img : $image; } } return $image; } /** * Load an image from the database. */ function img_assist_load_image($id, $derivatives = TRUE) { $node = db_fetch_object(db_query(db_rewrite_sql('SELECT n.nid, n.title, i.*, f.* FROM {image} i, {node} n INNER JOIN {files} f ON f.fid = i.fid WHERE f.nid = n.nid AND f.fid = %d'), $id)); $node->filepath = file_create_path($node->filepath); if (!$derivatives) { $dim = getimagesize($node->filepath, $info); $node->width = $dim[0]; $node->height = $dim[1]; $image[$node->filename] = $node; } else { $image_module_image = FALSE; if (function_exists('image_get_sizes')) { foreach (image_get_sizes() as $size) { if ($size['label'] == $node->filename) { $image_module_image = TRUE; $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, r.teaser, i.*, f.* FROM {image} i, {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid INNER JOIN {files} f ON f.fid = i.fid WHERE i.nid = n.nid AND n.nid = %d'), $node->nid); while ($node = db_fetch_object($result)) { $node->filepath = file_create_path($node->filepath); $dim = getimagesize($node->filepath, $info); $node->width = $dim[0]; $node->height = $dim[1]; $image[$node->filename] = $node; } break; } } } if (!$image_module_image) { $dim = getimagesize($node->filepath, $info); $node->width = $dim[0]; $node->height = $dim[1]; $image[IMAGE_THUMBNAIL] = $node; $image[IMAGE_ORIGINAL] = $node; } } return $image; } /** * Attach the thumbnail metadata to the image object. * * Unfortunately we have to query the database since the thumbnail can be named * something entirely different from the original image. */ function _img_assist_get_thumbnail(&$image) { static $thumbs = array(); if ($thumbs[$image->nid] === NULL) { $thumbpath = file_create_path(db_result(db_query("SELECT f.filepath FROM {image} i INNER JOIN {files} f ON f.fid = i.fid WHERE i.nid = %d AND f.filename = '%s'", $image->nid, IMAGE_THUMBNAIL))); // In old versions of image.module thumbs were named 'thumb_filename.ext'. if (!file_exists($thumbpath)) { $pos = strrpos($image->filepath, '/') + 1; $thumbpath = file_create_path(substr($image->filepath, 0, $pos) .'thumb_'. substr($image->filepath, $pos)); } $img->thumbpath = is_file($thumbpath) && preg_match('|^'. variable_get('file_directory_path', 'files') .'\/'. variable_get('image_default_path', 'images') .'\/|', $image->filepath) ? $thumbpath : $image->filepath; $dim = getimagesize($img->thumbpath, $info); $img->thumbwidth = $dim[0]; $img->thumbheight = $dim[1]; $thumbs[$image->nid] = $img; } if ($thumbs[$image->nid]) { foreach ($thumbs[$image->nid] as $key => $value) { $image->$key = $value; } } } function theme_img_assist_legacy() { return '
%alt
%caption
'; } /** * @} End of "defgroup img_assist_legacy". */