? Success

User tests: Successful: Unsuccessful:

avatar Fedik
Fedik
13 Aug 2016

In the pull request a couple methods which allow to work with Events, and do AJAX request.
That allow to write some basic JavaSript without additional JavaSript library.

Testing Instructions

Add in index.php of Isis template the button:

<button id="my-button">button</button>

And in template.js:

Joomla.domReady(function(){
    var button = document.getElementById('my-button');

    function myClickHandler (event){
        console.log('You just clicked', event.target || event.srcElement);
        testRequest();

        button.removeEventListener('click', myClickHandler);

        button.addEventListener('click', function(){
            alert('Click me again!');
        });
    }

    function testRequest(){
        Joomla.request({
            url: 'index.php?option=com_content',

            onBefore: function(xhr){
                console.log('Before:', xhr.readyState);
            },
            onSuccess: function(response, xhr){
                alert('Page title is ' + response.match(/<title[^>]*>([^<]+)<\/title>/)[1]);
            },
            onError: function(xhr){
                alert('Error:' + xhr.status + ' ' + xhr.statusText);
            }
        });
    }

    button.addEventListener('click', myClickHandler);
});

then click on the button:

  • on first click you should get an alert with page title of 'index.php?option=com_content "Page title is Articles ..."
  • on second click you should get an alert with Click me again!

Then try change url: 'index.php?option=com_content', to url: 'index.php?option=com_foobar',.
After first click you should get an alert with "Page not found"

Ping @dgt41 @andrepereiradasilva @roland-d

avatar Fedik Fedik - open - 13 Aug 2016
avatar mbabker
mbabker - comment - 13 Aug 2016

My first feeling here is do we really want to go the route of writing a Joomla JavaScript framework and be 100% independent of dependencies that we're already loading and shipping? I get the value for some of our other utilities, but replacing jQuery.ajax()? Unless we're aiming for a headless CMS in 4.0 (and all of the UI stuff is basically deferred to templates only), this just seems like doing stuff for the sake of doing it.

avatar Fedik
Fedik - comment - 13 Aug 2016

I seen stuff where jQuery used only for catch domReady, and load a whole library just for it is a bit strange

Joomla JavaScript framework

That would be fun ?

avatar mbabker
mbabker - comment - 13 Aug 2016

I honestly don't see the need to invent new APIs and wheels to do stuff that is already being done with existing code and resources, even if it does mean a dependency to a library that people seem to hate being loaded for some reason. I'm all for using native JavaScript where it makes sense and where it doesn't create overly complex code (knowing we're still supporting IE8), but right now I'm not convinced that a homegrown replacement for jQuery(document).ready() or jQuery.ajax() is in our best interests. Maybe during the 4.0 development cycle where older browser support can be dropped that opinion could sway, but right now I think our time is better invested elsewhere.

Honestly in general I'm not a fan of how many times I see it suggested that Joomla writes its own solution when there is already a functional and supported solution either already shipped with Joomla or available to be easily consumed. Ya there's some risk with including third party dependencies, but the more we build in house and the more Joomlaisms we create the harder it is to maintain our code base or have it in a state where folks can easily implement it. Even worse is when the suggestion to just fork the third party resource and maintain it ourselves comes around.

avatar andrepereiradasilva
andrepereiradasilva - comment - 13 Aug 2016

I agree with @mbabker when it says there are several cases were Joomla writes its own solution when there is already a functional and supported solution either already shipped with Joomla or available to be easily consumed but for me this is not the case.

I agree with @Fedik on this, there are several case jQuery is only used for events or ajax calls and i prefer to always use a vanilla js aproach. For js performance reasons a vanilla js is always better than using jQuery.
I will test this when i have time.

avatar andrepereiradasilva
andrepereiradasilva - comment - 13 Aug 2016

@Fedik tested your example and works fine, but i also tried to add this and didn't totally work:

