[js] make _loadAjaxHtmlHead aware of mod_concat-like urls
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
Fri, 29 Apr 2011 12:34:53 +0200
changeset 7284 a474cb989546
parent 7283 1699393372b3
child 7285 39437617f3f0
[js] make _loadAjaxHtmlHead aware of mod_concat-like urls _loadAjaxHtmlHead keeps track of already imported resources (js / css) to make sure they're not included twice, but with mod_concat-like urls, things get a bit more complicated : if BASE_URL/data??foo.js,bar.js is already imported, then loading : BASE_URL/data??bar.js,spam.js should only load spam.js
web/data/cubicweb.ajax.js
web/data/cubicweb.js
--- a/web/data/cubicweb.ajax.js	Fri Apr 29 12:12:49 2011 +0200
+++ b/web/data/cubicweb.ajax.js	Fri Apr 29 12:34:53 2011 +0200
@@ -86,6 +86,41 @@
 
 var JSON_BASE_URL = baseuri() + 'json?';
 
+/**
+ * returns true if `url` is a mod_concat-like url
+ * (e.g. http://..../data??resource1.js,resource2.js)
+ */
+function _modconcatLikeUrl(url) {
+    var base = baseuri();
+    if (!base.endswith('/')) {
+        base += '/';
+    }
+    var modconcat_rgx = new RegExp('(' + base + 'data/([a-z0-9]+/))?\\?\\?(.+)');
+    return modconcat_rgx.exec(url);
+}
+
+/**
+ * decomposes a mod_concat-like url into its corresponding list of
+ * resources' urls
+ *
+ * >>> _listResources('http://foo.com/data/??a.js,b.js,c.js')
+ * ['http://foo.com/data/a.js', 'http://foo.com/data/b.js', 'http://foo.com/data/c.js']
+ */
+function _listResources(src) {
+    var resources = [];
+    var groups = _modconcatLikeUrl(src);
+    if (groups == null) {
+        resources.push(src);
+    } else {
+        var dataurl = groups[0];
+        $.each(cw.utils.lastOf(groups).split(','),
+               function() {
+                   resources.push(dataurl + this);
+               });
+    }
+    return resources;
+}
+
 //============= utility function handling remote calls responses. ==============//
 function _loadAjaxHtmlHead($node, $head, tag, srcattr) {
     var jqtagfilter = tag + '[' + srcattr + ']';
@@ -93,28 +128,33 @@
         cw['loaded_'+srcattr] = [];
         var loaded = cw['loaded_'+srcattr];
         jQuery('head ' + jqtagfilter).each(function(i) {
-                   loaded.push(this.getAttribute(srcattr));
-               });
+            // tab1.push.apply(tab1, tab2) <=> tab1 += tab2 (python-wise)
+            loaded.push.apply(loaded, _listResources(this.getAttribute(srcattr)));
+        });
     } else {
         var loaded = cw['loaded_'+srcattr];
     }
     $node.find(tag).each(function(i) {
-        var url = this.getAttribute(srcattr);
+        var srcnode = this;
+        var url = srcnode.getAttribute(srcattr);
         if (url) {
-            if (jQuery.inArray(url, loaded) == -1) {
-                // take care to <script> tags: jQuery append method script nodes
-                // don't appears in the DOM (See comments on
-                // http://api.jquery.com/append/), which cause undesired
-                // duplicated load in our case. After trying to use bare DOM api
-                // to avoid this, we switched to handle a list of already loaded
-                // stuff ourselves, since bare DOM api gives bug with the
-                // server-response event, since we loose control on when the
-                // script is loaded (jQuery load it immediatly).
-                loaded.push(url);
-                jQuery(this).appendTo($head);
-            }
+            $.each(_listResources(url), function() {
+                var resource = '' + this; // implicit object->string cast
+                if ($.inArray(resource, loaded) == -1) {
+                    // take care to <script> tags: jQuery append method script nodes
+                    // don't appears in the DOM (See comments on
+                    // http://api.jquery.com/append/), which cause undesired
+                    // duplicated load in our case. After trying to use bare DOM api
+                    // to avoid this, we switched to handle a list of already loaded
+                    // stuff ourselves, since bare DOM api gives bug with the
+                    // server-response event, since we loose control on when the
+                    // script is loaded (jQuery load it immediatly).
+                    loaded.push(resource);
+                    jQuery(srcnode).appendTo($head);
+                }
+            });
         } else {
-            jQuery(this).appendTo($head);
+            jQuery(srcnode).appendTo($head);
         }
     });
     $node.find(jqtagfilter).remove();
--- a/web/data/cubicweb.js	Fri Apr 29 12:12:49 2011 +0200
+++ b/web/data/cubicweb.js	Fri Apr 29 12:34:53 2011 +0200
@@ -308,6 +308,17 @@
     },
 
     /**
+     * returns the last element of an array-like object or undefined if empty
+     */
+    lastOf: function(array) {
+        if (array.length) {
+            return array[array.length-1];
+        } else {
+            return undefined;
+        }
+    },
+
+    /**
      * .. function:: difference(lst1, lst2)
      *
      * returns a list containing all elements in `lst1` that are not