js_injector.module in JS injector 7
Same filename and directory in other branches
Allows administrators to inject JS into the page output based on configurable rules. Useful for adding simple JS tweaks without modifying a site's official theme.
File
js_injector.moduleView source
<?php
/**
* @file
* Allows administrators to inject JS into the page output based on
* configurable rules. Useful for adding simple JS tweaks without modifying
* a site's official theme.
*/
/**
* Deploy this JS snippet on every page except the listed pages.
*/
define('JS_INJECTOR_PAGES_NOTLISTED', 0);
/**
* Deploy this JS snippet on only the listed pages.
*/
define('JS_INJECTOR_PAGES_LISTED', 1);
/**
* Deploy this JS snippet only if the associated PHP code returns TRUE.
*/
define('JS_INJECTOR_PHP', 2);
/**
* Implements hook_help().
*/
function js_injector_help($path, $arg) {
$output = '';
switch ($path) {
case 'admin/config/modules#description':
$output .= t('Allows administrators to inject JS into the page output based on configurable rules.');
break;
case 'admin/config/development/js-injector':
$output .= '<p>' . t('Use JS injection rules to add small snippets of JS to the page output when specific criteria are met. For example, a simple rule could change the page background color at night or float a particular div to the right on node editing pages.') . '</p>';
break;
}
return $output;
}
/**
* Implements hook_init().
* Checks to see whether any JS files should be added to the current page,
* based on rules configured by the site administrator.
*/
function js_injector_init() {
$js_rules = _js_injector_load_rule();
foreach ($js_rules as $js_rule) {
if (_js_injector_evaluate_rule($js_rule)) {
$filepath = _js_injector_rule_path($js_rule['crid']);
drupal_add_js($filepath, array(
'type' => 'file',
'group' => JS_THEME,
'media' => $js_rule['media'],
'preprocess' => $js_rule['preprocess'],
));
}
}
}
/**
* Implements hook_js_alter().
* Since we're trying to give the administrator complete control, we'll move
* JS that this module has added to a high weight, higher even than the theme's
* JS files. Currently the weight is 200 + the crid, which is currently higher
* than Bartik's JS.
*
* @param $js
* The array of JS files.
*/
function js_injector_js_alter(&$js) {
$js_rules = _js_injector_load_rule();
foreach ($js_rules as $js_rule) {
$filepath = _js_injector_rule_path($js_rule['crid']);
if (!empty($js[$filepath])) {
$js[$filepath]['weight'] = 200 + $js_rule['crid'];
}
}
}
/**
* Implements hook_menu().
* Defines menu callbacks for JS Injector's configuration pages.
*/
function js_injector_menu() {
$items = array(
'admin/config/development/js-injector' => array(
'title' => 'JS injector',
'description' => 'Add JS to the page output based on configurable rules.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'js_injector_admin_form',
),
'access arguments' => array(
'administer js injection',
),
'file' => 'js_injector.admin.inc',
),
'admin/config/development/js-injector/edit' => array(
'title' => 'Edit JS injector rule',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'js_injector_edit',
),
'access arguments' => array(
'administer js injection',
),
'file' => 'js_injector.admin.inc',
'type' => MENU_CALLBACK,
),
'admin/config/development/js-injector/add' => array(
'title' => 'Add JS injector rule',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'js_injector_edit',
),
'access arguments' => array(
'administer js injection',
),
'file' => 'js_injector.admin.inc',
'type' => MENU_CALLBACK,
),
'admin/config/development/js-injector/delete' => array(
'title' => 'Delete JS injector rule',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'js_injector_delete_confirm',
),
'access arguments' => array(
'administer js injection',
),
'file' => 'js_injector.admin.inc',
'type' => MENU_CALLBACK,
),
);
return $items;
}
/**
* Implements hook_theme().
*/
function js_injector_theme() {
$items['js_injector_admin_form'] = array(
'render element' => 'form',
'file' => 'js_injector.admin.inc',
);
return $items;
}
/**
* Implements hook_permission().
*/
function js_injector_permission() {
return array(
'administer js injection' => array(
'title' => t('Administer JS Injection'),
),
);
}
/**
* Helper function to load all JS injection rules.
*/
function _js_injector_load_rule($crid = NULL, $reset = FALSE) {
static $rules;
// TODO: Change to drupal_static_fast pattern.
if (!isset($rules) || $reset) {
if (!$reset && ($cache = cache_get('js_injector:rules')) && !empty($cache->data)) {
$rules = $cache->data;
}
else {
$rules = array();
$results = db_query("SELECT * FROM {js_injector_rule}", array(), array(
'fetch' => PDO::FETCH_ASSOC,
))
->fetchAllAssoc('crid');
foreach ($results as $id => $rule) {
$rules[$id] = $rule;
}
cache_set('js_injector:rules', $rules);
}
}
if (is_numeric($crid)) {
return $rules[$crid];
}
else {
return $rules;
}
}
/**
* Helper function to delete an existing rule and its accompanying file.
*/
function _js_injector_delete_rule($crid) {
if ($rule = _js_injector_load_rule($crid)) {
file_unmanaged_delete(_js_injector_rule_path($crid));
db_delete('js_injector_rule')
->condition('crid', $crid)
->execute();
drupal_set_message(t('The JS rule %title has been deleted.', array(
'%title' => $rule['title'],
)));
}
}
/**
* Helper function to determine whether a rule's conditions are met.
*
* @param $js_rule
* Array describing the rule.
*/
function _js_injector_evaluate_rule($js_rule = array()) {
// Match path if necessary.
if (!empty($js_rule['rule_conditions'])) {
if ($js_rule['rule_type'] < JS_INJECTOR_PHP) {
$path = drupal_get_path_alias($_GET['q']);
// Compare with the internal and path alias (if any).
$page_match = drupal_match_path($path, $js_rule['rule_conditions']);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $js_rule['rule_conditions']);
}
// When $js_rule['rule_type'] has a value of
// JS_INJECTOR_PAGES_NOTLISTED, the rule is matched on
// all pages except those listed in $js_rule['rule_conditions'].
// When set to JS_INJECTOR_PAGES_LISTED, it is displayed only on those
// pages listed in $js_rule['rule_type'].
$page_match = !($js_rule['rule_type'] xor $page_match);
}
else {
if (module_exists('php')) {
$page_match = php_eval($js_rule['rule_conditions']);
}
else {
$page_match = FALSE;
}
}
}
else {
$page_match = TRUE;
}
return $page_match;
}
/**
* Helper function to get file path for a rule.
* This will get the path relative to DRUPAL_ROOT,
* as in 'sites/default/files/js_injector/js_injector_99.js'.
*
* @param $crid
* The integer identifying the JS Rule ID (crid)
*/
function _js_injector_rule_path($crid) {
if (!empty($crid)) {
$local_path = drupal_realpath(_js_injector_rule_uri($crid));
// Now remove the part before the drupal root.
// The +1 gets rid of the leading '/'.
$local_path = substr_replace($local_path, '', 0, strlen(DRUPAL_ROOT) + 1);
return $local_path;
}
return NULL;
}
/**
* Return the URI for a crid.
* @param $crid
* The integer identifying the JS Rule ID (crid)
*/
function _js_injector_rule_uri($crid) {
if (!empty($crid)) {
$uri = 'public://js_injector/js_injector_' . $crid . '.js';
return $uri;
}
}
Functions
Name | Description |
---|---|
js_injector_help | Implements hook_help(). |
js_injector_init | Implements hook_init(). Checks to see whether any JS files should be added to the current page, based on rules configured by the site administrator. |
js_injector_js_alter | Implements hook_js_alter(). Since we're trying to give the administrator complete control, we'll move JS that this module has added to a high weight, higher even than the theme's JS files. Currently the weight is 200 + the crid, which… |
js_injector_menu | Implements hook_menu(). Defines menu callbacks for JS Injector's configuration pages. |
js_injector_permission | Implements hook_permission(). |
js_injector_theme | Implements hook_theme(). |
_js_injector_delete_rule | Helper function to delete an existing rule and its accompanying file. |
_js_injector_evaluate_rule | Helper function to determine whether a rule's conditions are met. |
_js_injector_load_rule | Helper function to load all JS injection rules. |
_js_injector_rule_path | Helper function to get file path for a rule. This will get the path relative to DRUPAL_ROOT, as in 'sites/default/files/js_injector/js_injector_99.js'. |
_js_injector_rule_uri | Return the URI for a crid. |
Constants
Name | Description |
---|---|
JS_INJECTOR_PAGES_LISTED | Deploy this JS snippet on only the listed pages. |
JS_INJECTOR_PAGES_NOTLISTED | Deploy this JS snippet on every page except the listed pages. |
JS_INJECTOR_PHP | Deploy this JS snippet only if the associated PHP code returns TRUE. |