JFactory::getDocument()->addScriptDeclaration("
Joomla.addListener(window, 'load', function ()
{
    var xhr = Joomla.request({
        url: 'index.php?option=com_foobar',
        onBefore: function(xhr){ console.log('Before:', xhr.readyState); },
        onSuccess: function(response, xhr){ alert('Page title is ' + response.match(/<title[^>]*>([^<]+)<\/title>/)[1]); },
        onError: function(xhr){ Joomla.ajaxErrorsMessages(xhr); }
    });
});
");

Js Console log

Before: 1
core.js:1 GET /administrator/index.php?option=com_foobar 404 (Component not found.)
core.js:1 Uncaught TypeError: Cannot read property 'replace' of undefined

Is something wrong with my code or other thing?

avatar Fedik
Fedik - comment - 14 Aug 2016

it because Joomla.JText._('JLIB_JS_AJAX_ERROR_OTHER') do not return the translation, because it do not exists.
you also need to call: JText::script('JLIB_JS_AJAX_ERROR_OTHER') if I right

and use Joomla.renderMessages(Joomla.ajaxErrorsMessages(xhr));

avatar andrepereiradasilva
andrepereiradasilva - comment - 14 Aug 2016

sorry my mistake, was sleeping before this works fine!:

// Load JavaScript message titles
JText::script('ERROR');
JText::script('WARNING');
JText::script('NOTICE');
JText::script('MESSAGE');

// Add strings for JavaScript error translations.
JText::script('JLIB_JS_AJAX_ERROR_CONNECTION_ABORT');
JText::script('JLIB_JS_AJAX_ERROR_NO_CONTENT');
JText::script('JLIB_JS_AJAX_ERROR_OTHER');
JText::script('JLIB_JS_AJAX_ERROR_PARSE');
JText::script('JLIB_JS_AJAX_ERROR_TIMEOUT');

JFactory::getDocument()->addScriptDeclaration("
Joomla.addListener(window, 'load', function ()
{
    var xhr = Joomla.request({
        url: 'index.php?option=com_foobar',
        onBefore: function(xhr){ console.log('Before:', xhr.readyState); },
        onSuccess: function(response, xhr){ alert('Page title is ' + response.match(/<title[^>]*>([^<]+)<\/title>/)[1]); },
        onError: function(xhr){ Joomla.renderMessages(Joomla.ajaxErrorsMessages(xhr)); }
    });
});
");
avatar andrepereiradasilva andrepereiradasilva - test_item - 14 Aug 2016 - Tested successfully
avatar andrepereiradasilva
andrepereiradasilva - comment - 14 Aug 2016

I have tested this item successfully on a1ae34c

Works fine and IMHO a much needed PR!


This comment was created with the J!Tracker Application at issues.joomla.org/joomla-cms/11585.

avatar C-Lodder
C-Lodder - comment - 14 Aug 2016

This will definitely need to be tested in IE8. If I rightly remember, don't older IE versions need a small pollyfill for functions like removeListener and addListener?

avatar Fedik
Fedik - comment - 14 Aug 2016

it already should work in IE, but testing is required ?

avatar dgt41
dgt41 - comment - 14 Aug 2016

@Fedik I think I agree to some extend with @mbabker, but that doesn't mean that I disagree completely with this PR.
My point of view is that Joomla should not start creating own functionality for something that is already given in ecmascript6. So let's say for addEventListener, this works for every modern browser except IE8! OK then, let's use that and polyfill the missing part for IE. At the end we end up at the same result BUT we re using the STANDARDS from ECMA and probably none of the PLT (in their right mind) should not object on that (I mean ECMA6 is already killing jQuery, open your eyes and don't put the project to the same position as with mootools/jquery)!
Recap: instead of introducing Joomla's own weird functions let's embrace the ECMA6 and fill the gaps for IE8 (for as long as this browser exists as a supported thing from the project)

avatar andrepereiradasilva
andrepereiradasilva - comment - 14 Aug 2016

as usual the real problem here is IE ... without that browser most jquery scripts could be replaced with vanilla js.

avatar dgt41
dgt41 - comment - 14 Aug 2016

@andrepereiradasilva I am just saying let's use vanilla js AND polyfill what IE is missing. In matter of fact we don;t even have to code that as those polyfills already exist

avatar dgt41
dgt41 - comment - 14 Aug 2016

@andrepereiradasilva we could even use JBrowser to add the polyfill only for IE

avatar andrepereiradasilva
andrepereiradasilva - comment - 14 Aug 2016

do you mean something like if ie load ecma6shim.js?
The same way we do it for html5shim ?

avatar Fedik
Fedik - comment - 15 Aug 2016

ok, I can remove Joomla.(add/remove)Listener and just add fallback for IE for Element.(add/remove)EventListener

about polyfill, it can be only with client side check, because JBrowser will fail for 100% when Joomla! behind caching proxy.

avatar Fedik
Fedik - comment - 16 Aug 2016

I have removed Joomla.(add/remove)Listener and added very simple fallback for IE for Element.(add/remove)EventListener, but it is pour fallback :neckbeard:

There still a small difference in event object. In theory it should be enough for our basic needs but, it like a half-worked solution.

So no idea, maybe can leave ajax and domReady, but remove other event stuff. Or include one of existing polyfill in the core, but it doesn't sounds as good idea ?

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

reggarding events, if i understand correctly for vannila js you use something like this

document.addEventListener('DOMContentLoaded', function() {

    this.getElementById('myElement1Id').addEventListener('click', function() {
        alert('clicked 1');
    });

    this.getElementById('myElement2Id').addEventListener('click', function() {
        alert('clicked 2');
    });

    this.querySelector(".myclass").addEventListener('click', function() {
        alert('clicked 3');
    });

});

For what i understand this doesn't work only in IE8 right?

http://caniuse.com/#feat=domcontentloaded
http://caniuse.com/#feat=addeventlistener
http://caniuse.com/#feat=queryselector (IE8 partial support)

avatar Fedik
Fedik - comment - 17 Aug 2016

For what i understand this doesn't work only in IE8 right?

yes, and maybe in IE9, not remember

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

so reggarding events we "just" needd to polyfill (add/remove)eventlistener and domcontentloaded for IE8 and all should work.

ajax is another matter

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

doesn't this does that? https://github.com/WebReflection/ie8 or https://gist.github.com/chriswrightdesign/7573368 (just an example)

we can include the polyfill only in ie8, like we do for html5shim, something like

<!--[if lt IE 9]><script src="/media/jui/js/ie8polyfill.js"></script><![endif]-->

with that we could use vanilla js for events!

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

what do you guys think?

avatar Fedik
Fedik - comment - 17 Aug 2016

unfortunately it will not work that easy, because <!--[if lt IE 9]>.. must be manually added in the template, and we cannot force it
so if template do not contain this then our scripts will be broken in old IE

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

Doesn't that also happens with html5 js?

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

and we cannot force it

when we need, we can

$doc->addCustomTag('<!--[if lt IE 9]><script src="/media/jui/js/ie8polyfill.js"></script><![endif]-->');
avatar ggppdk
ggppdk - comment - 17 Aug 2016

unfortunately it will not work that easy, because <!--[if lt IE 9]>.. must be manually added in the template, and we cannot force it, so if template do not contain this then or scripts will be broken in old IE

since the code is really small, why not add inside core.js,
and then add it inside an if statement

var userAgent = navigator.userAgent.toLowerCase();
var IEversion = (userAgent.indexOf('msie') != -1) ? parseInt(userAgent.split('msie')[1]) : false;
var isIE8 = IEversion ? IEversion < 9 : false;

if (isIE8)
{
...
}

also a little off topic, maybe we are are adding too many small JS files

avatar C-Lodder
C-Lodder - comment - 17 Aug 2016

@ggppdk - Using @andrepereiradasilva's method above is better than checking the user agent. Also means it doesn't need to manually be added to the template.

Personally, I'd suggest combining all IE8 pollyfills and shivs into 1 JS file and simply use the following in core templates:

<!--[if lt IE 9]>
    <script src="/media/jui/js/ie8.js"></script>
<![endif]-->

Either that or park this PR until J4.x when supporting IE8 may not be required in core, but instead the template providers.

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

also a little off topic, maybe we are are adding too many small JS files

I see no problem with that.

Also, after SPDY, the web is moving to HTTP 2.0 (finaly!!) and HTTP 2.0 does multiplexing of requests so from what i understand there is no bottleneck in a browser downloading a lot of js/css files from the same server.

avatar ggppdk
ggppdk - comment - 17 Aug 2016

Yes, ok,
@andrepereiradasilva

you mean add it here ?
https://github.com/joomla/joomla-cms/blob/staging/libraries/cms/html/behavior.php#L87

JFactory::getDocument()->addCustomTag(
  '<!--[if lt IE 9]><script src="media/jui/js/ie8polyfill.js"></script><![endif]-->'
);
JHtml::_('script', 'system/core.js', false, true);
avatar Fedik
Fedik - comment - 17 Aug 2016

Doesn't that also happens with html5 js?

html5 js do not contain any logic we use, it just for browser to help to understand new tags ?

$doc->addCustomTag() ignore possibility to override the script, that possible with JHtml::_('script', 'blabla.js')

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

you mean add it here ?
https://github.com/joomla/joomla-cms/blob/staging/libraries/cms/html/behavior.php#L87

if we use add/removeEventListener + DOMContentLoaded in the core.js ...

What i'm saying is adding a JHtml behaviour to add that custom tag

public static function ie8()
{
    // Only load once
    if (isset(static::$loaded[__METHOD__]))
    {
        return;
    }

    // Include IE8 polyfill
    JFactory::getDocument()->addCustomTag('<!--[if lt IE 9]><script src="/media/jui/js/ie8polyfill.js"></script><![endif]-->');

    // Set static array
    static::$loaded[__METHOD__] = true;
}

them whenever you use add/removeEventListener + DOMContentLoaded polyfill you call that dependency first.

JHtml::_('behavior.ie8');

or something like this

this will also be good in template managers still want (or need) to support ie8 in Joomla 4.

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

@Fedik @dgt41 @C-Lodder @ggppdk what do you guys think about this?

avatar C-Lodder
C-Lodder - comment - 17 Aug 2016

Yup, that sounds like a good idea.

JHtml::_('behavior.ie8'); should also load html5shiv.js.

One thing that needs to happen though is, these scripts should be loaded before any other script

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

One thing that needs to happen though is, these scripts should be loaded before any other script

for that you need to change JDocumentRendererHtmlHead output order
See https://github.com/joomla/joomla-cms/blob/staging/libraries/joomla/document/renderer/html/head.php#L310

avatar ggppdk
ggppdk - comment - 17 Aug 2016

What about

JHtml::_('behavior.extend'); 

or similar ?
in near future version of Joomla the inclusion of IE8 specific stuff will be removed

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

for me is ok

avatar andrepereiradasilva
andrepereiradasilva - comment - 17 Aug 2016

so for what i understand from this discussion we need to separate things:

  • joomla ajax request method in the core.js is one thing, and IMO it should be in core.js as this PR does. (IMHO we need to be able to easily make ajax requests with vannila js)
  • an add/removeEventListener + DOMContentLoaded ie8 polyfill is another thing.

So this should be two different PR's since they are not related. @Fedik do you agree?

avatar Fedik
Fedik - comment - 17 Aug 2016

yes, better to split these things,
I will remove the event stuff from current pull request

avatar brianteeman brianteeman - change - 18 Aug 2016
Category JavaScript
avatar andrepereiradasilva andrepereiradasilva - test_item - 18 Aug 2016 - Tested successfully
avatar andrepereiradasilva
andrepereiradasilva - comment - 18 Aug 2016

I have tested this item successfully on d000417

just removed the events so still ok for the ajax request in core js


This comment was created with the J!Tracker Application at issues.joomla.org/joomla-cms/11585.

avatar Fedik
Fedik - comment - 18 Aug 2016

I have removed the events stuff, and updated the testing instruction

avatar dgt41 dgt41 - test_item - 18 Aug 2016 - Tested successfully
avatar dgt41
dgt41 - comment - 18 Aug 2016

I have tested this item successfully on d000417

Works fine


This comment was created with the J!Tracker Application at issues.joomla.org/joomla-cms/11585.

avatar dgt41 dgt41 - change - 18 Aug 2016
Status New Ready to Commit
avatar dgt41
dgt41 - comment - 18 Aug 2016

RTC Let's wait for PLT

avatar andrepereiradasilva
andrepereiradasilva - comment - 18 Aug 2016

ok so this PR will be only for the core.js ajax request.

we will need a other PR for the events + DOMContentLoaded IE8 polyfill
@dgt41 @Fedik so how do you think it's better to proceed with this part?

avatar dgt41
dgt41 - comment - 18 Aug 2016

@andrepereiradasilva if you are about to do that can you use:

$scriptPath = JHtml::_('script', 'media/jui/js/ie8polyfill.js', false, true, true, false, true); // return only path
  // Include IE8 polyfill
    JFactory::getDocument()->addCustomTag('<!--[if lt IE 9]><script src="' . $scriptPath . '"></script><![endif]-->');
avatar Fedik
Fedik - comment - 18 Aug 2016

well, find a good polyfill and use condition comment as you suggested,
one of hundert https://github.com/WebReflection/ie8
there also was @dgt41 suggestions

hard to chose ?

avatar andrepereiradasilva
andrepereiradasilva - comment - 18 Aug 2016

i am not about to do it. you guys have more knowledge in this than i do.

avatar dgt41
dgt41 - comment - 18 Aug 2016

I fail miserably on copy-paste ?

avatar andrepereiradasilva
andrepereiradasilva - comment - 18 Aug 2016
avatar dgt41
dgt41 - comment - 18 Aug 2016

Yeah Financial-times don;t use native mobile apps instead they use plain javascript. Most of their code is available on github. Thus the polyfill need I guess

avatar andrepereiradasilva
andrepereiradasilva - comment - 18 Aug 2016

and this licence is usable with current joomla policy (i honestly don't have a clue)

avatar dgt41
dgt41 - comment - 18 Aug 2016

MIT should be fine (I have no clue either)

avatar mbabker
mbabker - comment - 18 Aug 2016

MIT's fine. Otherwise the Symfony code we're shipping would have to come out.

avatar brianteeman
brianteeman - comment - 19 Aug 2016

What @mbabker said MIT is fine

avatar andrepereiradasilva
andrepereiradasilva - comment - 20 Aug 2016

so will this be RTC ?

avatar dgt41 dgt41 - change - 20 Aug 2016
Status Ready to Commit Needs Review
avatar dgt41 dgt41 - change - 20 Aug 2016
Status Needs Review Ready to Commit
avatar dgt41
dgt41 - comment - 20 Aug 2016

@andrepereiradasilva ok RTC down to PLT then

avatar dgt41 dgt41 - change - 20 Aug 2016
Title
[RFC] Core.js AJAX and event methods
Core.js AJAX and event methods
avatar dgt41
dgt41 - comment - 20 Aug 2016

RTC

avatar dgt41
dgt41 - comment - 20 Aug 2016
avatar Fedik
Fedik - comment - 23 Aug 2016

@yvesh do you have a tip how to write a tests for AJAX requests?
and also be able test the HTTP errors while request.

avatar yvesh
yvesh - comment - 23 Aug 2016

@Fedik Take a look at the sendtestmail tests, they mock the http requests.

Ping me if i should explain more :)

avatar joomla-cms-bot joomla-cms-bot - change - 23 Aug 2016
Labels Added: ?
avatar Fedik
Fedik - comment - 23 Aug 2016

@yvesh thanks for the links.
Other small question. How to debug the stuff inside the test? I tried console.log but nothing in the console output

avatar yvesh
yvesh - comment - 23 Aug 2016

@Fedik try to use console.info

avatar rdeutz
rdeutz - comment - 1 Oct 2016

@Fedik could you have a look at the conflicts and resolve them, thanks!

avatar Fedik
Fedik - comment - 1 Oct 2016

done, just conflict of minified versions

avatar rdeutz rdeutz - change - 1 Oct 2016
Status Ready to Commit Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2016-10-01 14:44:54
Closed_By rdeutz
avatar rdeutz rdeutz - close - 1 Oct 2016
avatar rdeutz rdeutz - merge - 1 Oct 2016
avatar zero-24 zero-24 - close - 1 Oct 2016
avatar zero-24 zero-24 - change - 3 Oct 2016
Labels Removed: ?

Add a Comment

Login with GitHub to post a comment