? Failure

User tests: Successful: Unsuccessful:

avatar Fedik
Fedik
16 Jan 2016

This is the last piece of puzzle: how to throw away JHtml behaviors.
Other parts is #6357 und #3072

How we add js/css in current Joomla API

$doc->addStyleSheet('path/to/style1.css');
$doc->addStyleSheet('path/to/style2.css');
$doc->addScript('path/to/script1.js');
$doc->addScript('path/to/script2.js');
// or
JHtml::_('stylesheet', 'extension/style1.css', false, true);
JHtml::_('script', 'extension/script1.js', false, true);
JHtml::_('script', 'extension/script2.js', false, true);
// or with predefined JHtml behaviors
JHtml::_('behavior.core');
JHtml::_('jquery.framework');
JHtml::_('bootstrap.framework');

Advantage:

  • it works ?
  • it not so complicated (until you reach the point when you need to add a loot css/js)

Drawback

  • I need to remember all dependency. And if script2.js depend from script1.js then they should be added in the correct ordering from the beginning. If script2.js added before script1.js I end up with broken code.
  • if I want to use some library that has css and js I need to add them both in each layout file. And if in some point of time the file name is changed, I need to edit all entry where I added them. Or I should use my own behavior helper.

What I suggest

I suggest to add one more abstraction level ?

  • JHtmlAssetItem represent single asset, and it`s dependency.
  • JHtmlAssetFactory for manage all available assets, end resolve their dependency.

Previous example can become:

JHtml::_('asset.load', 'asset1'); 

Just a single line :neckbeard:

Or with inline script:

JHtml::_('asset.scriptDeclaration', $content, array('asset1')); 

How it works

Each Asset collection defined by joomla.asset.json, that stored aside js/css in the /media folder (see for /media/jui/joomla.asset.json, /media/system/joomla.asset.json for example), or it can be added at the run time (see JHtmlAssetFactory::registerDataFile($path)).

Example, when I want to use bootstrap I call JHtml::_('asset.load', 'bootstrap'); . At this point AssetFactory parse all new joomla.asset.json (if it first call of asset.load) and check whether exist the Asset with this name, and set it to active.

AssetFactory do NOT add any style/script to the document until header render.

Joomla call AssetFactory->attach() before start render the header. At this time AssetFactory check for all active assets and load all their dependency, in case with bootstrap it also will load jquery asset, and then will attach all required css/js files to the document.

Note: For now AssetFactory calculate the dependency only by name and ignore versions.

Advantage:

  • I do not need to remember which asset depend from which, I just call Asset what I need, all else Joomla do for me.
  • it is easy ?
  • as it provide dependency system, it should be more easy to integrate require.js. at time of attach()

Drawback

  • it make a bit more complicated the development entry point
  • I need to write joomla.asset.json, but it is also the Advantage, as I do not need to write my custom behavior helper ?
  • it is to complicated if I really want add just a single file ?

Possible Advantage:

  • If it need, we can allow to provide specific asset class (see JHtmlAssetFactory::prepareAssetInstance()), that will allow to do more tricky stuff (example, attach the files depend from language, etc)
  • with small plugin it allow to request all assets at once (merge them). Like <link href="index.php?com_ajax&getStyleAsset=bootstrap,calendar" > and <script src="index.php?com_ajax&getScriptAsset=bootstrap,calendar" >

API

joomla.asset.json example:

{
    "title" : "Example",
    "name"  : "com_example",
    "author": "Joomla! CMS",
    "assets": [
        {
            "name": "asset1",
            "version": "3.5.0",
            "versionAttach": true,
            "js": [
                "com_example/library1.min.js"
            ]
        },
        {
            "name": "assetname2",
            "version": "3.5.0",
            "js": [
                "com_example/library2.min.js"
            ],
            "css": [
                "com_example/library2.css"
            ],
            "dependency": [
                "core",
                "asset1"
            ],
            "attribute": {
                "com_example/library2.min.js": {
                    "attrname": "attrvalue"
                },
                "com_example/library2.css": {
                    "media": "all"
                }
            }
        },
    ]
}

I hope the Root Elements is clear, all it just for information, and not required.
Children of "assets": [] is actually provided assets .
Each asset can have:

  • name (required) The name of asset. Would be good if it will be compatible with Bower naming.
  • version Optional version of the asset
  • versionAttach Optional. Whether the files will be attached with the version variable (by addScriptVersion/addStyleSheetVersion)
  • js Optional. JavaScript files. Path can be relative to /media folder, relative to Joomla root or external.
  • css Optional. StyleSheet files. Path can be relative to /media folder, relative to Joomla root or external.
  • dependency Optional dependency. Name(s) of assets that required to make current Asset work.
  • attribute Optional attributes that will be attached with related css/js file.

JHtmlAsset helper methods:

// Manage the Assets
JHtml::_('asset.load', 'assetName'); // Load asset by name, or add and load new asset object
JHtml::_('asset.unload',  'assetName'); // Unload asset by name,
JHtml::_('asset.add', $assetInstance); // Add custom asset object to AssetFactory

// Manage the inline js/css
JHtml::_('asset.scriptDeclaration', $content, $dependancy); // Adds an inline script to the page
JHtml::_('asset.styleDeclaration', $content, $dependancy); // Adds an inline style declaration to the page

Final words

It is already worked solution. However I do not replace all Joomla stuff to use Asset factory, as it much work. And before do it, I need to know that this will be accepted.

In combination with #6357 und #3072 (after some refinement there) we can make life more easy (or harder, depend from point of view ?). In theory :neckbeard:

avatar Fedik Fedik - open - 16 Jan 2016
avatar Fedik Fedik - change - 16 Jan 2016
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 16 Jan 2016
Labels Added: ?
avatar Fedik Fedik - change - 16 Jan 2016
The description was changed
avatar brianteeman brianteeman - change - 30 Mar 2016
Category JavaScript
avatar andrepereiradasilva
andrepereiradasilva - comment - 30 Mar 2016

@Fedik just saw this PR now.

It seems like a very good idea.
Is the PR this still valid?

If so, some questions:

  • will this allow adding inline js/css with dependencies too?
  • does this allow to add other attributes (e.g. data attributes) to the script or link tag?
  • will this allow to add specific css/js with conditional statements (IE)?
  • with changes in the document rendering, will it be possible to define the asset HTML render position (ex: head tag, before end of body tag)

Drawbacks

  • it make a bit more complicated the development entry point
  • I need to write joomla.asset.json, but it is also the Advantage, as I do not need to write my custom behavior helper :smile:
  • it is to complicated if I really want add just a single file :smile:

For what i understand, and please correct if i'm wrong, if want to add a jquery dependent js script (without adding a json file), we'll do this:

$jsAsset = new JAssetItem('myCustomAsset')->setDependency(array('jquery'))->setJs(array('myjsfile.js'));
JHtml::_('asset.load', $jsAsset);

And now we use something like this:

JHtml::_('jquery.framework');       
JHtml::_('script', 'myjsfile.js');

So actually we can add it with the same lines of code (and without json). But yes, is not simple as the current method.

But if this is merged we can in the future modify the addScript (and other script css related methods) to use this to generate the css/js assets, right?

avatar Fedik
Fedik - comment - 30 Mar 2016

Is the PR this still valid?

it do not have a conflicts, so I guess it is valid :smile:

will this allow adding inline js/css with dependencies too?

It only for files, however if we allow "custom class" for each asset https://github.com/joomla/joomla-cms/pull/8913/files#diff-5dbc66d167ed44e3946ee1a79efb5201R574 then the class can have some own logic for add inline css/jss when JAssetFactory::attach() will be called

Also there #6357 is additional idea for reduce to zero the inline js.

  • does this allow to add other attributes (e.g. data attributes) to the script or link tag?
  • will this allow to add specific css/js with conditional statements (IE)?
  • with changes in the document rendering, will it be possible to define the asset HTML render position

The Asset factory it is just a layer over, it does not do more than JDocumentHtml allow to do. See JAssetItem::attachCss and JAssetItem::attachJs

But if this is merged we can in the future modify the addScript (and other script css related methods) to use this to generate the css/js assets, right?

Nope, the reason the same, it just a layer :wink:
My very naive idea is do not use addScript/addStyleshet directly, in future :smile:

.. if want to add a jquery dependent js script

yes, you can do as in your example,
or you can make a joomla.asset.json for your extension and place it under media/com_blabla/joomla.asset.json. Then in the code you can add one of your asset by:

JHtml::_('asset.load', 'my-cool-asset-name');

And AssetFactory automatically will load all css/js dependencies.

Also this allow to reuse your asset by other extensions, easily ... in theory :smile:

avatar andrepereiradasilva
andrepereiradasilva - comment - 30 Mar 2016

it do not have a conflicts, so I guess it is valid :smile:

Since it was travis errors i thought it was "abandoned" :)

I think the concept is very good, and i understand that now we can only use what JDocument allows.
But i think having the possibility to manage all assets (inline or not) through here would be nicer.

If with this we could implement a component with js/css files, inline js/css, dependencies, data-* attributes, async, defer, etc using only Asset factory layer (one to rule then all :) ) i think it would be more easy and logic to everyone, than using a bunch of different methods, ex: JHtml (script, stylesheet, asset), addScript, addScriptVersion, addStyleSheet, etc.

avatar Fedik
Fedik - comment - 31 Mar 2016

But i think having the possibility to manage all assets (inline or not) through here would be nicer.

With assets I mean only files, here.
Example you use colorbox: the library contain colorbox.js and colorbox.css - that the "colorbox" asset.
And the inline code for init the library it is not "asset" .. cause it can be very different, depend from case.

However you can make one more asset for your extension with "behavior-colorbox.js" (see other pull request) with "colorbox" as dependency, and putt there all code that will handle data-*, and do other stuf that need for your extension.

Well I am bad in good explanation :smile:

avatar andrepereiradasilva
andrepereiradasilva - comment - 31 Mar 2016

ok, this is only for external js/css files. I understand why, but from a developer learning curve perspective don't you agree with me that can be rather confusing having so many methods for js/css inline external, versioning, etc?

avatar Fedik
Fedik - comment - 1 Apr 2016

well, yes .. learning is hard here, can be ...
Maybe I try add some proxy for addXXXDeclaration, in to JHtmlAsset, so all will be in the one place.

So after all it can looks like:
Before
for 'some-library':

JHtml::_('behavior.core');
JHtml::_('jquery.framework');
JHtml::_('stylesheet', 'extension/some-library.css', false, true);
JHtml::_('script', 'extension/some-library.js', false, true);
$doc->addScriptDeclaration('some init code');

It not hard if I have it in single layout, but a bit annoying if need to edit it in couple different layouts.
I know about JHtml Behaviors, but it hard to manage the dependencies.

After
joomla.asset.json:

{
    "title" : "Some Extension",
    "name"  : "com_someextension",
    "author": "my name",
    "assets": [
        {
            "name": "some-library",
            "version": "1.0.0",
            "versionAttach": true, // attach the version query to each file
            "js": [
                "com_someextension/some-library.min.js"
            ],
            "css": [
                "com_someextension/some-library.css"
            ],
            "dependency": [
                "core",
                "jquery"
            ]
        },
    ]
}

and in layout just:

JHtml::_('asset.scriptDeclaration', 'alert("blabla")', $deps = array('some-library'));

hm

avatar andrepereiradasilva
andrepereiradasilva - comment - 1 Apr 2016

yes, it seems good. or for just jquery dependency something like this.

$inlineJs = '$( document ).ready(function() { alert("blabla"); });';
JHtml::_('asset.scriptDeclaration', $inlineJs, array('jquery'));

or for vanilla js without dependencies something like this.

JHtml::_('asset.scriptDeclaration', 'alert("blabla");');
avatar Fedik
Fedik - comment - 10 Apr 2016

I have added:

JHtml::_('asset.scriptDeclaration', $content, $dependancy); // Adds an inline script to the page
JHtml::_('asset.styleDeclaration', $content, $dependancy); // Adds an inline style declaration to the page

And now the AssetFactory pick up joomla.asset.json from the template to (see example for Isis and Protostar, in this pull request)

avatar joomla-cms-bot joomla-cms-bot - change - 11 Sep 2016
Category JavaScript Templates (admin) Administration Layout Libraries
avatar mbabker
mbabker - comment - 21 May 2017

Any word on this?

avatar joomla-cms-bot joomla-cms-bot - change - 21 May 2017
The description was changed
avatar joomla-cms-bot joomla-cms-bot - edited - 21 May 2017
avatar franz-wohlkoenig franz-wohlkoenig - change - 22 May 2017
The description was changed
Status Pending Information Required
avatar Fedik
Fedik - comment - 22 May 2017

Sadly it cannot be synced easily (more easy to write new). I kept it open to get some feedback, but seems not much interest in it.
I planed to make "basic" version of this patch for J 4.x, maybe some day.

I am closing it,
if someone interesting, can keep discussion in the related topic #12402

avatar Fedik Fedik - change - 22 May 2017
The description was changed
Status Information Required Closed
Closed_Date 0000-00-00 00:00:00 2017-05-22 16:08:10
Closed_By Fedik
avatar Fedik Fedik - close - 22 May 2017

Add a Comment

Login with GitHub to post a comment