You are here

angularjs.module in AngularJS 7

File

angularjs.module
View source
<?php

define('ANGULARJS_DEFAULT_VERSION', '1.0.8');
define('ANGULARJS_CDN_URL', 'https://ajax.googleapis.com/ajax/libs/angularjs');

/**
 * Implements hook_page_delivery_callback_alter().
 */
function angularjs_page_delivery_callback_alter(&$callback) {

  // pjax requests can be detected by the X-PJAX http header.
  // When serving pjax requests, deliver just the main page content.
  if (!empty($_SERVER['HTTP_X_ANGULARJS']) && $callback == 'drupal_deliver_html_page') {
    $callback = 'angularjs_deliver_page_content';
  }
}

/**
 * Delivers only the main content of the requested page, for pjax requests.
 */
function angularjs_deliver_page_content($page_callback_result) {
  if (is_int($page_callback_result)) {

    // Pass over to drupal_deliver_html_page() to deal with errors.
    drupal_deliver_html_page($page_callback_result);
  }
  else {
    if (is_null(drupal_get_http_header('Content-Type'))) {
      drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
    }

    // $page_callback_result contains the main contents of the page.
    // Add a page title, which will be picked up and used by pjax.
    $output = '<title>' . drupal_get_title() . '</title>' . render($page_callback_result);
    $output .= drupal_get_js();
    print $output;

    // Make sure the requests are cached. pajax requests will be cached separately
    // from standard page requests thanks to the "_pjax" query string.
    drupal_page_footer();
  }
}

/**
 * Implements hook_help().
 */
function angularjs_help($path, $arg) {
  switch ($path) {
    case 'admin/config/development/angularjs':
      return '<p>' . t('Configure what files <a href="@angularjs">AngularJS</a> are loaded onto the site. Select which AngularJS version, the compression level and whether or not to use a CDN.', array(
        '@jquery' => 'http://angularjs.com',
      )) . '</p>';
  }
}

/**
 * Implements hook_menu
 */
function angularjs_menu() {
  $items = array();
  $items['admin/config/development/angularjs'] = array(
    'title' => t('AngularJS'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'angularjs_settings_form',
    ),
    'file' => 'angularjs.admin.inc',
    'access arguments' => array(
      'administer angularjs',
    ),
    'description' => 'Configure settings related to the AngularJS library',
  );
  return $items;
}

/**
 * Returns a list of all current AngularJS versions
 * 
 * @param boolean $reset  Whether to reset the cache
 * @return array
 */
function angularjs_version_options($reset = FALSE) {
  $cid = 'angularjs:versions';
  if (!$reset && ($cache = cache_get($cid)) && !empty($cache->data)) {
    $data = $cache->data;
  }
  else {
    $result = drupal_http_request('https://code.angularjs.org/');
    $re = "/href=\"([0-9][0-9\\.a-z\\-]+)\\/\"/";
    if (TRUE === isset($result->data)) {
      preg_match_all($re, $result->data, $matches);
      if ($matches && 2 == sizeof($matches)) {
        $data = $matches[1];
        cache_set($cid, $data);
      }
    }
  }
  return drupal_map_assoc($data);
}

/**
 * Provides a list of files that are part of the selected version of AngularJS
 *
 * @param string $version          
 * @return array
 */
function angularjs_version_files($version = NULL, $reset = FALSE) {
  $data = array();
  if ($version) {
    $cid = 'angularjs:versions:' . $version;
    if (!$reset && ($cache = cache_get($cid)) && !empty($cache->data)) {
      $data = $cache->data;
    }
    else {
      $result = drupal_http_request('https://code.angularjs.org/' . $version);
      if (FALSE === isset($result->error)) {
        $re = "/href=\"([a-z][a-z\\-\\.0-9]+)(?<!min).js\"/";
        preg_match_all($re, $result->data, $matches);
        if ($matches && 2 == sizeof($matches)) {
          $data = $matches[1];

          // Make sure we don't list the basic library
          $angular_position = array_search('angular', $data);
          if (FALSE !== $angular_position) {
            unset($data[$angular_position]);
          }
          cache_set($cid, $data);
        }
      }
    }
  }
  return $data;
}

/**
 * Implements hook_permission
 */
function angularjs_permission() {
  return array(
    'administer angularjs' => array(
      'title' => t('Administer AngularJS'),
      'description' => t('Perform administration for AngularJS'),
    ),
  );
}

/**
 * Implements hook_library().
 */
