Skip to content

Commit

Permalink
feature(assets): Get rid of js/ and css/ directories
Browse files Browse the repository at this point in the history
All views under these directories are implicitly "hoisted" up one level.
They are also given the appropriate extension:

 * js/view => view.js
 * css/view => view.css

The main benefit this brings is being able to co-locate related assets.
So a template (view.php) can have its CSS/JS dependencies right next to it
(view.css, view.js). Compare to the current approach which is like so:

 * Template: page/components/module.php
 * CSS: css/elements/modules.php
 * JS: None in this case, but how would you know with any confidence?

BREAKING CHANGE:

Great care has been taken to make this change as backwards-compatible as possible,
so you should not need to update any view references right away. However, you are
certainly encouraged to move your JS and CSS views to their new, canonical
locations.

Certain uses of the `view,$view_name` and `view_vars,$view_name` hooks will not work.
See the docs on "View aliases" for more info.

Refs Elgg#8381
Fixes Elgg#8382
  • Loading branch information
ewinslow committed Jun 24, 2015
1 parent 35c8c89 commit 2f9101a
Show file tree
Hide file tree
Showing 121 changed files with 417 additions and 304 deletions.
2 changes: 1 addition & 1 deletion docs/contribute/code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Jasmine Tests
-------------

Test files must be named ``*Test.js`` and should go in either ``js/tests/`` or next
to their source files in ``views/default/js``. Karma will automatically pick up
to their source files in ``views/default/**.js``. Karma will automatically pick up
on new ``*Test.js`` files and run those tests.

Test boilerplate
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/plugins/start.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function my_plugin_init() {
elgg_register_action('my_plugin', "$base_dir/my_action.php");

// Extend the main CSS file
elgg_extend_view('css/elgg', 'my_plugin/css');
elgg_extend_view('elgg.css', 'my_plugin.css');

// Add a menu item to the main site menu
$item = new ElggMenuItem('my_plugin', elgg_echo('my_plugin:menu'), 'my_url');
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/ajax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ The Ajax view system works significantly differently than the action system.
``false`` if it can't be loaded.
* There's no "wrapper" object placed around the view output.
* System messages/errors shouldn't be used, as they don't display until the user loads another page.
* If the view name begins with ``js/`` or ``css/``, a corresponding Content-Type header is added.
* Depending on the view's suffix (.js, .html, .css, etc.), a corresponding Content-Type header is added.

.. warning::

Expand Down
28 changes: 13 additions & 15 deletions docs/guides/javascript.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Here we define a basic module that alters the page, by passing a "definition fun

.. code-block:: javascript
// in views/default/js/myplugin/say_hello.js
// in views/default/myplugin/say_hello.js
define(function(require) {
var elgg = require("elgg");
Expand All @@ -64,8 +64,8 @@ Here we define a basic module that alters the page, by passing a "definition fun
$('body').append(elgg.echo('hello_world'));
});
The module's name is determined by the view name, which here is ``js/myplugin/say_hello.js``.
We strip the leading ``js/`` and the ``.js`` extension, leaving ``myplugin/say_hello``.
The module's name is determined by the view name, which here is ``myplugin/say_hello.js``.
We strip the ``.js`` extension, leaving ``myplugin/say_hello``.

.. warning::

Expand All @@ -79,7 +79,7 @@ the greeting:

.. code-block:: javascript
// in views/default/js/myplugin/hello.js
// in views/default/myplugin/hello.js
define(function(require) {
var elgg = require("elgg");
Expand All @@ -89,7 +89,7 @@ the greeting:
.. code-block:: javascript
// in views/default/js/myplugin/say_hello.js
// in views/default/myplugin/say_hello.js
define(function(require) {
var $ = require("jquery");
Expand All @@ -102,7 +102,7 @@ Passing plugin/Elgg settings to modules
---------------------------------------

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/js/myplugin/settings.js.php`` (note the double extension
create the view file ``views/default/myplugin/settings.js.php`` (note the double extension
``.js.php``).

.. code-block:: php
Expand All @@ -124,7 +124,7 @@ You must also manually register the view as an external resource:
<?php
// note the view name does not include ".php"
elgg_register_simplecache_view('js/myplugin/settings.js');
elgg_register_simplecache_view('myplugin/settings.js');
.. note::

Expand All @@ -144,7 +144,7 @@ The best way to accomplish this is by configuring the path to the file using the
<?php // views.php
return [
'js/underscore.js' => 'vendor/bower-asset/underscore/underscore.min.js',
'underscore.js' => 'vendor/bower-asset/underscore/underscore.min.js',
];
If you've copied the script directly into your plugin instead of managing it with Composer,
Expand All @@ -154,7 +154,7 @@ you can use something like this instead:
<?php // views.php
return [
'js/underscore.js' => __DIR__ . '/bower_components/underscore/underscore.min.js',
'underscore.js' => __DIR__ . '/bower_components/underscore/underscore.min.js',
];
That's it! Elgg will now load this file whenever the "underscore" module is requested.
Expand All @@ -165,21 +165,20 @@ Using traditional JS libraries as modules

It's possible to support JavaScript libraries that do not declare themselves as AMD
modules (i.e. they declare global variables instead) if you shim them by
setting ``exports`` and optionally ``deps`` in ``elgg_define_js``:
setting ``exports`` and ``deps`` in ``elgg_define_js``:

.. code-block:: php
// set the path, define its dependencies, and what value it returns
elgg_define_js('jquery.form', [
'src' => elgg_get_simplecache_url('js/jquery.form.js'),
'deps' => array('jquery'),
'deps' => ['jquery'],
'exports' => 'jQuery.fn.ajaxForm',
]);
When this is requested client-side:

#. The jQuery module is loaded, as it's marked as a dependency.
#. ``https://elgg.example.org/cache/125235034/views/default/js/jquery.form.js`` is loaded and executed.
#. ``https://elgg.example.org/cache/125235034/views/default/jquery.form.js`` is loaded and executed.
#. The value of ``window.jQuery.fn.ajaxForm`` is returned by the module.

.. warning:: Calls to ``elgg_define_js()`` must be in an ``init, system`` event handler.
Expand All @@ -190,8 +189,7 @@ Some things to note
#. Do not use ``elgg.provide()`` anymore nor other means to attach code to ``elgg`` or other
global objects. Use modules.
#. Return the value of the module instead of adding to a global variable.
#. JS and CSS views (names starting with ``js/`` or ``css/``) as well as static (.js/.css) files
are automatically minified and cached by Elgg's simplecache system.
#. Static (.js,.css,etc.) files are automatically minified and cached by Elgg's simplecache system.


Migrating JS from Elgg 1.8 to AMD / 1.9
Expand Down
13 changes: 8 additions & 5 deletions docs/guides/plugins/plugin-skeleton.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ The following files for plugin ``example`` would go in ``/mod/example/``
example_3rd_party_lib/
views/
default/
example.png
css/
example.css
example/
component.css
component.js
component.png
forms/
example/
action.php
other_action.php
js/
example.js
object/
example.php
example/
Expand All @@ -45,7 +44,11 @@ The following files for plugin ``example`` would go in ``/mod/example/``
usersettings.php
resources/
example/
all.css
all.js
all.php
owner.css
owner.js
owner.php
widgets/
example_widget/
Expand Down
34 changes: 17 additions & 17 deletions docs/guides/themes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ overwhelmed.

Here is a list of the existing CSS views:

* css/elements/buttons: Provides a way to style all the different kinds of buttons your site will use. There are 5 kinds of buttons that plugins will expect to be available: action, cancel, delete, submit, and special.
* css/elements/chrome: This file has some miscellaneous look-and-feel classes.
* css/elements/components: This file contains many “css objects” that are used all over the site: media block, list, gallery, table, owner block, system messages, river, tags, photo, and comments.
* css/elements/forms: This file determines what your forms and input elements will look like.
* css/elements/icons: Contains styles for the sprite icons and avatars used on your site.
* css/elements/layout: Determines what your page layout will look like: sidebars, page wrapper, main body, header, footer, etc.
* css/elements/modules: Lots of content in Elgg is displayed in boxes with a title and a content body. We called these modules. There are a few kinds: info, aside, featured, dropdown, popup, widget. Widget styles are included in this file too, since they are a subset of modules.
* css/elements/navigation: This file determines what all your menus will look like.
* css/elements/typography: This file determines what the content and headings of your site will look like.
* css/rtl: Custom rules for users viewing your site in a right-to-left language.
* css/admin: A completely separate theme for the admin area (usually not overridden).
* css/elgg: Compiles all the core css/elements/\* files into one file (DO NOT OVERRIDE).
* css/elements/core: Contains base styles for the more complicated “css objects”. If you find yourself wanting to override this, you probably need to report a bug to Elgg core instead (DO NOT OVERRIDE).
* css/elements/reset: Contains a reset stylesheet that forces elements to have the same default
* elements/buttons.css: Provides a way to style all the different kinds of buttons your site will use. There are 5 kinds of buttons that plugins will expect to be available: action, cancel, delete, submit, and special.
* elements/chrome.css: This file has some miscellaneous look-and-feel classes.
* elements/components.css: This file contains many “css objects” that are used all over the site: media block, list, gallery, table, owner block, system messages, river, tags, photo, and comments.
* elements/forms.css: This file determines what your forms and input elements will look like.
* elements/icons.css: Contains styles for the sprite icons and avatars used on your site.
* elements/layout.css: Determines what your page layout will look like: sidebars, page wrapper, main body, header, footer, etc.
* elements/modules.css: Lots of content in Elgg is displayed in boxes with a title and a content body. We called these modules. There are a few kinds: info, aside, featured, dropdown, popup, widget. Widget styles are included in this file too, since they are a subset of modules.
* elements/navigation.css: This file determines what all your menus will look like.
* elements/typography.css: This file determines what the content and headings of your site will look like.
* rtl.css: Custom rules for users viewing your site in a right-to-left language.
* admin.css: A completely separate theme for the admin area (usually not overridden).
* elgg.css: Compiles all the core elements/\* files into one file (DO NOT OVERRIDE).
* elements/core.css: Contains base styles for the more complicated “css objects”. If you find yourself wanting to override this, you probably need to report a bug to Elgg core instead (DO NOT OVERRIDE).
* elements/reset.css: Contains a reset stylesheet that forces elements to have the same default


View extension
Expand All @@ -64,7 +64,7 @@ css file:
<?php
function mytheme_init() {
elgg_extend_view('css/elgg', 'mytheme/css');
elgg_extend_view('elgg.css', 'mytheme/css');
}
elgg_register_event_handler('init', 'system', 'mytheme_init');
Expand All @@ -77,11 +77,11 @@ Plugins can have a view hierarchy, any file that exists here will
replace any files in the existing core view hierarchy... so for example,
if my plugin has a file:

``/mod/myplugin/views/default/css/elements/typography.php``
``/mod/myplugin/views/default/elements/typography.css``

it will replace:

``/views/default/css/elements/typography.php``
``/views/default/elements/typography.css``

But only when the plugin is active.

Expand Down
55 changes: 55 additions & 0 deletions docs/guides/upgrading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,61 @@ See the administrator guides for :doc:`how to upgrade a live site </admin/upgrad
From 1.x to 2.0
===============

JS and CSS views have been moved out of the js/ and css/ directories
--------------------------------------------------------------------

They also have been given .js and .css extensions respectively if they didn't
already have them:

================= =============
Old view New view
================= =============
``js/view`` ``view.js``
``js/other.js`` ``other.js``
``css/view`` ``view.css``
``css/other.css`` ``other.css``
``js/img.png`` ``img.png``
================= =============

The main benefit this brings is being able to co-locate related assets.
So a template (``view.php``) can have its CSS/JS dependencies right next to it
(``view.css``, ``view.js``).

Care has been taken to make this change as backwards-compatible as possible,
so you should not need to update any view references right away. However, you are
certainly encouraged to move your JS and CSS views to their new, canonical
locations.

Practically speaking, this carries a few gotchas:

The ``view_vars, $view_name`` and ``view, $view_name`` hooks will operate on the
*canonical* view name:

.. code:: php
elgg_register_plugin_hook_handler('view', 'css/elgg', function($hook, $view_name) {
assert($view_name == 'elgg.css') // not "css/elgg"
});
Using the ``view, all`` hook and checking for individual views may not work as intended:

.. code:: php
elgg_register_plugin_hook_handler('view', 'all', function($hook, $view_name) {
// Won't work because "css/elgg" was aliased to "elgg.css"
if ($view_name == 'css/elgg') {
// Never executed...
}
// Won't work because no canonical views start with css/* anymore
if (strpos($view_name, 'css/') === 0) {
// Never executed...
}
});
Please let us know about any other BC issues this change causes.
We'd like to fix as many as possible to make the transition smooth.

``fxp/composer-asset-plugin`` is now required to install Elgg from source
-------------------------------------------------------------------------

Expand Down
12 changes: 7 additions & 5 deletions docs/guides/views.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,13 @@ instead of an ``h1``, we could create a file at ``/mod/example/views/default/hel
When considering long-term maintenance, overriding views in the core and bundled plugins has a cost:
Upgrades may bring changes in views, and if you have overridden them, you will not get those changes.

You may instead want to :ref:`alter the input <guides/views#altering-view-input>`
or the :ref:`the output <guides/views#altering-view-output>` of the view via plugin hooks.
You may instead want to alter :ref:`the input <guides/views#altering-view-input>`
or :ref:`the output <guides/views#altering-view-output>` of the view via plugin hooks.

.. note::

Elgg caches view locations. This means that you should disable the system cache while developing with views.
When you install the changes to a production environment you mush flush the caches.
When you install the changes to a production environment you must flush the caches.

Extending views
---------------
Expand Down Expand Up @@ -294,9 +294,10 @@ Since 1.11, before each view rendering the ``$vars`` array is filtered by the
Each registered handler function is passed these arguments:

* ``$hook`` - the string ``"view_vars"``
* ``$type`` - the view name being rendered (the first argument passed to ``elgg_view()``)
* ``$view_name`` - the view name being rendered (the first argument passed to ``elgg_view()``)
* ``$returnvalue`` - the modified ``$vars`` array
* ``$params`` - an array containing:

* ``vars`` - the original ``$vars`` array, unaltered
* ``view`` - the view name
* ``viewtype`` - The :ref:`viewtype <guides/views#viewtypes>` being rendered
Expand Down Expand Up @@ -328,9 +329,10 @@ The output of each view is run through the :ref:`plugin hook <guides/hooks-list#
Each registered handler function is passed these arguments:

* ``$hook`` - the string ``"view"``
* ``$type`` - the view name being rendered (the first argument passed to ``elgg_view()``)
* ``$view_name`` - the view name being rendered (the first argument passed to ``elgg_view()``)
* ``$result`` - the modified output of the view
* ``$params`` - an array containing:

* ``viewtype`` - The :ref:`viewtype <guides/views#viewtypes>` being rendered

To alter the view output, the handler just needs to alter ``$returnvalue`` and return a new string.
Expand Down
8 changes: 4 additions & 4 deletions docs/guides/views/simplecache.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ You can register a view with the Simplecache with the following function at init
**Accessing the cached view**

If you registered a JavaScript or CSS file with Simplecache and put in in the view folder
``js/your_view.js`` or ``css/your_view.css`` you can very easily get the url to this cached view by calling
If you registered a JavaScript or CSS file with Simplecache and put in the view folder as
``your_view.js`` or ``your_view.css`` you can very easily get the url to this cached view by calling
``elgg_get_simplecache_url($view)``. For example:

.. code:: php
$js = elgg_get_simplecache_url('js/your_view.js');
$css = elgg_get_simplecache_url('css/your_view.css');
$js = elgg_get_simplecache_url('your_view.js');
$css = elgg_get_simplecache_url('your_view.css');
2 changes: 1 addition & 1 deletion engine/classes/Elgg/Amd/ViewFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ViewFilter {
/**
* Given the view name, returns the AMD name.
*
* @param string $name The name of the view (e.g., 'js/elgg/module.js')
* @param string $name The name of the view (e.g., 'elgg/module.js')
*
* @return string The AMD name (e.g., 'elgg/module'), or blank for no AMD name.
*/
Expand Down
Loading

0 comments on commit 2f9101a

Please sign in to comment.