You are here

media_browser_plus.module in Media Browser Plus 7

Same filename and directory in other branches
  1. 7.3 media_browser_plus.module
  2. 7.2 media_browser_plus.module

Adds fields to the media browser forms for better UX

File

media_browser_plus.module
View source
<?php

/**
 * @file
 * Adds fields to the media browser forms for better UX
 */

/** ***************************************** */

/** INCLUDES                                  */

/** ***************************************** */

// A registry of variable_get defaults.
require_once dirname(__FILE__) . '/includes/media_browser_plus.variables.inc';

/**
 * Alter the media browser from to enable new UI
 */
function media_browser_plus_form_media_admin_alter(&$form, &$form_state) {
  $path = drupal_get_path('module', 'media_browser_plus');

  // Add css for both views.
  $form['#attached']['library'][] = array(
    'media_browser_plus',
    'media_browser_plus',
  );
  $form['#attached']['library'][] = array(
    'media_browser_plus',
    'colorbox',
  );

  // Set base href for javascript requests.
  $settings = media_browser_plus_main_view_javascript_settings();
  $form['#attached']['js'][] = array(
    'type' => 'setting',
    'data' => $settings,
  );

  // Check which mode we are in.
  if (isset($form_state['build_info']['args'][0]) && $form_state['build_info']['args'][0] != 'thumbnails') {
    return _media_browser_plus_media_admin_list_alter($form, $form_state);
  }

  // Check access rights.
  if (!media_browser_plus_access('media grid view')) {
    drupal_access_denied();
    return array();
  }

  // Adding grid view js and css.
  $form['#attached']['js'][] = $path . '/js/media_browser_plus.admin.js';
  drupal_add_library('system', 'ui.draggable');
  drupal_add_library('system', 'ui.droppable');

  // Removing options form part.
  unset($form['options']);
  if (!media_browser_plus_access('media list view') || !media_browser_plus_access('media grid view')) {
    unset($form['switch']);
  }
  $form['admin'] = media_browser_plus_grid_view_form();
  $form['media-basket'] = media_browser_plus_media_basket_form();
  if (media_access('preview')) {
    $form['media-preview'] = media_browser_plus_media_preview_form();
  }
  return $form;
}

/**
 * Enter description here
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_media_admin_validate($form, &$form_state) {

  // Copy input files to values.
  if ($form_state['values']['op'] != 'Download') {
    $form_state['values']['files'] = array();
    if (!empty($form_state['input']['files'])) {
      $form_state['values']['files'] = $form_state['input']['files'];
    }

    // Call the old validate.
    module_load_include('inc', 'media', 'includes/media.admin');
    media_admin_validate($form, $form_state);
  }
}

/**
 * Enter description here
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_edit_multiple_redirect($form, &$form_state) {
  $fids = implode(' ', array_keys(array_filter($form_state['values']['files'])));
  $form_state['redirect'] = array(
    'admin/content/media/edit_multiple/' . $fids,
    array(
      'query' => array(
        'destination' => 'admin/content/media/thumbnails',
      ),
    ),
  );
}

/**
 * Enter description here
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_delete_multiple_redirect($form, &$form_state) {
  $fids = implode(' ', array_keys(array_filter($form_state['values']['files'])));
  $form_state['redirect'] = array(
    'admin/content/media/delete_multiple/' . $fids,
    array(
      'query' => array(
        'destination' => 'admin/content/media/thumbnails',
      ),
    ),
  );
}

/**
 * Puts all selected media items into a zip archive and sends it as download.
 *
 * @TODO: check for internet sources etc. Only local files should be parsed.
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_download_images_submit($form, &$form_state) {
  if (isset($form_state['input']['selected_media']) && media_access('download')) {
    $ids = array_keys($form_state['input']['selected_media']);

    // only load those
    $conditions[] = array(
      'property' => array(
        'fid',
        array(
          $ids,
        ),
        'IN',
      ),
    );
    $media_entities = media_browser_plus_load_multiple(array(
      'conditions' => $conditions,
      'apply_filter' => FALSE,
      'paging' => FALSE,
    ));

    // Create archive.
    apache_setenv('no-gzip', '1');
    $name = 'media-download-' . md5(microtime() . uniqid());
    $zip_file = '/tmp/' . $name . '.zip';
    $zip = new ZipArchive();
    $res = $zip
      ->open($zip_file, ZipArchive::CREATE);
    if ($res === TRUE && count($media_entities->results)) {
      foreach ($media_entities->results as $media) {
        $zip
          ->addFile(drupal_realpath($media->uri), $media->filename);
      }
      $zip
        ->close();

      /** OLD
          header('Content-type: application/zip');
          header('Content-Disposition: attachment; filename=' . $zip_file);
          header('Content-Length: ' . filesize($zip_file));
          header('Pragma: no-cache');
          header('Expires: 0');
          */
      header('Cache-Control: public');
      header('Pragma: public');
      header('Expires: 0');
      header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
      header('Cache-Control: public');

      // header('Content-Description: File Transfer');
      // header('Content-type: application/zip');
      header('Content-Disposition: attachment; filename=' . $zip_file);

      // header('Content-Transfer-Encoding: binary');
      header('Content-length: ' . filesize($zip_file));
      readfile($zip_file);
      unlink($zip_file);
      die;
    }
    else {
      drupal_set_message(t('Failed to create download archive'), 'error');
    }
  }
}

/**
 * Alter the media list display.
 *
 */
function _media_browser_plus_media_admin_list_alter(&$form, &$form_state) {
  global $user;

  // Check access rights.
  if (!media_browser_plus_access('media list view')) {
    drupal_access_denied();
    return array();
  }
  $header = array(
    'title' => array(
      'data' => t('Title'),
      'specifier' => 'filename',
      'type' => 'property',
      'field' => 'f.filename',
    ),
    'type' => array(
      'data' => t('Type'),
      'specifier' => 'filemime',
      'type' => 'property',
      'field' => 'f.filemime',
    ),
    'folder' => array(
      'data' => t('Folder'),
      'specifier' => array(
        'field' => 'field_folder',
        'column' => 'tid',
      ),
      'type' => 'field',
    ),
    'size' => array(
      'data' => t('Size'),
      'specifier' => 'filesize',
      'type' => 'property',
      'field' => 'f.filesize',
    ),
    'author' => array(
      'data' => t('Author'),
      'specifier' => 'uid',
      'type' => 'property',
      'field' => 'u.name',
    ),
    'timestamp' => array(
      'data' => t('Updated'),
      'specifier' => 'timestamp',
      'type' => 'property',
      'sort' => 'desc',
      'field' => 'f.timestamp',
    ),
    'operations' => array(
      'data' => t('Operations'),
    ),
  );
  $destination = drupal_get_destination();
  $options = array();
  $media_entities = media_browser_plus_load_multiple(array(
    'conditions' => array(),
    'header' => $header,
  ));

  // Gather the data from each media object.
  foreach ($media_entities->results as $media) {

    // Load folder name.
    $folder = '';
    if (isset($media->field_folder[LANGUAGE_NONE][0]['tid']) && ($term = taxonomy_term_load($media->field_folder[LANGUAGE_NONE][0]['tid']))) {
      $folder = $term->name;
    }

    // Load user object if media author is not the current user.
    if ($media->uid != $user->uid) {
      $media_user = user_load($media->uid);
    }
    else {
      $media_user = $user;
    }
    $options[$media->fid] = array(
      'title' => theme('media_link', array(
        'file' => $media,
      )),
      'folder' => $folder,
      'type' => check_plain($media->filemime),
      'size' => format_size($media->filesize),
      'author' => theme('username', array(
        'account' => $media_user,
      )),
      'timestamp' => format_date($media->timestamp, 'short'),
    );
    $options[$media->fid]['operations'] = l(t('edit'), 'media/' . $media->fid . '/edit', array(
      'query' => $destination,
    ));
  }

  // Grab old options.
  $ops = $form['options']['operation']['#options'];

  // Redo the options form.
  unset($form['options']);
  $form['options'] = array(
    '#type' => 'fieldset',
    '#title' => t('Operations'),
    '#weight' => -10,
    'operations' => array(
      '#type' => 'container',
      '#prefix' => '<div class="container-inline">',
      '#suffix' => '</div>',
      'operation' => array(
        '#type' => 'select',
        '#options' => $ops,
        '#default_value' => 'delete',
      ),
      'submit' => array(
        '#type' => 'submit',
        '#value' => t('Submit'),
        '#submit' => array(
          'media_admin_submit',
        ),
        '#validate' => array(
          'media_admin_validate',
        ),
      ),
    ),
    'folder' => array(
      '#type' => 'container',
      'selected_folder' => array(
        '#type' => 'select',
        '#title' => t('Media Folder*'),
        '#required' => FALSE,
        '#options' => _media_browser_plus_folder_list(),
      ),
      'submit' => array(
        '#type' => 'container',
        '#prefix' => '<div class="container-inline">',
        '#suffix' => '</div>',
        'submit' => array(
          '#type' => 'submit',
          '#value' => t('Change Folder'),
          '#submit' => array(
            'media_browser_plus_media_admin_folder_change_submit',
          ),
          '#validate' => array(
            'media_admin_validate',
          ),
        ),
        'notice' => array(
          '#type' => 'item',
          '#markup' => t('*: change will be applied to ALL selected media files'),
        ),
      ),
    ),
  );
  $form['admin']['files']['#header'] = $header;
  $form['admin']['files']['#options'] = $options;

  // Reset pager.
  unset($form['admin']['pager']);
  $form['admin']['pager'] = array(
    '#markup' => _media_browser_plus_pager($media_entities->page, $media_entities->pages),
  );
  return $form;
}

/**
 * Called by the JS fronted (ajax) to change the folder of a media object.
 */
