Source: src/modules/image/image.js



// Holds onto the phonegap getPicture success image data. It is keyed by field
// name, then delta value.
var image_phonegap_camera_options = {};

/**
 * Implements hook_field_formatter_view().
 /**
 * Implements hook_field_formatter_view().
 * @param {String} entity_type
 * @param {Object} entity
 * @param {Object} field
 * @param {Object} instance
 * @param {String} langcode
 * @param {Object} items
 * @param {*} display
 * @return {Object}
 */
function image_field_formatter_view(entity_type, entity, field, instance,
  langcode, items, display) {
  try {
    var element = {};
    // Toss on the default image if we one is specified and we have no items.
    // "In addition, any code which programmatically generates a link to an
    // image derivative without using the standard image_style_url() API
    // function will no longer work correctly if the image does not already
    // exist in the file system, since the necessary token will not be present
    // in the URL." @see http://drupal.stackexchange.com/a/76827/10645
    if (empty(items) && instance.settings.default_image) {
      items = [{
          uri: instance.settings.default_image_uri
      }];
    }
    if (!empty(items)) {
      for (var delta in items) {
          if (!items.hasOwnProperty(delta)) { continue; }
          var item = items[delta];
          var theme = empty(display.settings.image_style) ?
            'image' : 'image_style';
          var image = {
            theme: theme,
            alt: item.alt,
            title: item.title
          };
          if (theme == 'image_style') {
            image.style_name = display.settings.image_style;
            image.path = item.uri;
          }
          else { image.path = drupalgap_image_path(item.uri); }
          element[delta] = image;
      }
    }
    return element;
  }
  catch (error) { console.log('image_field_formatter_view - ' + error); }
}

/**
 * Implements hook_field_widget_form().
 * @param {Object} form
 * @param {Object} form_state
 * @param {Object} field
 * @param {Object} instance
 * @param {String} langcode
 * @param {Object} items
 * @param {Number} delta
 * @param {Object} element
 */
function image_field_widget_form(form, form_state, field, instance, langcode,
  items, delta, element) {
  try {
    // Change the item type to a hidden input to hold the file id.
    items[delta].type = 'hidden';

    // If we're dealing with the user profile 'picture' it isn't a real field,
    // so we need to spoof some field settings to get the widget to render
    // properly.
    // @TODO the field label doesn't show up.
    if (form.id == 'user_profile_form' && element.name == 'picture') {
      field = { field_name: 'picture' };
    }

    // If we already have an image for this item, show it.
    if (typeof items[delta].item !== 'undefined' && items[delta].item.fid) {
      // Set the hidden input's value equal to the file id.
      items[delta].value = items[delta].item.fid;
      // Show the image on the form, the file name as a link to the actual file,
      // the file size, and a remove button.
      var path = drupalgap_image_path(items[delta].item.uri);
      // @TODO - show the filesize.
      // @TODO - show the remove button.
      var html = theme('image', { path: path }) +
        '<div class="filename">' +
          l(items[delta].item.filename, path, { InAppBrowser: true }) +
        '</div>';
        /*theme('button_link', {
            text: 'Remove',
            path: null,
            attributes: {
              onclick: "_image_field_widget_form_remove_image()",
              'data-icon': 'delete',
              'data-iconpos': 'right'
            }
        });*/
        //'<div class="filesize">(' + items[delta].item.filesize + ')</div>';
      // Add html to the item's children.
      items[delta].children.push({markup: html});
      return; // No further processing required.
    }

    // Set the default button text, and if a value was provided,
    // overwrite the button text.
    var button_text = t('Take Photo');
    if (items[delta].value) { button_text = items[delta].value; }
    var browse_button_text = t('Browse');
    if (items[delta].value2) { browse_button_text = items[delta].value2; }

    // Place variables into document for PhoneGap image processing.
    var item_id_base = items[delta].id.replace(/-/g, '_');
    var image_field_source = item_id_base + '_imagefield_source';
    var imagefield_destination_type =
      item_id_base + '_imagefield_destination_type';
    var imagefield_data = item_id_base + '_imagefield_data';
    eval('var ' + image_field_source + ' = null;');
    eval('var ' + imagefield_destination_type + ' = null;');
    eval('var ' + imagefield_data + ' = null;');
    // Build an imagefield widget with PhoneGap. Contains a message
    // div, an image item, a button to add an image, and a button to browse for
    // images.
    var browse_button_id = items[delta].id + '-browse-button';
    var html = '<div>' +
      '<div id="' + items[delta].id + '-imagefield-msg"></div>' +
      '<img id="' + items[delta].id + '-imagefield" style="display: none;" />' +
      '<a href="#" data-role="button" data-icon="camera" ' +
        'id="' + items[delta].id + '-button">' +
        button_text +
      '</a>' +
      '<a href="#" data-role="button" data-icon="grid" ' +
        'id="' + browse_button_id + '">' +
        browse_button_text +
      '</a>' +
    '</div>';
    // Open extra javascript declaration.
    html += '<script type="text/javascript">';
    // Add device ready listener for PhoneGap camera.
    var event_listener = item_id_base + '_imagefield_ready';
    html += '$("#' + drupalgap_get_page_id(
      drupalgap_path_get()) + '").on("pageshow",function(){' +
        'document.addEventListener(' +
        '"deviceready", ' +
        event_listener + ', ' +
        'false);' +
      '});' +
    'function ' + event_listener + '() {' +
      image_field_source + ' = navigator.camera.PictureSourceType;' +
      imagefield_destination_type + ' = navigator.camera.DestinationType;' +
    '}';
    // Define error callback function.
    var imagefield_error = item_id_base + '_error';
    html += 'function ' + imagefield_error + '(message) {' +
      'if (message != "Camera cancelled." && ' +
        'message != "Selection cancelled." && ' +
        'message != "no image selected")' +
      '{' +
        'console.log("' + imagefield_error + '");' +
        'drupalgap_alert(message);' +
      '}' +
    '}';
    // Define success callback function.
    var imagefield_success = item_id_base + '_success';
    html += 'function ' + imagefield_success + '(imageData) {' +
      '_image_phonegap_camera_getPicture_success(' +
      '{field_name:"' + field.field_name + '", ' +
        'image:imageData, id:"' + items[delta].id + '"' +
       '})' +
    '}';
    // Determine image quality.
    var quality = 50;
    if (drupalgap.settings.camera.quality) {
      quality = drupalgap.settings.camera.quality;
    }
    // Add click handler for photo button.
    html += '$("#' + items[delta].id + '-button").on("click",function(){' +
      'var photo_options = {' +
        'quality: ' + quality + ',' +
        'destinationType: ' + imagefield_destination_type + '.DATA_URL,' +
        'correctOrientation: true' +
      '};' +
      'navigator.camera.getPicture(' +
        imagefield_success + ', ' +
        imagefield_error + ', ' +
        'photo_options);' +
    '});';
    // Add click handler for browse button.
    html += '$("#' + browse_button_id + '").on("click",function(){' +
      'var browse_photo_options = {' +
        'quality: ' + quality + ',' +
        'sourceType: ' + image_field_source + '.PHOTOLIBRARY,' +
        'destinationType: ' + imagefield_destination_type + '.DATA_URL,' +
        'correctOrientation: true' +
      '};' +
      'navigator.camera.getPicture(' +
        imagefield_success + ', ' +
        imagefield_error + ', ' +
        'browse_photo_options);' +
    '});';
    // Close extra javascript declaration.
    html += '</script>';
    // Add html to the item's children.
    items[delta].children.push({markup: html});
  }
  catch (error) { console.log('image_field_widget_form - ' + error); }
}