function angularjs_library() {
  $libraries = array();
  $library_path = libraries_get_path('angular');
  $version = variable_get('angularjs_version', ANGULARJS_DEFAULT_VERSION);
  $files = variable_get('angularjs_files', array());
  $compression = variable_get('angularjs_compression_type', 'min');
  $cdn = TRUE == variable_get('angularjs_cdn', '0');

  // Get correct extension
  $extension = FALSE === empty($compression) ? $compression . '.js' : 'js';
  $path = FALSE == $cdn ? $library_path : ANGULARJS_CDN_URL . '/' . $version;
  $js = array(
    $path . '/angular.' . $extension => array(
      'external' => $cdn,
    ),
  );

  // Add selected files
  foreach ($files as $file) {
    $js[$path . '/' . $file . '.' . $extension] = array(
      'external' => $cdn,
    );
  }

  // Load module types exposed by modules
  foreach (array(
    'controllers',
    'filters',
    'directives',
    'services',
  ) as $type) {
    foreach (angularjs_get_modules($type, FALSE, $version) as $path => $options) {
      $js[$path] = $options;
    }
  }
  $libraries['angularjs'] = array(
    'title' => 'AngularJS',
    'website' => 'angularjs.org',
    'version' => $version,
    'js' => $js,
  );

  // Add CSRF token required by restWS.
  $js_settings = array(
    'angularjsApp' => array(
      'restws_csrf_token' => drupal_get_token('restws'),
      'basePath' => url('', array(
        'absolute' => TRUE,
      )),
    ),
  );
  drupal_add_js($js_settings, 'setting');
  return $libraries;
}

/**
 * Initializes an AngularJS application setting the application name, the base path
 * and adds the library
 *
 * @param string $name
 *          The application name
 *          
 * @param string $base_href
 *          The base href, defaults to current page if nothing is entered
 */
function angularjs_init_application($name, $base_href = NULL) {

  // If no value is entered use the current URL
  if (NULL == $base_href) {
    $base_href = url($_GET['q']) . '/';
  }
  angularjs_set_app_name($name);
  angularjs_set_base_href($base_href);
  drupal_add_library('angularjs', 'angularjs');
}

/**
 * Gets the AngularJS application name for the current request / page
 *
 * @return string
 */
function angularjs_get_app_name() {
  return drupal_static('angularjs_app_name');
}

/**
 * Sets AngularJS application name for the current request / page
 *
 * @param string $app_name
 *          The application name
 *          
 * @return string
 */
function angularjs_set_app_name($app_name) {
  $name =& drupal_static('angularjs_app_name');
  $name = $app_name;
  return $name;
}

/**
 * Gets the current base tag
 *
 * @return string
 */
function angularjs_get_base_href() {
  return drupal_static('angularjs_base_href');
}

/**
 * Sets the current base tag
 *
 * @param string $base_href
 *          The base href for the application
 *          
 * @return string
 */
function angularjs_set_base_href($base_href) {
  $href =& drupal_static('angularjs_base_href');
  $href = $base_href;
  return $href;
}

/**
 * Implements hook_preprocess_html
 *
 * Adds <base> tag and sets ng-app attribute if provided
 */
function angularjs_preprocess_html(&$vars) {
  $app_name = angularjs_get_app_name();
  $base_href = angularjs_get_base_href();
  if (FALSE === empty($app_name)) {
    $vars['attributes_array']['ng-app'] = $app_name;
    $vars['html_attributes_array']['ng-app'] = $app_name;
  }
  if (FALSE === empty($base_href)) {
    drupal_add_html_head(array(
      '#tag' => 'base',
      '#attributes' => array(
        'href' => $base_href,
      ),
    ), 'angularjs_base_href');
  }
}

/**
 * Implements hook_element_info().
 */
function angularjs_element_info() {
  $types['ng_select'] = array(
    '#input' => TRUE,
    '#multiple' => FALSE,
    '#theme' => 'ng_select',
    '#theme_wrappers' => array(
      'form_element',
    ),
    '#process' => array(
      'form_process_select',
      'ajax_process_form',
      'angularjs_process_select',
    ),
    '#ng_model' => '',
    // @todo: Add option to look at parents(s) for the controller definition.
    '#ng_controller' => '',
    '#attached' => array(
      'library' => array(),
    ),
  );
  return $types;
}

/**
 * Implements hook_theme().
 */
function angularjs_theme() {
  return array(
    'ng_select' => array(
      'render element' => 'element',
    ),
    'ng_table' => array(
      'variables' => array(
        'header' => NULL,
        'attributes' => array(),
        'caption' => NULL,
        'sticky' => TRUE,
        'empty' => '',
        // Angular settings.
        'row' => array(),
        'ng_model' => '',
        'ng_controller' => '',
        'ng_repeat' => '',
        'ng_empty' => '',
      ),
    ),
  );
}