function media_browser_plus_change_folder($form, &$form_state) {

  // Parse values.
  $folder = (int) str_replace('folder_load_', '', $form_state['input']['folder']);
  $media = file_load((int) str_replace('edit-files-', '', $form_state['input']['media']));

  // Apply new folder.
  if (isset($media->field_folder[LANGUAGE_NONE][0]['tid'])) {
    $media->field_folder[LANGUAGE_NONE][0]['tid'] = $folder;
  }
  else {
    $media->field_folder = array(
      LANGUAGE_NONE => array(
        array(
          'tid' => $folder,
        ),
      ),
    );
  }

  // Save changes.
  media_browser_plus_move_file($folder, $media);

  // @fixme Decide: die() or return.
  die('');
  return $form;
}

/**
 * Called by the JS fronted (ajax) to get the media list for a given folder.
 */
function media_browser_plus_thumbnailsJSON() {
  if (isset($_GET['folder'])) {
    $folder = (int) str_replace('folder_load_', '', $_GET['folder']);

    // Create conditions.
    $conditions = array();

    // Check for filter set by library.
    if (isset($_GET['filter'])) {
      $filter = drupal_json_decode($_GET['filter']);

      // Bugfix - $conditions = $filter;
      foreach ($filter as $key => $value) {

        // Checking each filter.
        $valid = TRUE;
        foreach ($value as $type => $params) {
          foreach ($params as $param) {
            if (is_array($param)) {
              if (empty($param)) {
                $valid = FALSE;
                break;
              }
              foreach ($param as $media_type) {
                if (strlen(trim($media_type)) == 0) {
                  $valid = FALSE;
                  break;
                }
              }
            }
            else {
              if (strlen(trim($param)) == 0) {
                $valid = FALSE;
                break;
              }
            }
          }
        }
        if ($valid) {
          $conditions[] = $value;
        }
      }
    }

    // More conditions.
    $conditions[] = array(
      'field' => array(
        'field_folder',
        'tid',
        array(
          $folder,
        ),
        'IN',
      ),
    );
    $order = array(
      array(
        'property' => array(
          'fid',
          'DESC',
        ),
      ),
    );
    $media_entities = media_browser_plus_load_multiple(array(
      'conditions' => $conditions,
      'order' => $order,
    ));
    module_load_include('inc', 'media', 'includes/media.browser');
    foreach ($media_entities->results as $media) {
      media_browser_build_media_item($media);
    }
    $output = array(
      'media' => array_values($media_entities->results),
      'folder_loaded' => 'folder_load_' . $folder,
      'overall_count' => $media_entities->overall_count,
    );
    drupal_json_output($output);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function media_browser_plus_form_media_add_upload_multiple_alter(&$form, &$form_state) {

  // This builds the tags textfield and adds the autocomplete handlers to it.
  // The #element_validate may not be necessary because this never triggers
  // hook_field_update() or hook_field_insert()
  $form['field_tags'] = _media_browser_plus_tag_form();
  $form['field_folder'] = _media_browser_plus_folder_form();

  // Change the weight of the other form items so they appear in the right order
  $form['upload']['#weight'] = 0;
  $form['submit']['#weight'] = 2;

  // Add an additional form submission callback that fires after the default.
  $form['#submit'][] = 'media_browser_plus_submit';
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function media_browser_plus_form_media_import_alter(&$form, &$form_state) {
  $form['field_tags'] = _media_browser_plus_tag_form();
  $form['field_folder'] = _media_browser_plus_folder_form();

  // Change submit.
  $form['submit']['#weight'] = 2;
  $form['#submit'] = array(
    'media_browser_plus_media_import_submit',
  );
}

/**
 * Changing the media import standard submit to use our own batch process.
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_media_import_submit($form, &$form_state) {
  if ($form_state['values']['op'] == 'Confirm') {
    $files = $form_state['storage']['files'];
    $batch = array(
      'title' => t('Importing Media'),
      'operations' => array(
        array(
          'media_browser_plus_media_import_batch_import_files',
          array(
            $files,
            $form_state['values'],
          ),
        ),
      ),
      'finished' => 'media_browser_plus_media_import_batch_complete',
    );
    if (!empty($form_state['values']['field_tags'])) {

      // Create any new taxonomy terms.
      foreach ($form_state['values']['field_tags'] as $i => &$item) {
        if ($item['tid'] == 'autocreate') {
          $term = (object) $item;
          unset($term->tid);
          taxonomy_term_save($term);
          $item['tid'] = $term->tid;
        }
      }
    }
    batch_set($batch);
    return;
  }
  $form_state['rebuild'] = TRUE;
}

/**
 * Batch process that only differs in the ability to apply the field values to the items
 *
 * @param $files
 * @param $form_values
 * @param $context
 */
function media_browser_plus_media_import_batch_import_files($files, $form_values, &$context) {

  // Split up attributes.
  // list($files, $form_values) = $attributes;
  // Need to repeat a lot of code here just to add the fields :-(
  if (!isset($context['sandbox']['files'])) {

    // This runs the first time the batch runs.
    // This is stupid, but otherwise, I don't think it will work...
    $context['results'] = array(
      'success' => array(),
      'errors' => array(),
    );
    $context['sandbox']['max'] = count($files);
    $context['sandbox']['files'] = $files;
  }
  $files =& $context['sandbox']['files'];

  // Take a cut of files.  Let's do 10 at a time.
  $length = media_variable_get('import_batch_size', 0);
  if ($length > count($files)) {
    $length = count($files);
  }
  $to_process = array_splice($files, 0, $length);
  $image_in_message = '';
  foreach ($to_process as $file) {
    try {
      $file_obj = media_parse_to_file($file);
      $context['results']['success'][] = $file;
      if (!$image_in_message) {
        $media = file_load($file_obj->fid);
        $image_in_message = field_view_field('file', $media, 'file', 'media_preview');
      }

      // adding fields here
      $media = file_load($file_obj->fid);
      $media->field_folder[LANGUAGE_NONE][0] = array(
        'tid' => $form_values['field_folder'],
      );
      $media->field_tags[LANGUAGE_NONE] = $form_values['field_tags'];
      media_browser_plus_move_file($form_values['field_folder'], $media);
    } catch (Exception $e) {
      $context['results']['errors'][] = $file . ' Reason: ' . $e
        ->getMessage();
    }
  }
  $context['message'] = t('Importing') . theme('item_list', array(
    'items' => $to_process,
  ));

  // Just for kicks, show an image we are importing.
  $context['message'] .= drupal_render($image_in_message);
  $context['finished'] = ($context['sandbox']['max'] - count($files)) / $context['sandbox']['max'];
}

/**
 * Same completed batch method as in media.
 *
 * @param $success
 * @param $results
 * @param $operations
 */
function media_browser_plus_media_import_batch_complete($success, $results, $operations) {
  if ($results['errors']) {
    drupal_set_message(filter_xss(theme('item_list', array(
      'items' => $results['errors'],
    ))), 'error');
  }
  if ($results['success']) {
    drupal_set_message(filter_xss(theme('item_list', array(
      'items' => $results['success'],
    ))));
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function media_browser_plus_form_media_internet_add_alter(&$form, &$form_state) {

  // Add an additional form submission callback that fires after the default.
  media_browser_plus_form_media_add_upload_alter($form, $form_state);
}

/**
 * Form element validate handler for taxonomy term autocomplete element.
 *
 * Because media_browser_plus_form_media_add_upload_multiple_alter() adds a
 * tags widget to a form that is not an entity editing form, but it is desired
 * for taxonomy_autocomplete_validate() to have access to the settings of the
 * field for which this widget is being added, this handler runs before
 * taxonomy_autocomplete_validate(), and adds the expected information to
 * $form_state, as expected by taxonomy_autocomplete_validate().
 */
function media_browser_plus_prepare_taxonomy_autocomplete_validate(&$element, &$form_state) {

  // Causes: Notice: Undefined index: #language in
  // media_browser_plus_prepare_taxonomy_autocomplete_validate()
  // (line 436 of ...sites/all/modules/media_browser_plus-HEAD/media_browser_plus.module).
  // @TODO: Fix
  $form_state['field'][$element['#field_name']][$element['#language']]['field'] = field_info_field($element['#field_name']);

  // Fixes: undefined index #field_parents in field_widget_field().
  if (!isset($element['#field_parents'])) {
    $element['#field_parents'] = array();
  }
}

/**
 * Submit handler for the media browser forms that create new media entities.
 *
 * Enhances the media creation process by populating field content for the newly
 * created entities from user-submitted data and/or data available from a
 * remote provider.
 *
 * @see media_browser_plus_form_media_add_upload_multiple_alter()
 * @see media_browser_plus_form_media_internet_add_alter()
 */
function media_browser_plus_submit($form, &$form_state) {

  // Grab the fids of the newly created media entities from the redirect query
  // string that was created by the form's primary submit handler, and load the
  // corresponding entities.
  $fids = $form_state['redirect'][1]['query']['fid'];
  if (!is_array($fids)) {
    $fids = array(
      $fids,
    );
  }
  $media_entities = file_load_multiple($fids);

  // If tags have been entered, apply them to each new entity.
  if (!empty($form_state['values']['field_tags'])) {

    // Create any new taxonomy terms.
    foreach ($form_state['values']['field_tags'] as $i => &$item) {
      if ($item['tid'] == 'autocreate') {
        $term = (object) $item;
        unset($term->tid);
        taxonomy_term_save($term);
        $item['tid'] = $term->tid;
      }
      unset($item);
    }
    foreach ($media_entities as $media) {
      $media->field_tags[LANGUAGE_NONE] = $form_state['values']['field_tags'];
    }
  }

  // Apply folder.
  foreach ($media_entities as $media) {
    $media->field_folder[LANGUAGE_NONE] = array(
      array(
        'tid' => $form_state['values']['field_folder'],
      ),
    );
  }

  // If the new media is from a 3rd party provider, and that provider also
  // provides MRSS data about the media, then populate the title and description
  // fields from that data.
  if (!empty($form_state['values']['embed_code'])) {
    $provider = media_internet_get_provider($form_state['values']['embed_code']);
    if ($data = _media_browser_plus_metadata($provider)) {
      foreach ($data as $field_name => $value) {
        $field = field_info_field($field_name);

        // Limiting value population only if the field is of type 'text' or
        // 'text_long' isn't as extensible as would be ideal, but we need some
        // protection against populating a field with incompatible content.
        if (isset($field) && in_array($field['type'], array(
          'text',
          'text_long',
        )) && isset($field['bundles']['media'])) {
          foreach ($media_entities as $media) {
            if (in_array($media->type, $field['bundles']['media']) && !isset($media->{$field_name}[LANGUAGE_NONE][0]['value'])) {
              $media->{$field_name}[LANGUAGE_NONE][0]['value'] = $value;
            }
          }
        }
      }
    }
  }
  foreach ($media_entities as $media) {
    media_browser_plus_move_file($form_state['values']['field_folder'], $media);
  }
}

/**
 * Form submit handler for the media browser forms that edit media entities.
 *
 * Changes file's filesystem physical folder
 *
 * @see media_browser_plus_form_media_edit_alter()
 */
function media_browser_plus_edit_file_submit($form, &$form_state) {
  $media = $form_state['file'];
  $folder_id = $media->field_folder[LANGUAGE_NONE][0]['tid'];

  // Only save it if the folder id is changed
  if ($form['field_folder'][LANGUAGE_NONE]['#default_value'][0] != $folder_id) {
    media_browser_plus_move_file($folder_id, $media);
  }
}

/**
 * Helper function to return metadata from a 3rd party media provider.
 *
 * Support for 3rd party metadata such as YouTube.
 *
 * @param $provider
 *   A provider object as returned by media_internet_get_provider().
 *
 * @return
 *   An array of media metadata available from the provider, keyed on field
 *   name.
 *
 * @see http://video.search.yahoo.com/mrss
 * @see media_internet_get_provider()
 * @see MediaInternetYouTubeHandler::getMRSS()
 */
function _media_browser_plus_metadata($provider) {

  // @todo This is early, experimental code, still subject to much change. For
  //   now, we assume $provider->getMRSS() returns a SimpleXML element. We'll
  //   want to change this assumption and have it return an array instead, but
  //   that requires fixing media_retrieve_xml() to handle XML namespaces
  //   properly.
  $data = array();
  if (is_callable(array(
    $provider,
    'getMRSS',
  )) && ($rss = $provider
    ->getMRSS())) {

    // MRSS is an extension of RSS, so the title field is available in the
    // default (ATOM) namespace.
    $data['media_title'] = (string) $rss->title;

    // The MRSS extensions are in their own namespace.
    $mrss = $rss
      ->children('http://search.yahoo.com/mrss/');
    $data['media_description'] = (string) $mrss->group->description;
  }
  $data = array_filter($data, 'strlen');
  return $data;
}

/**
 * Implements hook_preprocess_media_link().
 */
function media_browser_plus_preprocess_media_link(&$variables) {

  // Use the value of the title field, when there is one, as the link text for
  // all links that would otherwise default to the filename.
  // @todo Solve generically using the 'label' key of hook_entity_indo(). See
  //   http://drupal.org/node/910396.
  $media = file_load($variables['file']->fid);
  if (empty($variables['file']->description) && isset($media->media_title[LANGUAGE_NONE][0]['value'])) {
    $variables['file']->description = $media->media_title[LANGUAGE_NONE][0]['value'];
  }
}

/**
 * Implements hook_preprocess_media_thubmnail().
 */
function media_browser_plus_preprocess_media_thumbnail(&$variables) {

  // See media_browser_plus_preprocess_media_link(). Same thing here, but for
  // the links that appear underneath thumbnail previews.
  $media = $variables['element']['#file'];
  if (isset($media->media_title[LANGUAGE_NONE][0]['value'])) {
    $variables['element']['#name'] = $media->media_title[LANGUAGE_NONE][0]['value'];
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Altering the add file upload form the include folder and tag options
 */
function media_browser_plus_form_media_add_upload_alter(&$form, &$form_state) {

  // Alter weight to display new forms in correct order.
  $form['file']['#weight'] = -5;
  $form['submit']['#weight'] = 5;
  $form['field_tags'] = _media_browser_plus_tag_form();
  $form['field_folder'] = _media_browser_plus_folder_form();
  $form['#submit'][] = 'media_browser_plus_submit';
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Ensure the tagging form is below the folder form part.
 */
function media_browser_plus_form_media_edit_alter(&$form, &$form_state) {

  // Setting the weight accordingly.
  $form['field_folder']['#weight'] = $form['field_tags']['#weight'] - 1;
  $form['actions']['cancel'] = array(
    '#type' => 'submit',
    '#value' => t('Cancel'),
    '#weight' => 20,
    '#submit' => array(
      'media_browser_plus_edit_cancel',
    ),
  );
  $form['actions']['submit']['#submit'][] = 'media_browser_plus_edit_file_submit';
}

/**
 * @todo Document what this function does.
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_edit_cancel($form, &$form_state) {
  $destination = array();
  if (isset($_GET['destination'])) {
    $destination = drupal_get_destination();
    unset($_GET['destination']);
  }
  if (isset($destination['destination'])) {
    $form_state['redirect'] = $destination['destination'];
  }
}

/**
 * Returns the tag form element.
 */
function _media_browser_plus_tag_form() {
  return array(
    '#weight' => 1,
    '#language' => LANGUAGE_NONE,
    '#field_name' => 'field_tags',
    '#columns' => array(
      'tid',
    ),
    '#title' => t('Tags'),
    '#description' => t('Enter a comma-separated list of words to describe your media.'),
    '#required' => FALSE,
    '#delta' => 0,
    '#type' => 'textfield',
    '#default_value' => '',
    '#autocomplete_path' => 'taxonomy/autocomplete/field_tags',
    '#element_validate' => array(
      'media_browser_plus_prepare_taxonomy_autocomplete_validate',
      'taxonomy_autocomplete_validate',
    ),
    '#size' => 60,
  );
}

/**
 * Returns a select form item with a selectable media folders.
 */
function _media_browser_plus_folder_form() {
  $list = _media_browser_plus_folder_list();
  return array(
    '#type' => 'select',
    '#language' => LANGUAGE_NONE,
    '#title' => t('Media Folder'),
    '#field_name' => 'field_tags',
    '#weigth' => -2,
    '#options' => $list,
    '#description' => t('Select a folder for the media to be put in'),
  );
}

/**
 * Implements hook_menu().
 */
function media_browser_plus_menu() {
  $items['admin/content/media/change_folder'] = array(
    'title' => 'Change Folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_change_folder',
    ),
    'type' => MENU_CALLBACK,
    'access callback' => 'media_access',
    'access arguments' => array(
      'edit',
    ),
  );
  $items['admin/content/media/filter'] = array(
    'title' => 'Media Filter',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_media_filter',
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
    'access callback' => 'media_access',
    'access arguments' => array(
      'filter',
    ),
    'type' => MENU_LOCAL_ACTION,
    'context' => MENU_CONTEXT_INLINE,
  );
  $items['admin/content/media/thumbnailsJSON'] = array(
    'title' => 'Load Media Entities',
    'page callback' => 'media_browser_plus_thumbnailsJSON',
    'access callback' => 'media_access',
    'access arguments' => array(
      'preview',
    ),
  );
  $items['admin/config/media/media_browser_plus_settings'] = array(
    'title' => 'Media Browser Plus Settings',
    'description' => 'Change the behaviour and layout of the media browser plus UI',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_media_settings',
    ),
    'access callback' => 'media_access',
    'access arguments' => array(
      'administer',
    ),
  );
  $items['admin/content/media/edit_multiple/%'] = array(
    'title' => 'Edit Media Items',
    'page callback' => 'media_browser_plus_edit_multiple_form',
    'page arguments' => array(
      4,
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
    'access callback' => 'media_access',
    'access arguments' => array(
      'edit',
    ),
  );
  $items['admin/content/media/delete_multiple/%'] = array(
    'title' => 'Delete Media Items',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_delete_multiple_form',
      4,
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
    'access callback' => 'media_access',
    'access arguments' => array(
      'edit',
    ),
  );

  // folder management disabled until menu bug has been fixed
  $items['admin/content/media/folder_list'] = array(
    'title' => 'Administer folders',
    'description' => 'Manage your media folders',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_list',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
  );
  $items['admin/content/media/add_folder'] = array(
    'title' => 'Add Folder',
    'description' => 'Add a new media folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_add',
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
  );
  $items['admin/content/media/folder/%media_browser_plus_folder/edit'] = array(
    'title' => 'Edit Folder',
    'description' => 'Edit media folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_edit',
      4,
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
  );
  $items['admin/content/media/folder/%media_browser_plus_folder/delete'] = array(
    'title' => 'Delete Folder',
    'description' => 'Delete media folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_delete',
      4,
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
  );
  $items['admin/content/media/%file/preview'] = array(
    'title' => 'Preview Media',
    'description' => 'Preview Media Item',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_media_preview',
      3,
    ),
    'access callback' => 'media_access',
    'access arguments' => array(
      'preview',
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
  );
  return $items;
}

/**
 * Implements hook_menu_alter().
 *
 * @param $items
 */
function media_browser_plus_menu_alter(&$items) {
  $items['admin/content/media']['access arguments'] = array(
    'access media backend',
  );
  $items['admin/content/media']['access callback'] = array(
    'media_browser_plus_access',
  );
}

/**
 * Implements hook_permission().
 */
function media_browser_plus_permission() {
  return array(
    'media grid view' => array(
      'title' => t('Grid View'),
      'description' => t('Allow users to use the grid view.'),
    ),
    'media list view' => array(
      'title' => t('List View'),
      'description' => t('Allow users to use the list view.'),
    ),
    'access media backend' => array(
      'title' => t('Access media backend'),
      'description' => t('Allow user to access the media backend according to their privileges.'),
    ),
    'upload media' => array(
      'title' => t('Upload media'),
      'description' => t('Allow user to add media.'),
    ),
    'download media' => array(
      'title' => t('Download Media'),
      'description' => t('Allows the user to download the original media items.'),
    ),
    'filter media' => array(
      'title' => t('Filter Media'),
      'description' => t('Allows the user to filter the displayed media in the backend.'),
    ),
    'administer media folders' => array(
      'title' => t('Administer Media Folders'),
      // @TODO better description
      'description' => t('Allows the user to add, edite, delete and resort media folders.'),
    ),
    'preview media' => array(
      'title' => t('Preview media'),
      // @TODO better description
      'description' => t('Allows the user to view a configurable preview of the original media item.'),
    ),
  );
}

/**
 * Implements hook_library().
 */
function media_browser_plus_library() {
  $library_path = variable_get('media_browser_plus_library_path', 'sites/all/libraries');
  $stylesheet = variable_get('media_browser_plus_stylesheet', 'example1');
  $libraries['colorbox'] = array(
    'title' => 'Colorbox',
    'website' => 'http://colorpowered.com/colorbox/',
    'version' => '1.3.9',
    'js' => array(
      $library_path . '/colorbox/jquery.colorbox-min.js' => array(),
    ),
    'css' => array(
      $library_path . '/colorbox/' . $stylesheet . '/colorbox.css' => array(
        'type' => 'file',
        'media' => 'screen',
      ),
    ),
  );
  $path = drupal_get_path('module', 'media_browser_plus');
  $libraries['media_browser_plus'] = array(
    'title' => 'Media Browser Plus',
    'version' => '1',
    'js' => array(
      $path . '/js/media_browser_plus.admin.menu.js' => array(),
    ),
    'css' => array(
      $path . '/css/media_browser_plus.admin.css' => array(
        'type' => 'file',
        'media' => 'screen',
      ),
      $path . '/css/colorbox.css' => array(
        'type' => 'file',
        'media' => 'screen',
      ),
    ),
  );
  return $libraries;
}

/**
 * Checks if the user has the permission to download a file.
 *
 * @param $field
 * @param $entity_type
 * @param $entity
 */
function media_browser_plus_file_download_access($field, $entity_type, $entity) {

  // Only check against media entities.
  if ($entity_type == 'file') {

    // Check for media admin AND return true if found.
    return media_browser_plus_media_access($entity);
  }
}

/**
 * Checks access to a given media entity.
 *
 * @param $media_entity
 */
function media_browser_plus_media_access($media_entity) {
  if (media_browser_plus_access('administer media')) {
    return TRUE;
  }

  // Start with ACCESS_ALLOW - by default media items are fully accessible.
  $access = MEDIA_ENTITY_ACCESS_ALLOW;

  // Collect all modules implementing hook_media_entity_access.
  foreach (module_implements('media_entity_access') as $module) {

    // and invoke the hook
    $return = module_invoke($module, 'media_entity_access', $media_entity);

    // If no ALLOW or DENY was returned we assume IGNORE and check the next.
    if ($return != MEDIA_ENTITY_ACCESS_ALLOW && $return != MEDIA_ENTITY_ACCESS_DENY) {
      continue;
    }

    // If we have a DENY we can return a complete false here.
    if ($return === MEDIA_ENTITY_ACCESS_DENY) {
      return FALSE;
    }

    // Otherwise it is an ALLOW and we save it.
    $access = MEDIA_ENTITY_ACCESS_ALLOW;
  }

  // Check if we had one allow.
  return $access === MEDIA_ENTITY_ACCESS_ALLOW;
}

/**
 * Revokes the general 'view media' == 'download media' access rule.
 *
 * @param $grants
 * @param $field
 * @param $entity_type
 * @param $entity
 */
function media_browser_plus_file_download_access_alter(&$grants, $field, $entity_type, $entity = NULL) {
  if ($entity_type == 'file') {
    unset($grants['file']);
  }
}

/**
 * Implements hook_media_operations().
 */
function media_browser_plus_media_operations() {
  return array(
    'edit_multiple' => array(
      'label' => t('Edit'),
      'callback' => NULL,
      'redirect' => 'admin/content/media/edit_multiple/%fids',
    ),
  );
}

/**
 * Manages access for media browser plus actions.
 *
 * @param $op
 */
function media_browser_plus_access($op) {
  return user_access('administer media') || user_access($op);
}

/**
 * Implements of hook_load().
 *
 * Used to load media folders.
 */
function media_browser_plus_folder_load($id) {
  return taxonomy_term_load($id);
}

/**
 * Creates the folder media tree.
 */
function _media_browser_plus_folder_hierarchy_list($list) {
  if (!isset($list['parents']) || !isset($list['children'])) {
    return;
  }
  if (count($list['parents']) == 0) {
    return t('No folders created yet');
  }
  else {
    if (_media_browser_plus_has_unsorted_media()) {
      $all_folders = array();
      $all_folders[0] = new stdClass();
      $all_folders[0]->name = t('Unsorted');
      $all_folders[0]->tid = 0;
      $list['parents'] = array_merge($all_folders, $list['parents']);
    }
    return _media_browser_plus_folder_hierarchy_list_helper($list['parents'], $list['children']);
  }
}

/**
 * @todo Document what this function does.
 *
 * @param $parents
 * @param $children
 * @param $hide
 */
function _media_browser_plus_folder_hierarchy_list_helper($parents, &$children, $hide = FALSE) {
  $path = base_path() . drupal_get_path('module', 'media_browser_plus');
  $buffer = '<ul' . ($hide ? ' class="hidden"' : '') . '>' . "\n";
  foreach ($parents as $item) {
    $has_children = isset($children[$item->tid]);
    $has_media = _media_browser_plus_folder_empty($item->tid) || $item->tid == 0;
    $buffer .= '<li class="media_folder';
    if ($has_children) {
      $buffer .= ' parent">';
      $buffer .= '<div class="folder';
      $buffer .= $has_media ? '' : ' emptyParent';
      $buffer .= ' folder-children-toggle">' . '<img src="' . $path . '/images/pixel.gif" border="0" alt="">' . '</div> ';
      $buffer .= '<div id="folder_load_' . $item->tid . '" class="folder_load';
      $buffer .= $has_media ? '' : ' emptyFolder';
      $buffer .= '">' . $item->name . '</div>' . "\n";
      $buffer .= _media_browser_plus_folder_hierarchy_list_helper($children[$item->tid], $children, TRUE);
      $buffer .= '</li>' . "\n";
    }
    else {
      $buffer .= '">';
      $buffer .= '<div class="folder';
      $buffer .= $has_media ? '' : ' empty';
      $buffer .= ' ">' . '<img src="' . $path . '/images/pixel.gif" border="0" alt="">' . '</div> ';
      $buffer .= '<div id="folder_load_' . $item->tid . '" class="folder_load';
      $buffer .= $has_media ? '' : ' emptyFolder';
      $buffer .= '">' . $item->name . '</div></li>' . "\n";
    }
  }
  $buffer .= '</ul>' . "\n";
  return $buffer;
}

/**
 * @todo Document what this function does.
 *
 * helper function
 */
function _media_browser_plus_create_relationship_list($categories) {
  $return = array();
  $parents = array();
  $children = array();
  foreach ($categories as $key => $value) {

    // root node
    if ($value->parents[0] == 0) {

      // create parent entry
      $parents[$value->tid] = $value;
      continue;
    }
    else {

      // create child entry
      $children[$value->parents[0]][$value->tid] = $value;
      continue;
    }
  }

  // if no root parents
  if (!count($parents) && count($children)) {
    foreach ($children as $pid => $parents_children) {
      if (!isset($parents[$pid])) {

        // move child into parent array keeping indexes
        foreach ($children[$pid] as $id => $item) {
          $parents[$id] = $item;
        }
        unset($children[$pid]);
      }
    }
  }
  $return['parents'] = $parents;
  $return['children'] = $children;
  return $return;
}

/**
 * Checks for unsorted (i.e. media not in folders) media.
 */
function _media_browser_plus_has_unsorted_media() {

  // loading media
  $entity_controller = entity_get_controller('file');
  $media_entities = $entity_controller
    ->load(NULL, array(), 0, 100);
  foreach ($media_entities as $media) {
    if (!isset($media->field_folder[LANGUAGE_NONE][0]['tid'])) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * @todo Document what this function does.
 *
 * @param string $prefix_padding
 */
function _media_browser_plus_folder_list($prefix_padding = '-') {
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  $folders = taxonomy_get_tree($vocabulary->vid);
  $folders = _media_browser_plus_filter_folder_access($folders);

  // Fill list with padded folders.
  $list = array();
  foreach ($folders as $folder) {
    $pad = $folder->depth * strlen($prefix_padding) + strlen($folder->name);
    $list[$folder->tid] = str_pad($folder->name, $pad, $prefix_padding, STR_PAD_LEFT);
  }
  return $list;
}

/**
 * Changes the folder of the submitted media items.
 */
function media_browser_plus_media_admin_folder_change_submit(&$form, &$form_state) {

  // Get IDs.
  $fids = array_keys(array_filter($form_state['values']['files']));
  $folder = (int) $form_state['values']['selected_folder'];
  $media_entities = file_load_multiple($fids);

  // Apply folder.
  foreach ($media_entities as $media) {
    if (isset($media->field_folder[LANGUAGE_NONE][0]['tid'])) {
      $media->field_folder[LANGUAGE_NONE][0]['tid'] = $folder;
    }
    else {
      $media->field_folder = array(
        LANGUAGE_NONE => array(
          array(
            'tid' => $folder,
          ),
        ),
      );
    }
    media_browser_plus_move_file($folder, $media);
  }
  drupal_set_message(t('Folder changes applied successfully'));
}

/**
 * Loads media entities and allows filtering, sorting and paging.
 *
 * @param $variables holds an array with the following optional parameters
 * $ids
 *   one dimensional array of entity_ids
 * $conditions
 *   multidemsional array build like this:
 *   array(
 *     array('entity' => array('comlumn', 'value', 'condition')),
 *     array('property' => array('comlumn', 'value', 'condition')),
 *     array('field' => array('field_name', 'comlumn', 'value', 'condition')),
 *   )
 * $order
 *   multidemsional array build like this:
 *   array(array('entity' => array('comlumn', 'direction')),
 *         array('property' => array('comlumn', 'direction')),
 *         array('field' => array('comlumn', 'direction')))
 * $header
 *   table header used for sorting
 * $per_page
 *   items per page
 * @param array $paging
 *   enables/disables paging - default is paging on
 */
function media_browser_plus_load_multiple($variables) {

  // Set up default parameter.
  $params = array(
    'ids' => array(),
    'conditions' => array(),
    'order' => array(),
    'header' => array(),
    'page' => -1,
    'per_page' => variable_get('media_media_per_page'),
    'paging' => TRUE,
    'ids_only' => FALSE,
    'count_only' => FALSE,
    'apply_filter' => TRUE,
  );

  // Override defaults.
  // @todo Is this loop really necessary. Something like
  // $params = $variables + $params; should work too, right?
  foreach ($variables as $key => $value) {
    if (isset($params[$key])) {
      $params[$key] =& $variables[$key];
    }
  }
  if ($params['apply_filter'] && isset($_SESSION['media-filter'])) {
    if (strlen($_SESSION['media-filter']['filename'])) {
      $params['conditions'][] = array(
        'property' => array(
          'filename',
          '%' . $_SESSION['media-filter']['filename'] . '%',
          'LIKE',
        ),
      );
    }
    if (count($_SESSION['media-filter']['type'])) {
      $params['conditions'][] = array(
        'property' => array(
          'type',
          explode(',', $_SESSION['media-filter']['type']),
          'IN',
        ),
      );
    }
    if (count($_SESSION['media-filter']['field_folder'])) {
      $params['conditions'][] = array(
        'field' => array(
          'field_folder',
          'tid',
          $_SESSION['media-filter']['field_folder'],
          'IN',
        ),
      );
    }
    if (count($_SESSION['media-filter']['field_tags'])) {
      foreach ($_SESSION['media-filter']['field_tags'] as $tag_id) {
        $params['conditions'][] = array(
          'field' => array(
            'field_tags',
            'tid',
            $tag_id,
            '=',
          ),
        );
      }
    }
  }

  // Allow other modules to add/alter conditions.
  foreach (module_implements('media_access_conditions') as $module) {
    $params['conditions'] = array_merge(module_invoke($module, 'media_access_conditions'), $params['conditions']);
  }
  $query = new EntityFieldQuery();

  // Set entity type to media.
  $query
    ->entityCondition('entity_type', 'file');

  // Parse ids if any have been passed.
  if (count($params['ids'])) {
    $query
      ->entityCondition('entity_id', $params['ids'], 'IN');
  }

  // Check for table header.
  if (count($params['header'])) {
    $query
      ->tableSort($params['header']);
  }

  // Parse conditions.
  foreach ($params['conditions'] as $condition) {

    // Look what type we have.
    $condition_keys = array_keys($condition);
    switch (array_pop($condition_keys)) {
      case 'entity':
        $query
          ->entityCondition($condition['entity'][0], $condition['entity'][1], $condition['entity'][2]);
        break;
      case 'property':
        $query
          ->propertyCondition($condition['property'][0], $condition['property'][1], $condition['property'][2]);
        break;
      case 'field':
        $query
          ->fieldCondition($condition['field'][0], $condition['field'][1], $condition['field'][2], $condition['field'][3]);
        break;
    }
  }

  // Parse order array.
  foreach ($params['order'] as $condition) {

    // Look what type we have.
    $condition_keys = array_keys($condition);
    switch (array_pop($condition_keys)) {
      case 'entity':
        $query
          ->entityOrderBy($condition['entity'][0], $condition['entity'][1]);
        break;
      case 'property':
        $query
          ->propertyOrderBy($condition['property'][0], $condition['property'][1]);
        break;
      case 'field':
        $query
          ->fieldOrderBy($condition['field'][0], $condition['field'][1], $condition['field'][2]);
        break;
    }
  }

  // Prepare result object.
  $res_object = new stdClass();
  if ($params['paging'] && !$params['count_only']) {

    // Doing a seperate count query here, because including the internal pager
    // doesn't work but seems the only way to get a total result count.
    $count = clone $query;
    $count
      ->pager();
    $count
      ->execute();
    $res_object->overall_count = $count->pager['total'];

    // Using range here, because as said above the internal pager seems to be
    // bugged.
    $page = $params['page'];
    if ($page == -1) {
      $page = isset($_REQUEST['page']) ? $_REQUEST['page'] : 0;
    }
    $query
      ->range($page * $params['per_page'], $params['per_page']);

    // Adding the addition result fields.
    $res_object->page = $page;
    $res_object->pages = ceil($res_object->overall_count / variable_get('media_media_per_page'));
    $res_object->per_page = $params['per_page'];
  }

  // Count only query.
  if ($params['count_only']) {
    $query
      ->pager();
    $query
      ->execute();
    return $query->pager['total'];
  }
  $res_object->results = array();

  // Execute query and load results.
  $result = $query
    ->execute();
  if (!empty($result['file'])) {
    $res_object->results = $params['ids_only'] ? array_keys($result['file']) : entity_load('file', array_keys($result['file']));
  }
  return $res_object;
}

/**
 * Looks if a filter is active and filters the folders accordingly.
 *
 * @param array $folders
 */
function _media_browser_plus_filter_folders($folders) {

  // No filter active, return unchanged $folders array.
  $filtered_folders = $folders;
  if (isset($_SESSION['media-filter'])) {
    $folder_filtered = array();

    // Look through the tree and add elements that match filter.
    foreach ($folders as $item) {
      if (in_array($item->tid, $_SESSION['media-filter']['field_folder'])) {
        $folder_filtered[] = $item;
      }
    }
    $filtered_folders = $folder_filtered;
  }
  $filtered_folders = _media_browser_plus_filter_folder_access($filtered_folders);
  return $filtered_folders;
}

/**
 * @todo Document what this function does.
 *
 * @param $folders
 */
function _media_browser_plus_filter_folder_access($folders) {
  $temp_folders = $folders;
  $filtered_folders = array();
  foreach ($temp_folders as $item) {
    $access = TRUE;
    foreach (module_implements('media_folder_access') as $module) {
      $access = module_invoke($module, 'media_folder_access', $item);
      if ($access === FALSE) {
        break;
      }
      else {
        $access = TRUE;
      }
    }
    if ($access) {
      $filtered_folders[] = $item;
    }
  }
  return $filtered_folders;
}

/**
 * @todo Document what this function does.
 *
 * @param $page
 * @param $pages
 */
function _media_browser_plus_pager($page, $pages) {

  // Get url for paging link.
  $destination = drupal_get_destination();
  $link = base_path() . '?q=admin/content/media/list';
  $sort = isset($_GET['sort']) ? '&sort=' . check_plain($_GET['sort']) : '';
  $order = isset($_GET['order']) ? '&order=' . check_plain($_GET['order']) : '';
  $url = $link . $sort . $order;

  // Create paging div inside buffer.
  $output = '<div id="media_paging_table" align="center">';

  // Calculate paging.
  $start = max(0, $page - ceil(variable_get('media_page_items_per_page') / 2));
  $end = min($pages, $start + variable_get('media_page_items_per_page'));
  if ($start > 0) {
    $output .= _media_browser_plus_pager_add_page_item($url, $start - 1, $page, '...');
  }

  // Create numbers.
  for ($i = $start; $i < $end; $i++) {
    $output .= _media_browser_plus_pager_add_page_item($url, $i, $page, $i + 1);
  }
  if ($pages > $i) {
    $output .= _media_browser_plus_pager_add_page_item($url, $i, $page, '...');
  }
  return $output . '</div>';
}

/**
 * @todo Document what this function does.
 *
 * @param $url
 * @param $page
 * @param $title
 */
function _media_browser_plus_pager_add_page_item($url, $page, $current_page, $title) {
  $page_item = '<a class="media_paging_page';
  if ($page == $current_page) {
    $page_item .= ' active_page';
  }
  $page_item .= '" href="' . $url . '&page=' . $page . '">' . $title . '</a>';
  return $page_item;
}

/**
 * Creates the media browser plus settings form.
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_media_settings($form, &$form_state = array()) {
  $form = array(
    'media_per_page' => array(
      '#type' => 'textfield',
      '#title' => 'Media Items per page',
      '#description' => t('Insert a number higher than one for the amount of media items displayed per page.'),
      '#default_value' => variable_get('media_media_per_page'),
      '#maxlength' => 4,
      '#required' => TRUE,
    ),
    'grid_window_height' => array(
      '#type' => 'textfield',
      '#title' => 'Grind Window Height',
      '#default_value' => variable_get('media_grid_window_height'),
      '#description' => t('Set a maximum height of pixels for the media grid view.'),
      '#maxlength' => 4,
      '#required' => TRUE,
    ),
    'page_items_per_page' => array(
      '#type' => 'textfield',
      '#title' => 'Page Items per page',
      '#default_value' => variable_get('media_page_items_per_page'),
      '#description' => t('Set how many page items you want in the paging navigation of each page.'),
      '#maxlength' => 4,
      '#required' => TRUE,
    ),
    'max_filesize' => array(
      '#type' => 'textfield',
      '#title' => 'Upload Maximum Filesize',
      '#default_value' => media_variable_get('max_filesize'),
      '#description' => t('Standard unit is MB and therefore can be left out. Otherwise use "NUMBER UNIT"'),
      '#maxlength' => 20,
      '#required' => TRUE,
    ),
    'root_folder' => array(
      '#type' => 'textfield',
      '#title' => 'Media Root folder',
      '#default_value' => variable_get('media_root_folder', 'media'),
      '#description' => t('The root folder of uploaded images.Dont use start or end slashes. eg "media/images"'),
      '#required' => TRUE,
    ),
  );
  $form['actions'] = array(
    '#type' => 'actions',
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save Changes'),
  );
  return $form;
}

/**
 * Saves the entered settings.
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_media_settings_submit($form, &$form_state) {
  $scheme = variable_get('file_default_scheme', 'public') . '://';

  // Get current media root folder.
  $old_root = variable_get('media_root_folder');

  // And set the new.
  $new_root = trim($form_state['values']['root_folder'], '/');

  // Change settings.
  variable_set('media_media_per_page', (int) $form_state['values']['media_per_page']);
  variable_set('media_grid_window_height', (int) $form_state['values']['grid_window_height']);
  variable_set('media_page_items_per_page', (int) $form_state['values']['page_items_per_page']);
  media_variable_set('max_filesize', trim($form_state['values']['max_filesize']));

  // Move the files to the new root folder if its changed.
  if ($old_root != $new_root) {
    variable_set('media_root_folder', $new_root);
    $source = $scheme . $old_root;
    $destination = $scheme . $new_root;
    media_browser_plus_move_physical_folder($source, $destination);
  }

  // Notify user.
  drupal_set_message(t('Media Browser Plus Settings changed successfully'));

  // Go back to media overview.
  $form_state['redirect'] = array(
    'admin/config',
  );
}

/**
 * Validates the settings.
 *
 * @param unknown_type $form
 * @param unknown_type $form_state
 */
function media_browser_plus_media_settings_validate($form, &$form_state) {

  // Validate settings.
  $value = (int) $form_state['values']['media_per_page'];
  if ($value <= 0) {
    form_set_error('Media Settings', t('Illegal value for "Media Items per page"'));
  }
  $value = (int) $form_state['values']['grid_window_height'];
  if ($value <= 100) {
    form_set_error('Media Settings', t('Illegal value for "Grind Window Height"'));
  }
  $value = (int) $form_state['values']['page_items_per_page'];
  if ($value <= 2) {
    form_set_error('Media Settings', t('Illegal value for "Page Items per page"'));
  }
  $value = parse_size(trim($form_state['values']['max_filesize']));
  if ($value === 0) {
    form_set_error('Media Settings', t('Illegal value for "Upload Maximum Filesize"'));
  }
}

/**
 * Implements hook_field_attach_presave().
 *
 * Makes sure all media are in a folder.
 */
function media_browser_plus_field_attach_presave($entity_type, $entity) {
  if ($entity_type != 'file') {
    return;
  }

  // Look for folder and set default if none found
  // $media->field_folder[LANGUAGE_NONE] = array(array('tid' => $form_state['values']['field_folder']));
  if (!isset($entity->field_folder) || !isset($entity->field_folder[LANGUAGE_NONE]) || !count($entity->field_folder[LANGUAGE_NONE]) || !isset($entity->field_folder[LANGUAGE_NONE][0]['tid']) || (int) $entity->field_folder[LANGUAGE_NONE][0]['tid'] == 0) {

    // sSt default folder is no folder or incorrect value.
    $root = media_browser_plus_get_media_root_folder();
    $entity->field_folder = array();
    $entity->field_folder[LANGUAGE_NONE] = array(
      array(
        'tid' => $root->tid,
      ),
    );
  }
}

/**
 * Check if a given folder has media in it (does include current filter)
 *
 * @param int $folder_id
 */
function _media_browser_plus_folder_empty($folder_id) {

  // Save paging values.
  $gp = isset($_GET['page']) ? $_GET['page'] : NULL;
  $pp = isset($_POST['page']) ? $_POST['page'] : NULL;

  // Set media condition.
  $condition = array(
    array(
      'field' => array(
        'field_folder',
        'tid',
        array(
          $folder_id,
        ),
        'IN',
      ),
    ),
  );
  $variables = array(
    'conditions' => $condition,
    'per_page' => 1,
    'ids_only' => TRUE,
  );
  $media = media_browser_plus_load_multiple($variables);

  // Restore paging values if necessary.
  if ($gp) {
    $_GET['page'] = $gp;
  }
  if ($pp) {
    $_POST['page'] = $pp;
  }

  // Check if media has been found in the folder.
  return $media->overall_count > 0;
}

/**
 * @todo Document what this funciont does.
 *
 * @param string $tags
 * @param boolean $tids_only
 * @param boolean $auto_create
 * @return array
 */
function media_browser_plus_load_tag_terms($tags, $tids_only = TRUE, $auto_create = FALSE) {
  $vocabulary = taxonomy_vocabulary_machine_name_load('tags');
  $select = $tids_only ? 'tid, name' : '*';
  $all_tags = array();
  $found_tags = array();
  $found_terms = array();
  $terms = explode(',', $tags);
  foreach ($terms as $tag) {

    // Check if tag exists.
    // @todo Would an EntityFieldQuery be appropriate?
    // http://drupal.org/node/916776
    $results = db_query('SELECT ' . $select . ' FROM {taxonomy_term_data} ttd WHERE ttd.name = :name AND ttd.vid = :vocabulary', array(
      'name' => check_plain(trim($tag)),
      'vocabulary' => $vocabulary->vid,
    ));
    foreach ($results as $result) {
      $term = taxonomy_term_load($result->tid);
      if ($tids_only) {
        $found_terms[] = array(
          'tid' => $term->tid,
        );
      }
      else {
        $found_terms[] = get_object_vars($term);
      }
      $found_tags[] = trim($tag);
    }
    $all_tags[] = trim($tag);
  }
  if ($auto_create) {
    foreach (array_diff($all_tags, $found_tags) as $id => $tag) {
      $term = new stdClass();
      $term->name = $tag;
      $term->vid = $vocabulary->vid;
      if (strlen(trim($term->name))) {
        taxonomy_term_save($term);
        if ($tids_only) {
          $found_terms[] = array(
            'tid' => $term->tid,
          );
        }
        else {
          $found_terms[] = get_object_vars($term);
        }
      }
    }
  }
  return $found_terms;
}

/**
 * Loads and (if $autocreate is set) creates the default media folder object.
 */
function media_browser_plus_get_media_root_folder($autocreate = FALSE) {
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  if ($vocabulary) {

    // @todo Would an EntityFieldQuery be appropriate?
    // http://drupal.org/node/916776
    $results = db_query('SELECT * FROM {taxonomy_term_data} ttd WHERE ttd.name = :name AND ttd.vid = :vocabulary', array(
      'name' => 'Media Root',
      'vocabulary' => $vocabulary->vid,
    ));
    $term = NULL;
    foreach ($results as $result) {
      $term_id = $result->tid;
    }
    if (!isset($term_id) && $autocreate) {
      $media_root_term = new stdClass();
      $media_root_term->name = 'Media Root';
      $media_root_term->description = 'default media folder';
      $media_root_term->vid = $vocabulary->vid;
      $media_root_term->weight = '-10';

      // Save (default folder) term.
      taxonomy_term_save($media_root_term);

      // @todo Would an EntityFieldQuery be appropriate?
      // http://drupal.org/node/916776
      $results = db_query('SELECT * FROM {taxonomy_term_data} ttd WHERE ttd.name = :name AND ttd.vid = :vocabulary', array(
        'name' => 'Media Root',
        'vocabulary' => $vocabulary->vid,
      ));
      foreach ($results as $result) {
        $term_id = $result->tid;
      }
    }
    if ($term_id) {
      return media_browser_plus_folder_load($term_id);
    }
  }
}

/**
 * Implements hook_media_browser_plugin_info().
 */
function media_browser_plus_media_browser_plugin_info() {
  $plugins = array();
  $plugins['library_plus'] = array(
    '#weight' => 10,
    '#title' => t('Library Plus'),
  );
  return $plugins;
}

/**
 * Implements hook_media_browser_plugin_view().
 *
 * @param $plugin_name
 * @param $params
 */
function media_browser_plus_media_browser_plugin_view($plugin_name, $params) {
  $types = isset($params['types']) ? $params['types'] : array();
  $multiselect = isset($params['multiselect']) ? $params['multiselect'] : FALSE;

  // Get plugin form.
  $upload_form = drupal_get_form('media_browser_plus_library_browser', $multiselect, $types);
  return array(
    '#title' => t('Library Plus'),
    'form' => array(
      $upload_form,
    ),
  );
}

/**
 * Remove the old Library for the media browser popup.
 *
 * @param $form
 * @param $form_state
 */
function media_browser_plus_media_browser_plugins_alter(&$form, &$form_state) {

  // @TODO: find a better way to keep the library_plus from popping up only when
  // the old library would without editing media module if possible
  if (!isset($form['library'])) {
    unset($form['library_plus']);
  }

  // remove old library
  if (isset($form['library'])) {
    unset($form['library']);
  }
}

/**
 * Creates the Extended Library for the media browser popup.
 *
 * @param $form
 * @param $form_state
 * @param $multiselect
 * @param $types
 */
function media_browser_plus_library_browser($form, &$form_state, $multiselect, $types) {
  $path = drupal_get_path('module', 'media_browser_plus');

  // Assemble library from grid view.
  $form['#attached']['library'][] = array(
    'media_browser_plus',
    'media_browser_plus',
  );
  $form['#attached']['library'][] = array(
    'media_browser_plus',
    'colorbox',
  );

  // Set base href for javascript requests.
  $settings = media_browser_plus_main_view_javascript_settings();
  $settings['media_browser_plus']['multiselect'] = $multiselect;
  $settings['media_browser_plus']['folder_dnd_enabled'] = FALSE;

  // Setting filter condition.
  $filter = array(
    array(
      'property' => array(
        'type',
        $types,
        'IN',
      ),
    ),
  );
  $settings['media_browser_plus']['filter'] = drupal_json_encode($filter);

  // Attach settings.
  $form['#attached']['js'][] = array(
    'type' => 'setting',
    'data' => $settings,
  );

  // Check access rights.
  if (!media_browser_plus_access('media grid view')) {
    drupal_access_denied();
    return array();
  }

  // Adding grid view js and css.
  $form['#attached']['js'][] = $path . '/js/media_browser_plus.admin.js';
  $form['#attached']['js'][] = $path . '/js/media_browser_plus.library.js';
  drupal_add_library('system', 'ui.draggable');
  drupal_add_library('system', 'ui.droppable');

  // Removing options form part.
  unset($form['options']);
  if (!media_browser_plus_access('media list view') || !media_browser_plus_access('media grid view')) {
    unset($form['switch']);
  }

  // Add main grid view window.
  $form['admin'] = media_browser_plus_grid_view_form(TRUE, $multiselect);

  // Append media basket only for multi select.
  if ($multiselect) {
    $form['media-basket'] = media_browser_plus_media_basket_form(TRUE);
  }
  return $form;
}

/**
 * Deleting all field data attached to the media entity.
 *
 * @todo: This should actually be done in media module
 *
 * @param $file
 */
function media_browser_plus_file_delete($file) {
  $media = file_load($file->fid);
  module_invoke_all('entity_delete', $media, 'file');
  field_attach_delete('file', $media);
}

/**
 * Appends main grid view form.
 */
function media_browser_plus_grid_view_form($library_mode = FALSE, $multiselect = FALSE) {

  // Load the media folders.
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  $folders = taxonomy_get_tree($vocabulary->vid);
  $folders = _media_browser_plus_filter_folders($folders);
  $list = _media_browser_plus_create_relationship_list($folders, TRUE);
  $folders = _media_browser_plus_folder_hierarchy_list($list);

  // Build the folder form.
  $form['admin']['folder'] = array(
    '#type' => 'markup',
    '#markup' => '<div id="folder" style="height:' . variable_get('media_grid_window_height') . 'px;">' . $folders . ' </div>',
  );
  $form['admin']['files']['#prefix'] = '<div class="media-display-thumbnails media-clear clearfix">' . '<ul class="media-list-thumbnails" style="height:' . variable_get('media_grid_window_height') . 'px;">';

  // Aetting up the header.
  $header = array(
    array(
      'data' => t('Folders'),
      'width' => '200',
    ),
    array(
      'data' => t('Media Files'),
      'width' => '*',
    ),
  );

  // and the data
  $form['buttons'] = array();
  $form['buttons']['selection_assets'] = array(
    '#type' => 'markup',
    '#markup' => '<a href="#media_folder_table" id="media_main_view_select_all" >' . t('Select All') . '</a>' . '<a href="#media_folder_table" id="media_main_view_deselect_all" >' . t('Deselect All') . '</a>',
  );
  if (!$library_mode) {
    if (media_access('view')) {
      $form['buttons']['view_media'] = array(
        '#type' => 'button',
        '#attributes' => array(
          'id' => 'media_buttons_view',
        ),
        '#value' => t('View'),
      );
    }
    if (media_access('preview')) {
      $form['buttons']['preview_media'] = array(
        '#type' => 'button',
        '#attributes' => array(
          'id' => 'media_buttons_preview',
        ),
        '#value' => t('Preview'),
      );
    }
    if (media_access('edit')) {
      $form['buttons']['edit_media'] = array(
        '#type' => 'submit',
        '#attributes' => array(
          'id' => 'media_buttons_edit',
        ),
        '#submit' => array(
          'media_browser_plus_edit_multiple_redirect',
        ),
        '#validate' => array(
          'media_browser_plus_media_admin_validate',
        ),
        '#value' => t('Edit'),
      );
    }
    if (media_access('edit')) {

      // edit-submit
      $form['buttons']['delete_media'] = array(
        '#type' => 'submit',
        '#submit' => array(
          'media_browser_plus_delete_multiple_redirect',
        ),
        '#validate' => array(
          'media_browser_plus_media_admin_validate',
        ),
        '#value' => t('Delete'),
      );
    }
  }
  $form['buttons']['select_media'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'id' => 'media_buttons_select',
    ),
    '#value' => t('Add to Media Basket'),
  );
  if ($library_mode && !$multiselect) {

    // Remove select/deselect all.
    unset($form['buttons']['selection_assets']);

    // Change "Add to media basket" to process with selection.
    $form['buttons']['select_media'] = _media_browser_plus_media_basket_select_button();
  }
  $options = array(
    array(
      'categories' => array(
        'data' => drupal_render($form['admin']['folder']),
      ),
      'media' => array(
        'data' => '<div class="media-display-thumbnails media-clear clearfix">' . '<ul class="media-list-thumbnails" id="media-thumb-list" style="height: ' . variable_get('media_grid_window_height') . 'px;">' . '</ul></div>',
      ),
    ),
    array(
      'categories' => array(
        'data' => '',
      ),
      'media' => array(
        'data' => '',
        'id' => array(
          'media_browser_plus_pages',
        ),
      ),
    ),
  );

  // If no library mode with single selection add media basket buttons.
  if (!$library_mode || $multiselect) {
    $options[] = array(
      'categories' => array(
        'data' => '',
      ),
      'media' => array(
        'data' => drupal_render($form['buttons']),
        'id' => array(
          'media_browser_plus_selection_panel',
        ),
      ),
    );
  }

  // Table setup.
  $table = array(
    'header' => $header,
    'rows' => $options,
    'attributes' => array(
      'id' => 'media_folder_table',
    ),
    'empty' => t('No media added yet.'),
  );

  // Return themed table.
  $output = array(
    '#type' => 'markup',
    '#markup' => theme('table', $table),
    'buttons' => $form['buttons'],
  );
  if ($library_mode && !$multiselect) {
    $output['#markup'] .= drupal_render($form['buttons']);
  }
  return $output;
}

/**
 * Returns default javascript settings.
 */
function media_browser_plus_main_view_javascript_settings() {
  global $base_url;

  // Gather enviroment data.
  $path = drupal_get_path('module', 'media_browser_plus');
  $url = $base_url . base_path();

  // Create default settings.
  $settings = array(
    'media_browser_plus' => array(
      'filter_active' => isset($_SESSION['media-filter']),
      'url' => $url,
      'images_url' => $base_url . '/' . $path . '/images/',
      'page' => isset($_GET['page']) ? $_GET['page'] : 0,
      'per_page' => variable_get('media_media_per_page'),
      'page_items_per_page' => variable_get('media_page_items_per_page'),
      'folder_management_url' => url('admin/content/media/folder_list'),
      'multiselect' => TRUE,
      // texts
      'messages' => array(
        'only_one_selection_allowed' => t('Only one media item may be selected'),
      ),
      // access settings
      'folder_dnd_enabled' => media_access('edit'),
      'manage_folders' => media_access('edit folders'),
      'filter_allowed' => media_access('filter'),
      'add_files' => media_access('upload'),
    ),
  );
  return $settings;
}

/**
 * Appends the media basket.
 */
function media_browser_plus_media_basket_form($library_mode = FALSE) {
  $header = array(
    array(
      'data' => t('Media Basket'),
    ),
  );
  $form['basket_actions'] = array();
  $form['basket_actions']['selection_assets'] = array(
    '#type' => 'markup',
    '#markup' => '<a href="#media_basket_table" id="media_basket_remove_all" >' . t('Remove All') . '</a>',
  );
  if ($library_mode) {
    $form['basket_actions']['select'] = _media_browser_plus_media_basket_select_button();
  }
  else {
    if (media_access('download')) {
      $form['basket_actions']['download'] = array(
        '#type' => 'submit',
        '#value' => t('Download'),
        '#attributes' => array(
          'id' => 'perform_download',
        ),
        '#limit_validation_errors' => array(),
        '#validate' => array(
          'media_browser_plus_media_admin_validate',
        ),
        '#submit' => array(
          'media_browser_plus_download_images_submit',
        ),
      );
    }
  }
  $options = array(
    array(
      'media' => array(
        'data' => '<ul id="media-basket-list" class="media-list-thumbnails"></ul>',
      ),
    ),
    array(
      'media' => array(
        'data' => drupal_render($form['basket_actions']),
        'id' => array(
          'media_browser_plus_basket_panel',
        ),
      ),
    ),
  );
  $table = array(
    'header' => $header,
    'rows' => $options,
    'attributes' => array(
      'id' => 'media_basket_table',
    ),
    'empty' => t('No media added yet.'),
  );
  return array(
    '#type' => 'markup',
    '#markup' => theme('table', $table),
    'basket_actions' => $form['basket_actions'],
  );
}

/**
 * Appends the hidden preview form.
 */
function media_browser_plus_media_preview_form() {
  $header = array(
    array(
      'data' => t('Media Preview'),
      'id' => array(
        'media-preview-label',
      ),
    ),
  );
  $form['preview_actions'] = array(
    'previous' => array(
      '#type' => 'submit',
      '#value' => t('previous'),
      '#attributes' => array(
        'id' => 'previous_preview_item',
      ),
    ),
    'select' => array(
      '#type' => 'submit',
      '#value' => t('Select'),
      '#attributes' => array(
        'id' => 'select_preview_item',
      ),
    ),
    'next' => array(
      '#type' => 'submit',
      '#value' => t('next'),
      '#attributes' => array(
        'id' => 'next_preview_item',
      ),
    ),
  );
  $options = array(
    array(
      'media' => array(
        'data' => '',
        'id' => array(
          'media_browser_plus_preview_content',
        ),
      ),
    ),
    array(
      'media' => array(
        'data' => drupal_render($form['preview_actions']),
        'id' => array(
          'media_browser_plus_preview_panel',
        ),
      ),
    ),
  );
  $table = array(
    'header' => $header,
    'rows' => $options,
    'attributes' => array(
      'id' => 'media-preview-table',
    ),
    'empty' => t('No media added yet.'),
  );
  return array(
    '#type' => 'markup',
    '#markup' => '<div id="media-preview-table-container" style="display: none;">' . theme('table', $table) . '</div>',
    'preview_actions' => $form['preview_actions'],
  );
}

/**
 * @todo Document what this is for!
 *
 * @return array
 */
function _media_browser_plus_media_basket_select_button() {
  return array(
    '#type' => 'submit',
    '#value' => t('Continue with Selection'),
    '#attributes' => array(
      'id' => 'proceed_with_select',
    ),
    '#limit_validation_errors' => array(),
    '#validate' => array(
      'media_browser_plus_media_admin_validate',
    ),
  );
}

/**
 * Construct the path of a media_folder term.
 *
 * @param $term object containing term id and term name
 */
function media_browser_plus_construct_dir_path($term) {
  $file_default_scheme = variable_get('file_default_scheme', 'public') . ':/';
  if ($term) {
    $parents = array_reverse(taxonomy_get_parents_all($term->tid));
    $path = $file_default_scheme . '/';
    if (is_array($parents) && !empty($parents)) {
      foreach ($parents as $parent) {
        $path .= $parent->name . '/';
      }
    }
    $path = str_replace('Media Root', variable_get('media_root_folder', 'media'), $path);
    $dir_path = rtrim($path, '/');
  }
  return isset($dir_path) ? $dir_path : $file_default_scheme;
}

/**
 * Cut-paste a directory with its children into a new filesystem location.
 *
 * @param $source string the current folder path
 * @param $destination string the path we want the folder moved to
 */
function media_browser_plus_move_physical_folder($source, $destination) {
  $destination = drupal_realpath($destination);
  $source = drupal_realpath($source);
  $jail = drupal_realpath(variable_get('file_default_scheme', 'public') . '://');

  // @todo Please avoid an error by checking the preconditions instead.
  $files = @scandir($source);
  if ($files && count($files) > 2) {
    $transfer = new FileTransferLocal($jail);
    $transfer
      ->copyDirectory($source, $destination);
    $transfer
      ->removeDirectory($source);
  }
  else {

    // The folder is empty so just delete and create the new one.
    drupal_rmdir($source);
    file_prepare_directory($destination, FILE_CREATE_DIRECTORY);
  }
}

/**
 * Moves and saves permanently a media file.
 *
 * Every media file that is saved or updated,should pass through this to make
 * sure the filesystem location is the same with the folder term.
 *
 * @param $tid the folder's term id.
 * @param $media the media object.
 * @param $replace Replace behavior when the destination file already exists.
 */
function media_browser_plus_move_file($tid, $media, $replace = FILE_EXISTS_RENAME) {

  // Dont change the uri for media files with external source
  if (strpos($media->uri, 'public') === FALSE && strpos($media->uri, 'private') === FALSE) {
    file_save($media);
  }
  else {

    // media translation module does need this since it allows the creation of
    // file references which shouldn't move the referenced file itself when moved.
    // see http://drupal.org/node/1331818 for details.
    if (module_exists('media_translation') && media_translation_is_virtual_file($media->fid)) {
      file_save($media);
      return;
    }
    $folder = media_browser_plus_folder_load($tid);
    $path = media_browser_plus_construct_dir_path($folder);
    file_prepare_directory($path, FILE_CREATE_DIRECTORY);
    $destination = $path . '/' . $media->filename;
    file_move($media, $destination, $replace);
  }
}

Functions

Namesort descending Description
media_browser_plus_access Manages access for media browser plus actions.
media_browser_plus_change_folder Called by the JS fronted (ajax) to change the folder of a media object.
media_browser_plus_construct_dir_path Construct the path of a media_folder term.
media_browser_plus_delete_multiple_redirect Enter description here
media_browser_plus_download_images_submit Puts all selected media items into a zip archive and sends it as download.
media_browser_plus_edit_cancel @todo Document what this function does.
media_browser_plus_edit_file_submit Form submit handler for the media browser forms that edit media entities.
media_browser_plus_edit_multiple_redirect Enter description here
media_browser_plus_field_attach_presave Implements hook_field_attach_presave().
media_browser_plus_file_delete Deleting all field data attached to the media entity.
media_browser_plus_file_download_access Checks if the user has the permission to download a file.
media_browser_plus_file_download_access_alter Revokes the general 'view media' == 'download media' access rule.
media_browser_plus_folder_load Implements of hook_load().
media_browser_plus_form_media_add_upload_alter Implements hook_form_FORM_ID_alter().
media_browser_plus_form_media_add_upload_multiple_alter Implements hook_form_FORM_ID_alter().
media_browser_plus_form_media_admin_alter Alter the media browser from to enable new UI
media_browser_plus_form_media_edit_alter Implements hook_form_FORM_ID_alter().
media_browser_plus_form_media_import_alter Implements hook_form_FORM_ID_alter().
media_browser_plus_form_media_internet_add_alter Implements hook_form_FORM_ID_alter().
media_browser_plus_get_media_root_folder Loads and (if $autocreate is set) creates the default media folder object.
media_browser_plus_grid_view_form Appends main grid view form.
media_browser_plus_library Implements hook_library().
media_browser_plus_library_browser Creates the Extended Library for the media browser popup.
media_browser_plus_load_multiple Loads media entities and allows filtering, sorting and paging.
media_browser_plus_load_tag_terms @todo Document what this funciont does.
media_browser_plus_main_view_javascript_settings Returns default javascript settings.
media_browser_plus_media_access Checks access to a given media entity.
media_browser_plus_media_admin_folder_change_submit Changes the folder of the submitted media items.
media_browser_plus_media_admin_validate Enter description here
media_browser_plus_media_basket_form Appends the media basket.
media_browser_plus_media_browser_plugins_alter Remove the old Library for the media browser popup.
media_browser_plus_media_browser_plugin_info Implements hook_media_browser_plugin_info().
media_browser_plus_media_browser_plugin_view Implements hook_media_browser_plugin_view().
media_browser_plus_media_import_batch_complete Same completed batch method as in media.
media_browser_plus_media_import_batch_import_files Batch process that only differs in the ability to apply the field values to the items
media_browser_plus_media_import_submit Changing the media import standard submit to use our own batch process.
media_browser_plus_media_operations Implements hook_media_operations().
media_browser_plus_media_preview_form Appends the hidden preview form.
media_browser_plus_media_settings Creates the media browser plus settings form.
media_browser_plus_media_settings_submit Saves the entered settings.
media_browser_plus_media_settings_validate Validates the settings.
media_browser_plus_menu Implements hook_menu().
media_browser_plus_menu_alter Implements hook_menu_alter().
media_browser_plus_move_file Moves and saves permanently a media file.
media_browser_plus_move_physical_folder Cut-paste a directory with its children into a new filesystem location.
media_browser_plus_permission Implements hook_permission().
media_browser_plus_prepare_taxonomy_autocomplete_validate Form element validate handler for taxonomy term autocomplete element.
media_browser_plus_preprocess_media_link Implements hook_preprocess_media_link().
media_browser_plus_preprocess_media_thumbnail Implements hook_preprocess_media_thubmnail().
media_browser_plus_submit Submit handler for the media browser forms that create new media entities.
media_browser_plus_thumbnailsJSON Called by the JS fronted (ajax) to get the media list for a given folder.
_media_browser_plus_create_relationship_list @todo Document what this function does.
_media_browser_plus_filter_folders Looks if a filter is active and filters the folders accordingly.
_media_browser_plus_filter_folder_access @todo Document what this function does.
_media_browser_plus_folder_empty Check if a given folder has media in it (does include current filter)
_media_browser_plus_folder_form Returns a select form item with a selectable media folders.
_media_browser_plus_folder_hierarchy_list Creates the folder media tree.
_media_browser_plus_folder_hierarchy_list_helper @todo Document what this function does.
_media_browser_plus_folder_list @todo Document what this function does.
_media_browser_plus_has_unsorted_media Checks for unsorted (i.e. media not in folders) media.
_media_browser_plus_media_admin_list_alter Alter the media list display.
_media_browser_plus_media_basket_select_button @todo Document what this is for!
_media_browser_plus_metadata Helper function to return metadata from a 3rd party media provider.
_media_browser_plus_pager @todo Document what this function does.
_media_browser_plus_pager_add_page_item @todo Document what this function does.
_media_browser_plus_tag_form Returns the tag form element.