Permalink
Browse files

feature(js): Adds hooks to pass site and page-level data client-side

Adds two hooks `"elgg.data"` that populate the object `elgg.data` available
in the `elgg` module.

Fixes #8997
  • Loading branch information...
mrclay committed Feb 15, 2016
1 parent f81bf02 commit cec6b42b2ec6b86bc3530f6233b7d8dfb8c05328
Showing with 146 additions and 46 deletions.
  1. +6 −0 docs/guides/hooks-list.rst
  2. +57 −5 docs/guides/javascript.rst
  3. +76 −0 engine/lib/views.php
  4. +6 −10 views/default/elgg.js.php
  5. +1 −31 views/default/initialize_elgg.js.php
@@ -117,6 +117,12 @@ System hooks
**add, river**
**elgg.data, site**
Filters cached configuration data to pass to the client. :ref:`More info <guides/javascript#config>`
**elgg.data, page**
Filters uncached, page-specific configuration data to pass to the client. :ref:`More info <guides/javascript#config>`
User hooks
==========
View
@@ -77,9 +77,62 @@ the greeting:
$('body').append(hello);
});
.. _guides/javascript#config:
Passing settings to modules
---------------------------
The ``elgg.data`` plugin hooks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``elgg`` module provides an object ``elgg.data`` which is populated from two server side hooks:
- **elgg.data, site**: This filters an associative array of site-specific data passed to the client and cached.
- **elgg.data, page**: This filters an associative array of uncached, page-specific data passed to the client.
Let's pass some data to a module:
.. code-block:: php
<?php
function myplugin_config_site($hook, $type, $value, $params) {
// this will be cached client-side
$value['myplugin']['api'] = elgg_get_site_url() . 'myplugin-api';
$value['myplugin']['key'] = 'none';
return $value;
}
function myplugin_config_page($hook, $type, $value, $params) {
$user = elgg_get_logged_in_user_entity();
if ($user) {
$value['myplugin']['key'] = $user->myplugin_api_key;
return $value;
}
}
elgg_register_plugin_hook_handler('elgg.data', 'site', 'myplugin_config_site');
elgg_register_plugin_hook_handler('elgg.data', 'page', 'myplugin_config_page');
.. code-block:: javascript
define(function(require) {
var elgg = require("elgg");
var api = elgg.data.myplugin.api;
var key = elgg.data.myplugin.key; // "none" or a user's key
// ...
});
.. note::
In ``elgg.data``, page data overrides site data. Also note ``json_encode()`` is used to copy
data client-side, so the data must be JSON-encodable.
Making a config module
^^^^^^^^^^^^^^^^^^^^^^
You can use a PHP-based module to pass values from the server. To make the module ``myplugin/settings``,
create the view file ``views/default/myplugin/settings.js.php`` (note the double extension
``.js.php``).
@@ -88,12 +141,11 @@ create the view file ``views/default/myplugin/settings.js.php`` (note the double
<?php
$settings = elgg_get_plugin_from_id('myplugin')->getAllSettings();
// this will be cached client-side
$settings = [
'foo' => elgg_extract('foo', $settings),
'bar' => elgg_extract('bar', $settings),
'api' => elgg_get_site_url() . 'myplugin-api',
'key' => null,
];
?>
define(<?php echo json_encode($settings); ?>);
@@ -669,7 +721,7 @@ The following example registers the ``handleFoo`` function for the ``foo, bar``
elgg.register_hook_handler('foo', 'bar', handleFoo);
return new Plugin();
});
});
The handler function
--------------------
View
@@ -1801,6 +1801,82 @@ function _elgg_manage_pagesetup($hook, $view, $value, $params) {
_elgg_services()->events->trigger('pagesetup', 'system');
}
/**
* Get the site data to be merged into "elgg" in elgg.js.
*
* Unlike _elgg_get_js_page_data(), the keys returned are literal expressions.
*
* @return array
* @access private
*/
function _elgg_get_js_site_data() {
$language = elgg_get_config('language');
if (!$language) {
$language = 'en';
}
return [
'elgg.data' => (object)elgg_trigger_plugin_hook('elgg.data', 'site', null, []),
'elgg.version' => elgg_get_version(),
'elgg.release' => elgg_get_version(true),
'elgg.config.wwwroot' => elgg_get_site_url(),
// refresh token 3 times during its lifetime (in microseconds 1000 * 1/3)
'elgg.security.interval' => (int)_elgg_services()->actions->getActionTokenTimeout() * 333,
'elgg.config.language' => $language,
];
}
/**
* Get the initial contents of "elgg" client side. Will be extended by elgg.js.
*
* @return array
* @access private
*/
function _elgg_get_js_page_data() {
$data = elgg_trigger_plugin_hook('elgg.data', 'page', null, []);
if (!is_array($data)) {
elgg_log('"elgg.data" plugin hook handlers must return an array. Returned ' . gettype($data) . '.', 'ERROR');
$data = [];
}
$elgg = array(
'config' => array(
'lastcache' => (int)elgg_get_config('lastcache'),
'viewtype' => elgg_get_viewtype(),
'simplecache_enabled' => (int)elgg_is_simplecache_enabled(),
),
'security' => array(
'token' => array(
'__elgg_ts' => $ts = time(),
'__elgg_token' => generate_action_token($ts),
),
),
'session' => array(
'user' => null,
),
'_data' => (object)$data,
);
if (elgg_get_config('elgg_load_sync_code')) {
$elgg['config']['load_sync_code'] = true;
}
$page_owner = elgg_get_page_owner_entity();
if ($page_owner instanceof ElggEntity) {
$elgg['page_owner'] = $page_owner->toObject();
}
$user = elgg_get_logged_in_user_entity();
if ($user instanceof ElggUser) {
$user_object = $user->toObject();
$user_object->admin = $user->isAdmin();
$elgg['session']['user'] = $user_object;
}
return $elgg;
}
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
$events->registerHandler('boot', 'system', 'elgg_views_boot');
$hooks->registerHandler('view_vars', 'all', '_elgg_manage_pagesetup', 1000);
View
@@ -68,19 +68,15 @@
echo "\n";
}
/**
* Set some values that are cacheable
*/
?>
//<script>
<?php foreach (_elgg_get_js_site_data() as $expression => $value): ?>
<?= $expression ?> = <?= json_encode($value) ?>;
<?php endforeach; ?>
elgg.version = '<?php echo elgg_get_version(); ?>';
elgg.release = '<?php echo elgg_get_version(true); ?>';
elgg.config.wwwroot = '<?php echo elgg_get_site_url(); ?>';
// refresh token 3 times during its lifetime (in microseconds 1000 * 1/3)
elgg.security.interval = <?php echo (int)_elgg_services()->actions->getActionTokenTimeout() * 333; ?>;
elgg.config.language = '<?php echo (empty($CONFIG->language) ? 'en' : $CONFIG->language); ?>';
// page data overrides site data
$.extend(elgg.data, elgg._data);
delete elgg._data;
// jQuery and UI must be loaded sync in 2.x but modules should depend on these AMD modules
define('jquery', function () {
@@ -2,39 +2,9 @@
/**
* Initialize Elgg's js lib with the uncacheable data
*/
$elgg = array(
'config' => array(
'lastcache' => (int)elgg_get_config('lastcache'),
'viewtype' => elgg_get_viewtype(),
'simplecache_enabled' => (int)elgg_is_simplecache_enabled(),
),
'security' => array(
'token' => array(
'__elgg_ts' => $ts = time(),
'__elgg_token' => generate_action_token($ts),
),
),
'session' => array(
'user' => null,
),
);
$page_owner = elgg_get_page_owner_entity();
if ($page_owner instanceof ElggEntity) {
$elgg['page_owner'] = $page_owner->toObject();
}
$user = elgg_get_logged_in_user_entity();
if ($user instanceof ElggUser) {
$user_object = $user->toObject();
$user_object->admin = $user->isAdmin();
$elgg['session']['user'] = $user_object;
}
?>
var elgg = <?php echo json_encode($elgg); ?>;
var elgg = <?php echo json_encode(_elgg_get_js_page_data()); ?>;
<?php
// note: elgg.session.user needs to be wrapped with elgg.ElggUser, but this class isn't
// defined yet. So this is delayed until after the classes are defined, in js/lib/session.js

0 comments on commit cec6b42

Please sign in to comment.