img_assist.module in Image Assist 5
Same filename and directory in other branches
Image Assist module
Implements a javascript-driven user interface to upload images to a Drupal site and select a previously uploaded image for displaying inline in a content.
File
img_assist.moduleView source
<?php
/**
* @file
* Image Assist module
*
* Implements a javascript-driven user interface to upload images to a Drupal
* site and select a previously uploaded image for displaying inline in a
* content.
*/
/**
* Implementation of hook_help().
*/
function img_assist_help($section) {
switch ($section) {
case 'admin/settings/img_assist':
return t('If this site was moved or is planned to move to another domain or sub-directory, it might be needed to <a href="!empty-cache">empty the filter cache</a> 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 '<div class="%image-class"><a href="%link">%image</a><div class="caption">%caption</div></div>';
}
}
/**
* Implementation of hook_menu().
*/
function img_assist_menu($may_cache) {
$items = array();
if ($may_cache) {
$admin_access = user_access('administer site configuration');
$ia_access = user_access('access img_assist');
$items[] = array(
'path' => 'img_assist/cache/clear',
'title' => t('Empty cache'),
'callback' => 'img_assist_cache_clear',
'access' => $admin_access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'img_assist/load',
'title' => t('Image Assist'),
'callback' => 'img_assist_loader',
'access' => $ia_access,
'type' => MENU_CALLBACK,
);
// Page callbacks called internally by img_assist/load.
$items[] = array(
'path' => 'img_assist/header',
'title' => t('Image Assist Header'),
'callback' => 'img_assist_header',
'access' => $ia_access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'img_assist/thumbs',
'title' => t('Image Assist Thumbnails'),
'callback' => 'img_assist_thumbs',
'access' => $ia_access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'img_assist/upload',
'title' => t('Image Assist Upload'),
'callback' => 'img_assist_upload',
'access' => $ia_access,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'img_assist/properties',
'title' => t('Image Assist Properties'),
'callback' => 'img_assist_properties',
'access' => $ia_access,
'type' => MENU_CALLBACK,
);
// Popup images page.
$items[] = array(
'path' => 'img_assist/popup',
'title' => t('Popup Image'),
'callback' => 'img_assist_popup',
'access' => user_access('access content'),
'type' => MENU_CALLBACK,
);
// Insert callback (only for inserting HTML, not filter tag).
$items[] = array(
'path' => 'img_assist/insert_html',
'title' => t('Insert Callback'),
'access' => $ia_access,
'type' => MENU_CALLBACK,
'callback' => 'img_assist_insert_html',
);
$items[] = array(
'path' => 'admin/settings/img_assist',
'title' => t('Image assist'),
'description' => t('Change settings for the Image assist module.'),
'callback' => 'drupal_get_form',
'callback arguments' => 'img_assist_admin_settings',
'access' => $admin_access,
);
}
else {
$path = drupal_get_path('module', 'img_assist');
if (variable_get('img_assist_page_styling', 'yes') == 'yes') {
drupal_add_css($path . '/img_assist.css');
}
// Assign base_path to insert in image source by javascript.
drupal_add_js('var BASE_URL = "' . base_path() . '";', 'inline');
drupal_add_js($path . '/img_assist.js');
}
return $items;
}
/**
* 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' => array(
'img_assist_textarea' => array(),
),
);
return $type;
}
/**
* Add image link underneath textareas.
*/
function img_assist_textarea($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 (user_access('access img_assist')) {
$output = theme('img_assist_textarea_link', $element, $link);
$element['#suffix'] = isset($element['#suffix']) ? $element['#suffix'] . $output : $output;
}
}
}
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() {
// 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' => '<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', 1),
'#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.'),
);
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 settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['image']['img_assist_preview_count'] = array(
'#type' => 'textfield',
'#title' => t('Maximum number of thumbnails per page'),
'#default_value' => variable_get('img_assist_preview_count', 8),
'#size' => 6,
'#maxlength' => 6,
'#description' => t('Enter the number of images to display in the thumbnail browser. If there are more images, next and previous links will be displayed.'),
);
$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 ? '<br /><strong>' . 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).') . '</strong>' : '';
$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(
'properties',
'custom_all',
'custom_advanced',
)),
'#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('Other Properties'),
'#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. <strong>Warning:</strong> 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('Preload image 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.'),
);
$form['properties']['img_assist_load_description'] = array(
'#type' => 'radios',
'#title' => t('Preload image description'),
'#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.'),
);
// Image display settings.
$form['display'] = array(
'#type' => 'fieldset',
'#title' => t('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_id, $form_values) {
// img_assist_max_size must contain a value for width and height.
if (!preg_match('/\\d+x\\d+/', $form_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.
*
* @todo Remove usage of global variable.
*/
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);
// Store nid globally if this node is an image uploaded with img_assist.
if ($node->type == 'image' && arg(0) == 'img_assist') {
global $_img_assist_saved_image;
$_img_assist_saved_image = $node->nid;
}
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() {
$editor = arg(2) ? arg(2) : 'textarea';
$output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">' . "\n";
$output .= "<html>\n";
$output .= "<head>\n";
$output .= '<title>' . t('Add image') . "</title>\n";
$output .= "\n<script type=\"text/javascript\"><!--\n";
$output .= ' var BASE_URL = "' . base_path() . '";' . "\n";
$output .= "--></script>\n";
$path = drupal_get_path('module', 'img_assist');
$output .= '<script type="text/javascript" src="' . base_path() . $path . '/img_assist.js"></script>' . "\n";
if ($editor == 'tinymce') {
$tinymce_path = drupal_get_path('module', 'tinymce');
$tinymce_js = base_path() . $tinymce_path . '/tinymce/jscripts/tiny_mce/tiny_mce_popup.js';
$output .= '<script type="text/javascript" src="' . $tinymce_js . '"></script>' . "\n";
}
$editor_js = base_path() . $path . '/img_assist_' . $editor . '.js';
$output .= '<script type="text/javascript" src="' . $editor_js . '"></script>' . "\n";
$output .= "</head>\n\n";
$output .= '<frameset rows="38, *" onload="initLoader()" frameborder="0" border="0" framespacing="0">' . "\n";
$output .= '<frame name="img_assist_header" src="" class="img_assist_header" noresize="noresize" />' . "\n";
$output .= '<frame name="img_assist_main" src="" class="img_assist_main" noresize="noresize" />' . "\n";
$output .= "</frameset>\n";
$output .= "</html>\n";
echo $output;
}
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',
));
}
function img_assist_header_form($mode) {
global $user;
// Upload image.
if ($mode == 'uploading') {
$form[] = array(
'#value' => '<div id="header-uploading">',
);
$form[] = array(
'#value' => '<strong>' . t('Upload: ') . '</strong>' . t('Fill in the form below to upload a new image.'),
);
$form[] = array(
'#value' => '</div><div id="header-startover">',
);
$form['startover'] = array(
'#type' => 'button',
'#value' => t('Start Over'),
'#button_type' => 'button',
'#attributes' => array(
'onclick' => 'parent.onClickStartOver();',
),
);
$form[] = array(
'#value' => '</div>',
);
}
elseif ($mode == 'properties') {
$form[] = array(
'#value' => '<div id="header-properties">',
);
$form[] = array(
'#value' => '<strong>' . t('Properties: ') . '</strong>' . t('Change how the image is displayed.'),
);
$form[] = array(
'#value' => '</div><div id="header-startover">',
);
$form['startover'] = array(
'#type' => 'button',
'#value' => t('Start Over'),
'#button_type' => 'button',
'#attributes' => array(
'onclick' => 'parent.onClickStartOver()',
),
);
$form[] = array(
'#value' => '</div>',
);
}
else {
$form[] = array(
'#value' => '<div id="header-browse">',
);
$form[] = array(
'#value' => '<strong>' . t('Browse Images: ') . '</strong>',
);
// Get my images and count.
$result = db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.type='image' AND n.uid= %d", $user->uid);
$count = $result ? db_result($result, 0) : 0;
$options['myimages'] = t('My Images') . " ({$count})";
// Get all images and count.
// Count all published images and the user's unpublished images.
if (user_access('access all images')) {
$result = db_query("SELECT COUNT(n.nid) FROM {node} n WHERE n.type='image' AND (n.uid = %d OR n.status = 1)", $user->uid);
$count = $result ? db_result($result, 0) : 0;
$options['allimages'] = t('All Images') . " ({$count})";
}
// Get category list.
if (module_exists('taxonomy')) {
$vocabs = (array) variable_get('img_assist_vocabs', array());
foreach ($vocabs as $vid) {
$vocab = taxonomy_get_vocabulary($vid);
$terms = taxonomy_get_tree($vid);
if ($terms) {
foreach ($terms as $key => $value) {
$tid = $value->tid;
$name = $value->name;
// For this term, count all published images and the user's
// unpublished images.
if (user_access('access all images')) {
$result = db_query("SELECT COUNT(n.nid) FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND (n.uid = %d OR n.status = 1)", $tid, $user->uid);
}
else {
$result = db_query("SELECT COUNT(n.nid) FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND n.uid = %d", $tid, $user->uid);
}
$count = $result ? db_result($result, 0) : 0;
if ($count) {
$options[$vocab->name][$tid] = $name . " ({$count})";
}
}
}
}
}
$form['browse'] = array(
'#type' => 'select',
'#default_value' => variable_get('feed_item_length', 'teaser'),
'#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' => '</div><div id="header-cancel">',
);
$form['cancel'] = array(
'#type' => 'button',
'#value' => t('Cancel'),
'#button_type' => 'button',
'#attributes' => array(
'onclick' => 'parent.cancelAction()',
),
);
$form[] = array(
'#value' => '</div>',
);
}
return $form;
}
/**
* Interface for adding images. Uses the regular image node form.
*/
function img_assist_upload() {
global $user;
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 = "<script type=\"text/javascript\"><!-- \n";
$output .= " if (Drupal.jsEnabled) { \n";
$output .= " \$(document).ready(parent.initUpload);\n";
$output .= " } \n";
$output .= "--></script>\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',
));
}
/**
* Implementation of hook_form_alter().
*
* Add a submit callback to image_node_form which alters the redirect.
*/
function img_assist_form_alter($form_id, &$form) {
if ($form_id == 'image_node_form' && arg(0) == 'img_assist') {
if (!is_array($form['#submit'])) {
$form['#submit'] = array();
}
$form['#submit'] += array(
'img_assist_node_form_submit' => array(),
);
}
}
/**
* Submit callback for image_node_form.
*
* Change the redirect from node/$nid to img_assist/properties/$nid.
*/
function img_assist_node_form_submit($form_id, $form_values) {
// Get the nid of the newly created image (caught by img_assist_nodeapi).
global $_img_assist_saved_image;
drupal_goto('img_assist/properties/' . $_img_assist_saved_image);
}
/**
* Load the thumbnail display pane.
*
* Grabs all images from image.module and loads the thumbnails.
*/
function img_assist_thumbs() {
global $user;
if (module_exists('image')) {
$browse = arg(2);
if ($browse == 'myimages') {
$myimagesonly = TRUE;
$tid = 0;
}
elseif ($browse == 'allimages') {
$myimagesonly = FALSE;
$tid = 0;
}
else {
$myimagesonly = FALSE;
$tid = $browse;
}
$output = '<div align="center">';
// Show by term id.
if ($tid) {
// For this term, show all published images and the user's unpublished images.
if (user_access('access all images')) {
$query = "SELECT n.nid FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND (n.uid = %d OR n.status = 1) ORDER BY n.sticky DESC, n.created DESC";
$params = array(
$tid,
$user->uid,
);
}
else {
$query = "SELECT n.nid FROM {node} n, {term_node} t WHERE t.nid=n.nid AND n.type='image' AND t.tid = %d AND n.uid = %d ORDER BY n.sticky DESC, n.created DESC";
$params = array(
$tid,
$user->uid,
);
}
}
else {
// Show all published images and the user's unpublished images.
if (user_access('access all images') && !$myimagesonly) {
$query = "SELECT n.nid FROM {node} n WHERE n.type='image' AND (n.uid = %d OR n.status = 1) ORDER BY n.sticky DESC, n.created DESC";
$params = array(
$user->uid,
);
}
else {
$query = "SELECT n.nid FROM {node} n WHERE n.type='image' AND n.uid= %d ORDER BY n.sticky DESC, n.created DESC";
$params = array(
$user->uid,
);
}
}
$show_amount = variable_get('img_assist_preview_count', 10);
$result = pager_query($query, $show_amount, $element = 0, $count_query = NULL, $params);
while ($row = db_fetch_object($result)) {
$node = node_load(array(
'nid' => $row->nid,
));
$image = img_assist_display($node, IMAGE_THUMBNAIL);
$output .= l($image, 'img_assist/properties/' . $node->nid, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = TRUE) . "\n";
}
if (!db_num_rows($result)) {
$output .= t('No images were found. Please upload a new image or browse images by a different category.');
}
$output .= theme('pager', NULL, $show_amount);
$output .= '</div>';
}
else {
$output = t('The image module must be enabled to use Image assist.');
}
echo theme('img_assist_page', $output, array(
'id' => 'img_assist_thumbs',
'onload' => 'parent.initThumbs();',
'class' => 'img_assist',
));
}
/**
* 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)) {
// Setup a default caption & description.
$node->title = str_replace("\r", ' ', strip_tags($node->title));
$node->title = str_replace("\n", ' ', trim($node->title));
$node->body = str_replace("\r", ' ', strip_tags($node->body));
$node->body = str_replace("\n", ' ', trim($node->body));
$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',
));
}
/**
* Construct the image properties form.
*/
function img_assist_properties_form($node, $update) {
$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 ($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 ($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' => '<div id="properties">',
);
$form[] = array(
'#value' => '<table width="100%" border="0" cellspacing="0" cellpadding="0">',
);
$form[] = array(
'#value' => '<tr><td valign="top" rowspan="3" id="preview">',
);
$form[] = array(
'#value' => $properties_image,
);
$form[] = array(
'#value' => '<span id="caption" style="width: ' . $properties_size['width'] . 'px;">' . check_plain($node->title) . '</span>',
);
$form[] = array(
'#value' => '</td><td width="100%" colspan="2">',
);
$form['title'] = array(
'#type' => 'textfield',
'#title' => t('Title (optional)'),
'#default_value' => variable_get('img_assist_load_title', 1) ? $node->title : '',
'#size' => 50,
'#maxlength' => 255,
'#description' => NULL,
'#attributes' => array(
'onblur' => 'parent.updateCaption()',
),
);
$form['desc'] = array(
'#type' => 'textfield',
'#title' => t('Description (optional)'),
'#default_value' => variable_get('img_assist_load_description', 1) ? $node->body : '',
'#size' => 50,
'#maxlength' => 255,
'#description' => NULL,
'#attributes' => array(
'onblur' => 'parent.updateCaption()',
),
);
// Size.
$form[] = array(
'#value' => '</td></tr><tr><td width="90%">',
);
$form[] = array(
'#value' => '<div class="form-item" id="edit-size">',
);
$form[] = array(
'#value' => '<label for="edit-size-label">' . t('Size: (orig @widthx@height, max @maxsize)', array(
'@width' => $image_info['width'],
'@height' => $image_info['height'],
'@maxsize' => variable_get('img_assist_max_size', '640x640'),
)) . '</label>',
);
$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' => '<div class="form-item" id="size-other">',
);
$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' => '</div></div>',
);
$form[] = array(
'#value' => '</td><td>',
);
// 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' => '<div id="alignment">',
'#suffix' => '</div>',
);
$form[] = array(
'#value' => '</td></tr><tr><td colspan="2">',
);
// Link.
if (user_access('access advanced options')) {
$form[] = array(
'#value' => '<div class="form-item" id="link-group">',
);
$form['link'] = array(
'#type' => 'select',
'#title' => t('Link'),
'#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'),
),
'#attributes' => array(
'onchange' => 'parent.onChangeLink()',
),
);
$form['url'] = array(
'#type' => 'textfield',
'#default_value' => variable_get('img_assist_default_link_url', 'http://'),
'#size' => 25,
'#maxlength' => 255,
'#description' => NULL,
);
$form['link_options_visible'] = array(
'#type' => 'hidden',
'#value' => 1,
);
$form[] = array(
'#value' => '</div>',
);
}
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' => '<div id="insertmode">',
);
$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' => '</div>',
);
}
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[] = array(
'#value' => '<div id="buttons">',
);
$form['insert'] = array(
'#type' => 'submit',
'#value' => $update ? t('Update') : t('Insert'),
'#attributes' => array(
'onclick' => 'parent.insertImage()',
'style' => 'float: left;',
),
);
$form['cancel'] = array(
'#type' => 'button',
'#value' => t('Cancel'),
'#button_type' => 'button',
'#attributes' => array(
'onclick' => 'parent.cancelAction()',
'style' => 'float: right;',
),
);
$form[] = array(
'#value' => '</div>',
);
$form[] = array(
'#value' => '</td></tr></table></div>',
);
$form['#attributes'] = array(
'name' => 'img_assist',
);
return $form;
}
function img_assist_properties_form_validate($form_id, $form_values) {
$html = img_assist_render_image($form_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 <span ...><img ...></span>
* - can be passed a specific standard size only
* - may call _image_build_derivatives()
* - calls theme_image() to create the <img> 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 <span ...><img ...></span>
* - can be passed EITHER a specific standard size only OR a custom size
* - may call _image_build_derivatives()
* - calls theme_image() to create the <img> 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'];
}
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;
}
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);
}
if (empty($node->images[$label])) {
return;
}
// Get actual size ($size is just a bounding box).
$info = image_get_info(file_create_path($node->images[$label]));
$attributes['class'] = 'image image-' . $label . (isset($attributes['class']) ? ' ' . $attributes['class'] : '');
$attributes['width'] = $info['width'];
$attributes['height'] = $info['height'];
return theme('image_display', $node, $label, file_create_url($node->images[$label]), $attributes);
}
/**
* 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,
);
}
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],
);
}
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} WHERE nid = %d AND 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 nid = %d AND filename = '%s'", $node->nid, $size['key']);
}
}
}
/**
* 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 = 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) {
// Try to get this page's nid to add to this custom image's derivative
// label; otherwise you can't really have the same image inline in more
// than one node at different custom sizes.
$page_nid = is_numeric(arg(2)) ? '_' . arg(2) : '';
$size['label'] = t('Custom');
$size['key'] = 'img_assist_custom';
$size['width'] = $width;
$size['height'] = $height;
}
else {
$size['key'] = $closest_std_size;
}
}
else {
$size = image_get_sizes();
$size = $size[IMAGE_THUMBNAIL];
$size['key'] = IMAGE_THUMBNAIL;
}
return theme('img_assist_inline', $node, $size, $attributes);
}
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);
}
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 {files} f INNER JOIN {img_assist_map} i ON f.nid = i.iid WHERE f.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)/',
'/\\\\\\*/',
'/(^|\\|)\\\\<front\\\\>($|\\|)/',
), 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
*/
/**
* Render a link text or button (underneath textareas).
*/
function theme_img_assist_textarea_link($element, $link) {
$output = '<div class="img_assist-button">';
if ($link == 'icon') {
$link = theme('image', drupal_get_path('module', 'img_assist') . '/add-image.jpg', t('Add image'));
}
else {
$link = t('Add image');
}
$attribs = array(
'class' => 'img_assist-link',
'id' => 'img_assist-link-' . $element['#id'],
'title' => t('Click here to add images'),
'onclick' => 'window.open(this.href, \'img_assist_link\', \'width=600,height=350,scrollbars=yes,status=yes,resizable=yes,toolbar=no,menubar=no\'); return false;',
);
$output .= l($link, 'img_assist/load/textarea', $attribs, 'textarea=' . $element['#name'], NULL, FALSE, TRUE);
$output .= '</div>';
return $output;
}
function theme_img_assist_inline($node, $size, $attributes) {
if ($attributes['title'] && $attributes['desc']) {
$caption = '<strong>' . $attributes['title'] . ': </strong>' . $attributes['desc'];
}
elseif ($attributes['title']) {
$caption = '<strong>' . $attributes['title'] . '</strong>';
}
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 = '<span class="inline inline-' . $attributes['align'] . '">';
$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(), NULL, NULL, FALSE, 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(
'onclick' => "launch_popup({$node->nid}, {$width}, {$height}); return false;",
'target' => '_blank',
), NULL, NULL, FALSE, TRUE);
}
elseif ($link == 'url') {
$output .= l($img_tag, $url, array(), NULL, NULL, FALSE, 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 .= '<span class="caption" style="width: ' . $width . 'px;">' . $caption . '</span>';
}
else {
$output .= '<span class="caption">' . $caption . '</span>';
}
}
$output .= '</span>';
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 . '<div class="image-clear"></div>';
}
function theme_img_assist_popup($content, $attributes = NULL) {
$title = drupal_get_title();
$output = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' . "\n";
$output .= "<html>\n";
$output .= "<head>\n";
$output .= '<title>' . $title . "</title>\n";
$output .= drupal_get_html_head();
$output .= drupal_get_css();
$output .= "</head>\n";
$output .= '<body' . drupal_attributes($attributes) . ">\n";
$output .= "<!-- begin content -->\n";
$output .= l($content, '', array(
'onclick' => 'javascript:window.close();',
), NULL, NULL, FALSE, TRUE);
$output .= "<!-- end content -->\n";
$output .= '</body>';
$output .= '</html>';
return $output;
}
function theme_img_assist_page($content, $attributes = NULL) {
$title = drupal_get_title();
$output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
$output .= '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">' . "\n";
$output .= "<head>\n";
$output .= '<title>' . $title . "</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<script type=\"text/javascript\"><!-- \n";
$output .= " if (parent.tinyMCE) {\n";
$output .= " document.write('<link href=\"' + parent.tinyMCE.getParam(\"popups_css\") + '\" rel=\"stylesheet\" type=\"text/css\">');\n";
$output .= " } else {\n";
foreach (drupal_add_css() as $media => $type) {
$paths = array_merge($type['module'], $type['theme']);
foreach (array_keys($paths) as $path) {
// Don't import img_assist.css twice.
if (!strstr($path, 'img_assist.css')) {
$output .= " document.write('<style type=\"text/css\" media=\"{$media}\">@import \"" . base_path() . $path . "\";<\\/style>');\n";
}
}
}
$output .= " }\n";
$output .= "--></script>\n";
// Ensure that img_assist.js is imported last.
$path = drupal_get_path('module', 'img_assist') . '/img_assist.css';
$output .= "<style type=\"text/css\" media=\"all\">@import \"" . base_path() . $path . "\";</style>\n";
$output .= "</head>\n";
$output .= '<body' . drupal_attributes($attributes) . ">\n";
$output .= theme_status_messages();
$output .= "<!-- begin content -->\n";
$output .= $content;
$output .= "<!-- end content -->\n";
$output .= '</body>';
$output .= '</html>';
return $output;
}
/**
* @} End of "defgroup img_assist_theme".
*/
/**
* @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, f.* FROM {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid INNER JOIN {files} f ON n.nid = f.nid AND n.type = '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][$node->filename] = $node;
if ($tid) {
$tid2 = array();
foreach (taxonomy_node_get_terms($node->nid) 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, f.* FROM {files} f, {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid WHERE f.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->nid) 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, f.* FROM {files} f, {node} n 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, f.* FROM {files} f, {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = n.nid WHERE f.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 filepath FROM {files} WHERE nid = %d AND 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 '<div class="%image-class"><a href="%node-link"><img src="%src" width="%width" height="%height" alt="%alt" /></a><div class="caption">%caption</div></div>';
}
/**
* @} End of "defgroup img_assist_legacy".
*/
Functions
Name | Description |
---|---|
img_assist_admin_settings | Implementation of hook_settings(). |
img_assist_admin_settings_validate | Validate Image Assist settings. |
img_assist_block | Implementation of hook_block(). |
img_assist_cache_clear | Menu callback; clears relevant caches, then redirects to the previous page. |
img_assist_display | Create an IMG tag for an image. |
img_assist_elements | Implementation of hook_elements(). |
img_assist_filter | Implementation of hook_filter(). |
img_assist_filter_tips | Implementation of hook_filter_tips(). |
img_assist_form_alter | Implementation of hook_form_alter(). |
img_assist_get_macros | Return all img_assist macros as an array. |
img_assist_get_references | Return a list of node links for a given nid. |
img_assist_header | |
img_assist_header_form | |
img_assist_help | Implementation of hook_help(). |
img_assist_insert_html | |
img_assist_insert_html_form | |
img_assist_loader | Output main img_assist interface HTML. |
img_assist_load_image | Load an image from the database. |
img_assist_load_images | Load all images into a static array. |
img_assist_map_delete | Delete references to a non-existant node. |
img_assist_map_load | Load the image map for a given nid. |
img_assist_map_save | Update the map table |
img_assist_menu | Implementation of hook_menu(). |
img_assist_nodeapi | Implementation of hook_nodeapi(). |
img_assist_node_form_submit | Submit callback for image_node_form. |
img_assist_perm | Implementation of hook_perm(). |
img_assist_popup | |
img_assist_properties | Load the image properties pane. |
img_assist_properties_form | Construct the image properties form. |
img_assist_properties_form_validate | |
img_assist_render_image | Return image HTML. |
img_assist_set_htmlcode | Store image tag or HTML in session. |
img_assist_textarea | Add image link underneath textareas. |
img_assist_thumbs | Load the thumbnail display pane. |
img_assist_upload | Interface for adding images. Uses the regular image node form. |
theme_img_assist_filter | |
theme_img_assist_inline | |
theme_img_assist_legacy | |
theme_img_assist_page | |
theme_img_assist_popup | |
theme_img_assist_textarea_link | Render a link text or button (underneath textareas). |
_img_assist_build_derivatives | Generate a image derivative |
_img_assist_get_thumbnail | Attach the thumbnail metadata to the image object. |
_img_assist_page_match | Determine if img_assist can render the current page. |
_img_assist_remove | |
_img_assist_textarea_match | Determine if img_assist can render the current textarea. |