/**
 * On an entity edit form, this removes an image file from the server, then from
 * the form elements and user interface.
 */
function _image_field_widget_form_remove_image() {
  try {
    alert('_image_field_widget_form_remove_image');
  }
  catch (error) {
    console.log('_image_field_widget_form_remove_image - ' + error);
  }
}

/**
 * Given an entity type and optional bundle name, this will return an array
 * containing any image field names present, false otherwise.
 * @param {String} entity_type
 * @param {String} bundle
 * @return {Object}
 */
function image_fields_present_on_entity_type(entity_type, bundle) {
  try {
    var results = [];
    var fields = drupalgap_field_info_instances(entity_type, bundle);
    if (!fields) { return false; }
    for (var name in fields) {
        if (!fields.hasOwnProperty(name)) { continue; }
        var field = fields[name];
        if (
          field.widget &&
          field.widget.type &&
          field.widget.type == 'image_image'
        ) { results.push(name); }
    }
    if (results.length == 0) { return false; }
    return results;
  }
  catch (error) {
    console.log('image_fields_present_on_entity_type - ' + error);
  }
}

/**
 * Implements hook_form_alter().
 * @param {Object} form
 * @param {Object} form_state
 * @param {String} form_id
 */
function image_form_alter(form, form_state, form_id) {
  try {
    // Make potential alterations to any entity edit form that has an image
    // field element(s).
    if (form.entity_type) {
      var bundle = form.bundle;
      var image_fields =
        image_fields_present_on_entity_type(form.entity_type, bundle);
      if (image_fields) {
        // Attach the image field names to the form for later reference.
        form.image_fields = image_fields;
        // For each image field, create a place for it in the global var.
        if ($.isArray(image_fields)) {
          for (var index in image_fields) {
              if (!image_fields.hasOwnProperty(index)) { continue; }
              var name = image_fields[index];
              image_phonegap_camera_options[name] = { 0: null };
          }
        }
      }
    }
  }
  catch (error) { console.log('image_form_alter - ' + error); }
}