/**
 * Process ng-select element.
 */
function angularjs_process_select($element, $form_state) {

  // Pass the option to JS.
  $options = array();
  if (TRUE === isset($element['#options'])) {
    foreach ($element['#options'] as $value => $name) {
      $options[] = array(
        'value' => $value,
        'name' => $name,
      );
    }
  }
  if (TRUE === isset($element['#ng_controller'])) {
    $data['angularjs'][$element['#ng_controller']][$element['#ng_model']] = array(
      'options' => $options,
      'required' => $element['#required'],
      'selected' => $element['#default_value'],
      '_type' => 'select',
      '_name' => $element['#name'],
    );
    $element['#attached']['js'][] = array(
      'type' => 'setting',
      'data' => $data,
    );
  }
  return $element;
}

/**
 * Returns HTML for a ng-select form element.
 *
 * @ingroup themeable
 */
function theme_ng_select($variables) {
  $element = $variables['element'];
  element_set_attributes($element, array(
    'id',
    'name',
    'size',
  ));
  _form_set_class($element, array(
    'form-select',
  ));
  return '<select' . drupal_attributes($element['#attributes']) . ' ng-model="' . $element['#ng_model'] . '.selected" ng-options="option.value as option.name for option in ' . $element['#ng_model'] . '.options"></select> ';
}

/**
 * Returns HTML for a table, using AngularJs.
 */
function theme_ng_table($variables) {
  $header = $variables['header'];
  $row = $variables['row'];
  $attributes = $variables['attributes'];
  $caption = $variables['caption'];
  $sticky = $variables['sticky'];
  $empty = $variables['empty'];
  $ng_controller = $variables['ng_controller'];
  $ng_model = $variables['ng_model'];
  $ng_repeat = !empty($variables['ng_repeat']) ? $variables['ng_repeat'] : "item in {$ng_model}";
  $ng_empty = !empty($variables['ng_empty']) ? $variables['ng_empty'] : "!{$ng_model}.length";

  // Add sticky headers, if applicable.
  if (count($header) && $sticky) {
    drupal_add_js('misc/tableheader.js');

    // Add 'sticky-enabled' class to the table to identify it for JS.
    // This is needed to target tables constructed by this function.
    $attributes['class'][] = 'sticky-enabled';
  }
  $output = '<table' . drupal_attributes($attributes) . ">\n";
  if (isset($caption)) {
    $output .= '<caption>' . $caption . "</caption>\n";
  }

  // Add the 'empty' row message if available.
  if (empty($row) && $empty) {
    $header_count = 0;
    foreach ($header as $header_cell) {
      if (is_array($header_cell)) {
        $header_count += 1;
      }
      else {
        $header_count++;
      }
    }

    // @todo: Fix.
    $rows[] = array(
      array(
        'data' => $empty,
        'class' => array(
          'empty',
          'message',
        ),
      ),
    );
  }

  // Format the table header:
  if (count($header)) {

    // HTML requires that the thead tag has tr tags in it followed by tbody
    // tags. Using ternary operator to check and see if we have any rows.
    $output .= count($row) ? ' <thead><tr>' : ' <tr>';
    foreach ($header as $cell) {
      $output .= '<th>' . $cell . '</th>';
    }

    // Using ternary operator to close the tags based on whether or not there are rows
    $output .= count($row) ? " </tr></thead>\n" : "</tr>\n";
  }

  // Format the table rows:
  if (!empty($row)) {
    $output .= "<tbody>\n";

    // Build row
    $output .= ' <tr ng-repeat="' . $ng_repeat . '">';
    foreach ($row as $cell) {
      $output .= '<td>' . $cell . '</td>';
    }
    $output .= " </tr>\n";

    // Add empty-text <tr>.
    $output .= '<tr ng-show="' . $ng_empty . '"><td>' . $empty . '</td></tr>';
    $output .= "</tbody>\n";
  }
  $output .= "</table>\n";
  return $output;
}

/**
 * Returns the registered AngularJS modules
 *
 * @param string $type          
 * @param boolean $reset          
 * @param string $version          
 * @return array
 */
function angularjs_get_modules($type, $reset = FALSE, $version = NULL) {
  $name = 'angularjs_' . $type;
  $modules =& drupal_static($name, array());
  if (TRUE === empty($modules)) {
    $cached_modules = cache_get($name);
    if (FALSE === isset($cached_modules->data) || TRUE == $reset) {
      $modules = module_invoke_all($name, $version);
      drupal_alter($name, $modules, $version);
      cache_set($name, $modules);
    }
    else {
      $modules = $cached_modules->data;
    }
  }
  return $modules;
}

