Search

Disclaimer: this is very much an early concept. All ideas welcome!

Here's my idea for including JS libraries within Symphony's backend, for other extensions to use.

http://github.com/nickdunn/javascript_libraries/tree/master

Install the extension, but be sure to name the folder "javascriptextensions" with the leading underscore. Then patch /symphony/lib/tooklit/class.extensionmanager.php adding the ORDER BY clause.

This patch and the obscure naming of the folder ensure that the JS Libraries extension is always the first to execute, and so is available in the pool for others to call. Another extension may request a library using the following syntax:

$js = $this->_Parent->ExtensionManager->getInstance("extension__javascript_libraries");
if ($js) $js->append("jquery");

The available libraries are (from Google AJAX Libraries)

  • jquery (jQuery 1.3.2)
  • mootools (MooTools 1.2.1)
  • prototype (Prototype 1.6.0.3)
  • swfobject (SWFObject 2.1)

If multiple extensions request the same library, it is only loaded once. Only one version of each library can ever be used, since most will not allow multiple versions to co-exist on a page.

This isn't an exceptionally well-rounded approach. The extension initialises on the InitaliseAdminPageHead delegate event. Because other extensions also initialise at this point (since this is where they would normally add their JS anyway) I rely on the alphabetical naming to ensure JS Libraries is loaded first.

One could get around this by creating a new delegate higher up the chain for the JS Libraries extension to initialise, for example InitaliseAdminPage.

The other messy part is the syntax to call the extension. Perhaps the extension could also create a static class so that the append syntax could be as simple as this?

JavaScriptLibraries::append("jquery");

Thoughts?

Maybe something like:

JavaScript::jquery($version, $versionMax=NULL) {
    // check if $version is available
    // if it is not, then check if $versionMax != NULL,
    // in which case compare available versions like (pseudo code):
    // if ($version <= $available <= $versionMax) return true;
    // else return false;
}

Even better would be to allow to merge scripts or code into one function. I just did something like that for markitup, and i can use it and mediathek side by side without a problem :).

So to follow example above (this time for mootools ;)

JavaScript::mootools($path, $version, $versionMax=NULL) {
    // check if $version is available
    // if it is not, then check if $versionMax != NULL,
    // in which case compare available versions like (pseudo code):
    // if ($version <= $available <= $versionMax) then
    //    if $path is file then
    //       JavaScript::privateCache[lib_id] .= file_get_contents($path).";\n";
    //    else if it contains newlines, then it most probably is raw JS code, so
    //       JavaScript::privateCache[lib_id] .= $path."\n";
    //    return true;
    // }
    // else return false;
}

// When we're ready to generate script tags,
// foreach JavaScript::privateCache as $id => $content
//    $content = '(function(){'.$content.')};'
//    if needed, generate cache file named with md5 sum of $content?
//    add script to header

It could generate cache files on the fly (if needed). It would help prevent conflicts and minimize number of .js files required to download at each page load.

I haven't tested your extension but from a mootools point of view it would be great if it was possible to pass an array with all needed module (core and more). This way, extensions could register the needed modules and a mootools version with only the needed parts (for all extensions together) could be generated.

I'm not sure how complicated this might be, but I would be a great feature to use.

I'd argue this is getting a little overcomplicated, but I like the approach. Are you suggesting it may support multiple versions of the same library?

A static class included is definitely the way forward. I also think we need the InitaliseAdminPage delegate so we don't need the ugly underscore name hack.

I don't know much about those libraries and their internals, but i guess it should be possible to have at least some of them in multiple versions. I suspect prototype may not work that well with this trick, because of using prototypes. But if it keeps backwards compatibility, all should be ok. Same for using different libraries at the same time - as long as they don't force "global" changes, they should work peacefully.

If we make it static, and support only those modules that call this static function, then one delegate should be enough for everything. Only it should be last one, just before rendering, so modules can keep adding stuff until last delegate (AdminPagePreGenerate) is called and we generate merged JS file and add it to head :).

One more thing: to look more like part of Symphony internals, it could be based on Manager class :).

But for the static class to be available to others you need a delegate to initialise the JS extension itself. The notifymembers() function calls the ExtensionManager->create method; before this time the JS extension wouldn't have executed at all and may not have included the static class. I could be mistaken.

Unfortunately the complexity of basing something on a Manager class is beginning to get beyond me. The project is on Git and I'm more than willing to get others contributing...

You're right, i forgot about a need to define class :).

Or modules could be required to include class file.... for now. If Symphony devs like this thing, it could be put in toolkit, and maybe become part of HTMLPage (Page->jquery() or Page::jquery(), doesn't really matter, it will keep its data static anyway).

I'll try to work on it tomorrow.

nickdunn, check this and let me know what You think about those changes (or pull them right away if You like them :).

Basically i added lib/class.javascript.php, which is static, and renamed .js files so they use version number in their name. Now whenever You want to add some JS to page, just use something like this:

if (!JavaScript::add('path/to/my/file.js', 'jquery', '1.3.0', '1.3.2')) {
    // show error about required library
}

Last version number is optional and defines maximum version that can be used. First version number is minimum version number required.

You can also pass raw JavaScript code instead of path. Or URL (downloaded JS files are additionally cached).

Merged JS files are generated (cached too) and added to head automatically by extension (it subscribes to AdminPagePreGenerate delegate), so no other function calls should be needed by extensions.

We could also add automatic download from Google, in case of missing library version that exists in Google repositories.

Sorry ahwayakchih I never made the time to check your contribution. Now Symphony is including jQuery for use in the backend (with the forthcoming 2.0.3) is there a need to continue development of this extension?

It would be useful to allow developers to request inclusion of Mootools, jQuery UI and so on…

Maybe this research can contribute to a model for a workflow for managing libraries in the frontend?

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details