/**
 * Given an image style name and image uri, this will return the absolute URL
 * that can be used as a src value for an img element.
 * @param {String} style_name
 * @param {String} path
 * @return {String}
 */
function image_style_url(style_name, path) {
  try {
    // @TODO - bug: the trailing slash on public and private is breaking images
    // that don't live in a sub directory in sites/default/files.
    var src =
      Drupal.settings.site_path + Drupal.settings.base_path + path;
    if (src.indexOf('public://') != -1) {
      src = src.replace(
        'public://',
        Drupal.settings.file_public_path +
          '/styles/' +
          style_name +
          '/public/'
      );
    }
    else if (src.indexOf('private://') != -1) {
      src = src.replace(
        'private://',
        Drupal.settings.file_private_path +
          '/styles/' +
          style_name +
          '/private/'
      );
    }
    return src;
  }
  catch (error) { console.log('image_style_url - ' + error); }
}

/**
 * The success callback function used when handling PhoneGap's camera
 * getPicture() call.
 * @param {Object} options
 */
function _image_phonegap_camera_getPicture_success(options) {
  try {

    // Hold on to the image options in the global var.
    image_phonegap_camera_options[options.field_name] = {0: options};

    // Hide the 'Add image' button and show the 'Upload' button.
    //$('#' + options.id + '-button').hide();
    //$('#' + options.id + '_upload').show();

    // Show the captured photo as a thumbnail. When the photo is loaded, resize
    // it to fit the content area, then show it.
    var image_element_id = options.id + '-imagefield';
    var image = document.getElementById(image_element_id);
    image.src = 'data:image/jpeg;base64,' +
      image_phonegap_camera_options[options.field_name][0].image;
    image.onload = function() {
      var width = this.width;
      var height = this.height;
      var ratio = width / drupalgap_max_width();
      var new_width = width / ratio;
      var new_height = height / ratio;
      image.width = new_width;
      image.height = new_height;
      $('#' + image_element_id).show();
    };
  }
  catch (error) {
    console.log('_image_phonegap_camera_getPicture_success - ' + error);
  }
}

/**
 * An internal function used to upload images to the server, retreive their file
 * id and then populate the corresponding form element's value with the file id.
 * @param {Object} form
 * @param {Object} form_state
 * @param {Object} options
 */
function _image_field_form_process(form, form_state, options) {
  try {
    // @TODO needs mutli value field support (delta)
    // @see https://www.drupal.org/node/2224803

    var lng = language_default();
    var processed_an_image = false;

    // For each image field on the form...
    for (var index in form.image_fields) {
      if (!form.image_fields.hasOwnProperty(index)) { continue; }
      var name = form.image_fields[index];

      // Skip empty images and ones that already have their field id set.
      if (!image_phonegap_camera_options[name][0] || form_state.values[name][lng][0] != '') { continue; }

      // Create a unique file name using the UTC integer value.
      var d = new Date();
      var image_file_name = Drupal.user.uid + '_' + d.valueOf() + '.jpg';

      // Build the data for the file create resource. If it's private, adjust the filepath.
      var image_file_path = form.elements[name].field_info_instance.settings.file_directory;
      if (image_file_path !== "") {
        image_file_path += "/";
      }
      var file = {
        file: {
          file: image_phonegap_camera_options[name][0].image,
          filename: image_file_name,
          filepath: 'public://' + image_file_path + image_file_name
        }
      };
      if (!empty(Drupal.settings.file_private_path)) {
        file.file.filepath = 'private://' + image_file_path + image_file_name;
      }

      // Change the loader mode to saving, and save the file.
      drupalgap.loader = 'saving';
      processed_an_image = true;
      file_save(file, {
          async: false,
          success: function(result) {
            try {
              // Set the hidden input and form state values with the file id.
              var element_id = drupalgap_form_get_element_id(name, form.id);
              $('#' + element_id).val(result.fid);
              form_state.values[name][lng][0] = result.fid;
              if (options.success) { options.success(); }
            }
            catch (error) {
              console.log('_image_field_form_process - success - ' + error);
            }
          }
      });
    }

    // If no images were processed, we need to continue onward anyway.
    if (!processed_an_image && options.success) { options.success(); }
  }
  catch (error) { console.log('_image_field_form_validate - ' + error); }
}

/**
 * Implements hook_assemble_form_state_into_field().
 * @param {Object} entity_type
 * @param {String} bundle
 * @param {String} form_state_value
 * @param {Object} field
 * @param {Object} instance
 * @param {String} langcode
 * @param {Number} delta
 * @param {Object} field_key
 * @return {*}
 */
function image_assemble_form_state_into_field(entity_type, bundle,
  form_state_value, field, instance, langcode, delta, field_key) {
  try {
    field_key.value = 'fid';
    return form_state_value;
  }
  catch (error) {
    console.log('image_assemble_form_state_into_field - ' + error);
  }
}