/**
 * Returns a list of AngularJS filters exposed by modules
 *
 * @param boolean $reset          
 * @param string $version          
 * @return array
 */
function angularjs_get_filters($reset = FALSE, $version = NULL) {
  return angularjs_get_modules('filters', $reset, $version);
}

/**
 * Returns a list of AngularJS directives exposed by modules
 *
 * @param boolean $reset          
 * @param string $version          
 * @return array
 */
function angularjs_get_directives($reset = FALSE, $version = NULL) {
  return angularjs_get_modules('directives', $reset, $version);
}

/**
 * Returns a list of AngularJS services exposed by modules
 *
 * @param boolean $reset          
 * @param string $version          
 * @return array
 */
function angularjs_get_services($reset = FALSE, $version = NULL) {
  return angularjs_get_modules('services', $reset, $version);
}

/**
 * Returns a list of AngularJS controllers exposed by modules
 *
 * @param boolean $reset          
 * @param string $version          
 * @return array
 */
function angularjs_get_controllers($reset = FALSE, $version = NULL) {
  return angularjs_get_modules('controllers', $reset, $version);
}

/**
 * Implements hook_angularjs_services
 *
 * @param string $version          
 * @return array
 */
function angularjs_angularjs_services($version = NULL) {
  return array(
    drupal_get_path('module', 'angularjs') . '/js/angular_resource.js' => array(),
  );
}

/**
 * Sends AngularJS template to browser
 *
 * @param string $var          
 */
function angularjs_template_output($var) {
  drupal_add_http_header('Content-Type', 'text/html');

  // Add new JS.
  echo drupal_get_js();
  if (isset($var)) {
    echo $var;
  }
}

/**
 * Adds an Angular JS template partial to be sent to the page.
 * Takes either a text
 * template or a render array
 *
 * @param string $name          
 * @param mixed $output          
 * @return array
 */
function angularjs_add_partial($name = NULL, $output = NULL) {
  $partials =& drupal_static(__FUNCTION__, array());
  if (NULL != $name) {
    $partials[$name] = $output;
  }
  return $partials;
}

/**
 * Implements hook_page_alter
 *
 * Adds partials to the page footer
 *
 * @param array $variables          
 */
function angularjs_page_alter(&$variables) {
  $partials = angularjs_add_partial();
  drupal_alter('angularjs_partials', $partials);
  foreach ($partials as $name => $output) {

    // If we have a render array render it
    if (TRUE === is_array($output)) {
      $output = render($output);
    }
    $element = array(
      '#tag' => 'script',
      '#value' => $output,
      '#attributes' => array(
        'type' => 'text/ng-template',
        'id' => $name,
      ),
    );
    $variables['footer']['partial_' . $name] = array(
      '#markup' => theme('html_tag', array(
        'element' => $element,
      )),
    );
  }
}

Functions

Namesort descending Description
angularjs_add_partial Adds an Angular JS template partial to be sent to the page. Takes either a text template or a render array
angularjs_angularjs_services Implements hook_angularjs_services
angularjs_deliver_page_content Delivers only the main content of the requested page, for pjax requests.
angularjs_element_info Implements hook_element_info().
angularjs_get_app_name Gets the AngularJS application name for the current request / page
angularjs_get_base_href Gets the current base tag
angularjs_get_controllers Returns a list of AngularJS controllers exposed by modules
angularjs_get_directives Returns a list of AngularJS directives exposed by modules
angularjs_get_filters Returns a list of AngularJS filters exposed by modules
angularjs_get_modules Returns the registered AngularJS modules
angularjs_get_services Returns a list of AngularJS services exposed by modules
angularjs_help Implements hook_help().
angularjs_init_application Initializes an AngularJS application setting the application name, the base path and adds the library
angularjs_library Implements hook_library().
angularjs_menu Implements hook_menu
angularjs_page_alter Implements hook_page_alter
angularjs_page_delivery_callback_alter Implements hook_page_delivery_callback_alter().
angularjs_permission Implements hook_permission
angularjs_preprocess_html Implements hook_preprocess_html
angularjs_process_select Process ng-select element.
angularjs_set_app_name Sets AngularJS application name for the current request / page
angularjs_set_base_href Sets the current base tag
angularjs_template_output Sends AngularJS template to browser
angularjs_theme Implements hook_theme().
angularjs_version_files Provides a list of files that are part of the selected version of AngularJS
angularjs_version_options Returns a list of all current AngularJS versions
theme_ng_select Returns HTML for a ng-select form element.
theme_ng_table Returns HTML for a table, using AngularJs.

Constants