[ajax] refactor/cleanup low-level ajax functions
* loadxhtml/replacePageChunck/reload_component/reload_box deprecated in favor of loadXHTML / ajaxFuncArgs
* some other cleanups in cubicweb.ajax.js
* add js_render which will replace js_component (more generic, nicer argument passing handling)
--- a/web/data/cubicweb.ajax.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.ajax.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,7 +1,20 @@
-/*
- * :organization: Logilab
- * :copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
- * :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+/* copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+ *
+ * This file is part of CubicWeb.
+ *
+ * CubicWeb is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 2.1 of the License, or (at your option)
+ * any later version.
+ *
+ * CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
*/
CubicWeb.require('python.js');
@@ -9,6 +22,7 @@
var JSON_BASE_URL = baseuri() + 'json?';
+//============= utility function handling remote calls responses. ==============//
function _loadAjaxHtmlHead(node, head, tag, srcattr) {
var loaded = [];
var jqtagfilter = tag + '[' + srcattr + ']';
@@ -17,7 +31,7 @@
});
node.find(tag).each(function(i) {
if (this.getAttribute(srcattr)) {
- if (!loaded.contains(this.getAttribute(srcattr))) {
+ if (jQuery.inArray(this.getAttribute(srcattr), loaded) == -1) {
jQuery(this).appendTo(head);
}
} else {
@@ -27,7 +41,9 @@
node.find(jqtagfilter).remove();
}
-/*
+/**
+ * .. function:: function loadAjaxHtmlHead(response)
+ *
* inspect dom response (as returned by getDomFromResponse), search for
* a <div class="ajaxHtmlHead"> node and put its content into the real
* document's head.
@@ -59,18 +75,13 @@
// we can safely return this node. Otherwise, the view itself
// returned several 'root' nodes and we need to keep the wrapper
// created by getDomFromResponse()
- if (response.childNodes.length == 1 &&
- response.getAttribute('cubicweb:type') == 'cwResponseWrapper') {
+ if (response.childNodes.length == 1 && response.getAttribute('cubicweb:type') == 'cwResponseWrapper') {
return response.firstChild;
}
return response;
}
-function preprocessAjaxLoad(node, newdomnode) {
- return loadAjaxHtmlHead(newdomnode);
-}
-
-function postAjaxLoad(node) {
+function _postAjaxLoad(node) {
// find sortable tables if there are some
if (typeof(Sortable) != 'undefined') {
Sortable.sortTables(node);
@@ -89,44 +100,77 @@
roundedCorners(node);
}
if (typeof setFormsTarget != 'undefined') {
- setFormsTarget(node);
+ setFormsTarget(node);
}
- loadDynamicFragments(node);
+ _loadDynamicFragments(node);
// XXX [3.7] jQuery.one is now used instead jQuery.bind,
// jquery.treeview.js can be unpatched accordingly.
jQuery(CubicWeb).trigger('server-response', [true, node]);
+ jQuery(node).trigger('server-response', [true, node]);
+}
+
+function remoteCallFailed(err, req) {
+ cw.log(err);
+ if (req.status == 500) {
+ updateMessage(err);
+ } else {
+ updateMessage(_("an error occured while processing your request"));
+ }
}
-/* cubicweb loadxhtml plugin to make jquery handle xhtml response
+//============= base AJAX functions to make remote calls =====================//
+/**
+ * .. function:: ajaxFuncArgs(fname, form, *args)
*
- * fetches `url` and replaces this's content with the result
+ * extend `form` parameters to call the js_`fname` function of the json
+ * controller with `args` arguments.
+ */
+function ajaxFuncArgs(fname, form /* ... */) {
+ form = form || {};
+ $.extend(form, {
+ 'fname': fname,
+ 'pageid': pageid,
+ 'arg': map(jQuery.toJSON, sliceList(arguments, 2))
+ });
+ return form;
+}
+
+/**
+ * .. function:: loadxhtml(url, form, reqtype='get', mode='replace', cursor=true)
*
- * @param mode how the replacement should be done (default is 'replace')
- * Possible values are :
+ * build url given by absolute or relative `url` and `form` parameters
+ * (dictionary), fetch it using `reqtype` method, then evaluate the
+ * returned XHTML and insert it according to `mode` in the
+ * document. Possible modes are :
+ *
* - 'replace' to replace the node's content with the generated HTML
* - 'swap' to replace the node itself with the generated HTML
* - 'append' to append the generated HTML to the node's content
+ *
+ * If `cursor`, turn mouse cursor into 'progress' cursor until the remote call
+ * is back.
*/
-jQuery.fn.loadxhtml = function(url, data, reqtype, mode) {
- var ajax = null;
- if (reqtype == 'post') {
- ajax = jQuery.post;
- } else {
- ajax = jQuery.get;
+jQuery.fn.loadxhtml = function(url, form, reqtype, mode, cursor) {
+ if (this.size() > 1) {
+ cw.log('loadxhtml was called with more than one element');
}
- if (this.size() > 1) {
- log('loadxhtml was called with more than one element');
+ var callback = null;
+ if (form && form.callback) {
+ cw.log('[3.9] callback given through form.callback is deprecated, add ' + 'callback on the defered');
+ callback = form.callback;
+ delete form.callback;
}
var node = this.get(0); // only consider the first element
- mode = mode || 'replace';
- var callback = null;
- if (data && data.callback) {
- callback = data.callback;
- delete data.callback;
+ if (cursor) {
+ setProgressCursor();
}
- ajax(url, data, function(response) {
+ var d = loadRemote(url, form, reqtype);
+ d.addCallback(function(response) {
var domnode = getDomFromResponse(response);
- domnode = preprocessAjaxLoad(node, domnode);
+ domnode = loadAjaxHtmlHead(domnode);
+ mode = mode || 'replace';
+ // make sure the component is visible
+ $(node).removeClass("hidden");
if (mode == 'swap') {
var origId = node.id;
node = swapDOM(node, domnode);
@@ -138,19 +182,97 @@
} else if (mode == 'append') {
jQuery(node).append(domnode);
}
- postAjaxLoad(node);
+ _postAjaxLoad(node);
while (jQuery.isFunction(callback)) {
callback = callback.apply(this, [domnode]);
}
});
-};
+ if (cursor) {
+ d.addCallback(resetCursor);
+ d.addErrback(resetCursor);
+ d.addErrback(remoteCallFailed);
+ }
+ return d;
+}
+/**
+ * .. function:: loadRemote(url, form, reqtype='GET', async=true)
+ *
+ * Asynchronously (unless `async` argument is set to false) load an url or path
+ * and return a deferred whose callbacks args are decoded according to the
+ * Content-Type response header. `form` should be additional form params
+ * dictionary, `reqtype` the HTTP request type (get 'GET' or 'POST').
+ */
+function loadRemote(url, form, reqtype, sync) {
+ if (!url.startswith(baseuri())) {
+ url = baseuri() + url;
+ }
+ if (!sync) {
+ var deferred = new Deferred();
+ jQuery.ajax({
+ url: url,
+ type: (reqtype || 'GET').toUpperCase(),
+ data: form,
+ async: true,
+
+ beforeSend: function(xhr) {
+ deferred._req = xhr;
+ },
+
+ success: function(data, status) {
+ if (deferred._req.getResponseHeader("content-type") == 'application/json') {
+ data = cw.evalJSON(data);
+ }
+ deferred.success(data);
+ },
+ error: function(xhr, status, error) {
+ try {
+ if (xhr.status == 500) {
+ var reason_dict = cw.evalJSON(xhr.responseText);
+ deferred.error(xhr, status, reason_dict['reason']);
+ return;
+ }
+ } catch(exc) {
+ cw.log('error with server side error report:' + exc);
+ }
+ deferred.error(xhr, status, null);
+ }
+ });
+ return deferred;
+ } else {
+ var result = jQuery.ajax({
+ url: url,
+ type: (reqtype || 'GET').toUpperCase(),
+ data: form,
+ async: false
+ });
+ if (result) {
+ // XXX no good reason to force json here,
+ // it should depends on request content-type
+ result = cw.evalJSON(result.responseText);
+ }
+ return result
+ }
+}
-/* finds each dynamic fragment in the page and executes the
+//============= higher level AJAX functions using remote calls ===============//
+/**
+ * .. function:: _(message)
+ *
+ * emulation of gettext's _ shortcut
+ */
+function _(message) {
+ return loadRemote('json', ajaxFuncArgs('i18n', null, [message]), 'GET', true)[0];
+}
+
+/**
+ * .. function:: _loadDynamicFragments(node)
+ *
+ * finds each dynamic fragment in the page and executes the
* the associated RQL to build them (Async call)
*/
-function loadDynamicFragments(node) {
+function _loadDynamicFragments(node) {
if (node) {
var fragments = jQuery(node).find('div.dynamicFragment');
} else {
@@ -162,246 +284,137 @@
if (typeof LOADING_MSG == 'undefined') {
LOADING_MSG = 'loading'; // this is only a safety belt, it should not happen
}
- for(var i=0; i<fragments.length; i++) {
+ for (var i = 0; i < fragments.length; i++) {
var fragment = fragments[i];
fragment.innerHTML = '<h3>' + LOADING_MSG + ' ... <img src="data/loading.gif" /></h3>';
+ var $fragment = jQuery(fragment);
// if cubicweb:loadurl is set, just pick the url et send it to loadxhtml
- var url = getNodeAttribute(fragment, 'cubicweb:loadurl');
+ var url = $fragment.attr('cubicweb:loadurl');
if (url) {
- jQuery(fragment).loadxhtml(url);
+ $fragment.loadxhtml(url);
continue;
}
// else: rebuild full url by fetching cubicweb:rql, cubicweb:vid, etc.
- var rql = getNodeAttribute(fragment, 'cubicweb:rql');
- var items = getNodeAttribute(fragment, 'cubicweb:vid').split('&');
+ var rql = $fragment.attr('cubicweb:rql');
+ var items = $fragment.attr('cubicweb:vid').split('&');
var vid = items[0];
var extraparams = {};
// case where vid='myvid¶m1=val1¶m2=val2': this is a deprecated abuse-case
if (items.length > 1) {
- console.log("[3.5] you're using extraargs in cubicweb:vid attribute, this is deprecated, consider using loadurl instead");
- for (var j=1; j<items.length; j++) {
+ cw.log("[3.5] you're using extraargs in cubicweb:vid " +
+ "attribute, this is deprecated, consider using " +
+ "loadurl instead");
+ for (var j = 1; j < items.length; j++) {
var keyvalue = items[j].split('=');
extraparams[keyvalue[0]] = keyvalue[1];
}
}
- var actrql = getNodeAttribute(fragment, 'cubicweb:actualrql');
- if (actrql) { extraparams['actualrql'] = actrql; }
- var fbvid = getNodeAttribute(fragment, 'cubicweb:fallbackvid');
- if (fbvid) { extraparams['fallbackvid'] = fbvid; }
- replacePageChunk(fragment.id, rql, vid, extraparams);
- }
-}
-
-jQuery(document).ready(function() {loadDynamicFragments();});
-
-//============= base AJAX functions to make remote calls =====================//
-
-function remoteCallFailed(err, req) {
- if (req.status == 500) {
- updateMessage(err);
- } else {
- updateMessage(_("an error occured while processing your request"));
+ var actrql = $fragment.attr('cubicweb:actualrql');
+ if (actrql) {
+ extraparams['actualrql'] = actrql;
+ }
+ var fbvid = $fragment.attr('cubicweb:fallbackvid');
+ if (fbvid) {
+ extraparams['fallbackvid'] = fbvid;
+ }
+ extraparams['rql'] = rql;
+ extraparams['vid'] = vid;
+ $(fragment.id).loadxhtml('json', ajaxFuncArgs('view', extraparams));
}
}
-
-
-/*
- * This function will call **synchronously** a remote method on the cubicweb server
- * @param fname: the function name to call (as exposed by the JSONController)
- *
- * additional arguments will be directly passed to the specified function
- *
- * It looks at http headers to guess the response type.
- */
-function remoteExec(fname /* ... */) {
- setProgressCursor();
- var props = {'fname' : fname, 'pageid' : pageid,
- 'arg': map(jQuery.toJSON, sliceList(arguments, 1))};
- var result = jQuery.ajax({url: JSON_BASE_URL, data: props, async: false}).responseText;
- if (result) {
- result = evalJSON(result);
- }
- resetCursor();
- return result;
-}
-
-/*
- * This function will call **asynchronously** a remote method on the json
- * controller of the cubicweb http server
- *
- * @param fname: the function name to call (as exposed by the JSONController)
- *
- * additional arguments will be directly passed to the specified function
- *
- * It looks at http headers to guess the response type.
- */
-
-function asyncRemoteExec(fname /* ... */) {
- setProgressCursor();
- var props = {'fname' : fname, 'pageid' : pageid,
- 'arg': map(jQuery.toJSON, sliceList(arguments, 1))};
- // XXX we should inline the content of loadRemote here
- var deferred = loadRemote(JSON_BASE_URL, props, 'POST');
- deferred = deferred.addErrback(remoteCallFailed);
- deferred = deferred.addErrback(resetCursor);
- deferred = deferred.addCallback(resetCursor);
- return deferred;
-}
-
-
-/* emulation of gettext's _ shortcut
- */
-function _(message) {
- return remoteExec('i18n', [message])[0];
-}
-
-function userCallback(cbname) {
- asyncRemoteExec('user_callback', cbname);
-}
+jQuery(document).ready(function() {
+ _loadDynamicFragments();
+});
function unloadPageData() {
// NOTE: do not make async calls on unload if you want to avoid
// strange bugs
- remoteExec('unload_page_data');
+ loadRemote('json', ajaxFuncArgs('unload_page_data'), 'GET', true);
+}
+
+function removeBookmark(beid) {
+ var d = loadRemote('json', ajaxFuncArgs('delete_bookmark', null, beid));
+ d.addCallback(function(boxcontent) {
+ $('#bookmarks_box').loadxhtml('json',
+ ajaxFuncArgs('render', null, 'boxes',
+ 'bookmarks_box'));
+ document.location.hash = '#header';
+ updateMessage(_("bookmark has been removed"));
+ });
+}
+
+function userCallback(cbname) {
+ setProgressCursor();
+ var d = loadRemote('json', ajaxFuncArgs('user_callback', null, cbname));
+ d.addCallback(resetCursor);
+ d.addErrback(resetCursor);
+ d.addErrback(remoteCallFailed);
+ return d;
}
+function userCallbackThenUpdateUI(cbname, compid, rql, msg, registry, nodeid) {
+ var d = userCallback(cbname);
+ d.addCallback(function() {
+ $('#' + nodeid).loadxhtml('json', ajaxFuncArgs('render', {
+ 'rql': rql
+ },
+ registry, compid));
+ if (msg) {
+ updateMessage(msg);
+ }
+ });
+}
+
+function userCallbackThenReloadPage(cbname, msg) {
+ var d = userCallback(cbname);
+ d.addCallback(function() {
+ window.location.reload();
+ if (msg) {
+ updateMessage(msg);
+ }
+ });
+}
+
+/**
+ * .. function:: unregisterUserCallback(cbname)
+ *
+ * unregisters the python function registered on the server's side
+ * while the page was generated.
+ */
+function unregisterUserCallback(cbname) {
+ setProgressCursor();
+ var d = loadRemote('json', ajaxFuncArgs('unregister_user_callback',
+ null, cbname));
+ d.addCallback(resetCursor);
+ d.addErrback(resetCursor);
+ d.addErrback(remoteCallFailed);
+}
+
+//============= XXX move those functions? ====================================//
function openHash() {
if (document.location.hash) {
var nid = document.location.hash.replace('#', '');
var node = jQuery('#' + nid);
- if (node) { removeElementClass(node, "hidden"); }
+ if (node) {
+ $(node).removeClass("hidden");
+ }
};
}
jQuery(document).ready(openHash);
-function reloadComponent(compid, rql, registry, nodeid, extraargs) {
- registry = registry || 'components';
- rql = rql || '';
- nodeid = nodeid || (compid + 'Component');
- extraargs = extraargs || {};
- var node = getNode(nodeid);
- var d = asyncRemoteExec('component', compid, rql, registry, extraargs);
- d.addCallback(function(result, req) {
- var domnode = getDomFromResponse(result);
- if (node) {
- // make sure the component is visible
- removeElementClass(node, "hidden");
- domnode = preprocessAjaxLoad(node, domnode);
- swapDOM(node, domnode);
- postAjaxLoad(domnode);
- }
- });
- d.addCallback(resetCursor);
- d.addErrback(function(xxx) {
- updateMessage(_("an error occured"));
- log(xxx);
- });
- return d;
-}
-
-/* XXX: HTML architecture of cubicweb boxes is a bit strange */
-function reloadBox(boxid, rql) {
- return reloadComponent(boxid, rql, 'boxes', boxid);
-}
-
-function userCallbackThenUpdateUI(cbname, compid, rql, msg, registry, nodeid) {
- var d = asyncRemoteExec('user_callback', cbname);
- d.addCallback(function() {
- reloadComponent(compid, rql, registry, nodeid);
- if (msg) { updateMessage(msg); }
- });
- d.addCallback(resetCursor);
- d.addErrback(function(xxx) {
- updateMessage(_("an error occured"));
- log(xxx);
- return resetCursor();
- });
-}
-
-function userCallbackThenReloadPage(cbname, msg) {
- var d = asyncRemoteExec('user_callback', cbname);
- d.addCallback(function() {
- window.location.reload();
- if (msg) { updateMessage(msg); }
- });
- d.addCallback(resetCursor);
- d.addErrback(function(xxx) {
- updateMessage(_("an error occured"));
- log(xxx);
- return resetCursor();
- });
-}
-
-/*
- * unregisters the python function registered on the server's side
- * while the page was generated.
- */
-function unregisterUserCallback(cbname) {
- var d = asyncRemoteExec('unregister_user_callback', cbname);
- d.addCallback(function() {resetCursor();});
- d.addErrback(function(xxx) {
- updateMessage(_("an error occured"));
- log(xxx);
- return resetCursor();
- });
-}
-
-
-/* executes an async query to the server and replaces a node's
- * content with the query result
+/**
+ * .. function:: buildWysiwygEditors(parent)
*
- * @param nodeId the placeholder node's id
- * @param rql the RQL query
- * @param vid the vid to apply to the RQL selection (default if not specified)
- * @param extraparmas table of additional query parameters
- */
-function replacePageChunk(nodeId, rql, vid, extraparams, /* ... */ swap, callback) {
- var params = null;
- if (callback) {
- params = {callback: callback};
- }
-
- var node = jQuery('#' + nodeId)[0];
- var props = {};
- if (node) {
- props['rql'] = rql;
- props['fname'] = 'view';
- props['pageid'] = pageid;
- if (vid) { props['vid'] = vid; }
- if (extraparams) { jQuery.extend(props, extraparams); }
- // FIXME we need to do asURL(props) manually instead of
- // passing `props` directly to loadxml because replacePageChunk
- // is sometimes called (abusively) with some extra parameters in `vid`
- var mode = swap?'swap':'replace';
- var url = JSON_BASE_URL + asURL(props);
- jQuery(node).loadxhtml(url, params, 'get', mode);
- } else {
- log('Node', nodeId, 'not found');
- }
-}
-
-/* XXX deprecates?
- * fetches `url` and replaces `nodeid`'s content with the result
- * @param replacemode how the replacement should be done (default is 'replace')
- * Possible values are :
- * - 'replace' to replace the node's content with the generated HTML
- * - 'swap' to replace the node itself with the generated HTML
- * - 'append' to append the generated HTML to the node's content
- */
-function loadxhtml(nodeid, url, /* ... */ replacemode) {
- jQuery('#' + nodeid).loadxhtml(url, null, 'post', replacemode);
-}
-
-/* XXX: this function should go in edition.js but as for now, htmlReplace
+ *XXX: this function should go in edition.js but as for now, htmlReplace
* references it.
*
* replace all textareas with fckeditors.
*/
function buildWysiwygEditors(parent) {
- jQuery('textarea').each(function () {
+ jQuery('textarea').each(function() {
if (this.getAttribute('cubicweb:type') == 'wysiwyg') {
// mark editor as instanciated, we may be called a number of times
- // (see postAjaxLoad)
+ // (see _postAjaxLoad)
this.setAttribute('cubicweb:type', 'fckeditor');
if (typeof FCKeditor != "undefined") {
var fck = new FCKeditor(this.id);
@@ -410,29 +423,29 @@
fck.BasePath = "fckeditor/";
fck.ReplaceTextarea();
} else {
- log('fckeditor could not be found.');
+ cw.log('fckeditor could not be found.');
}
}
});
}
-
jQuery(document).ready(buildWysiwygEditors);
-
-/*
+/**
+ * .. function:: stripEmptyTextNodes(nodelist)
+ *
* takes a list of DOM nodes and removes all empty text nodes
*/
function stripEmptyTextNodes(nodelist) {
/* this DROPS empty text nodes */
var stripped = [];
- for (var i=0; i < nodelist.length; i++) {
+ for (var i = 0; i < nodelist.length; i++) {
var node = nodelist[i];
if (isTextNode(node)) {
- /* all browsers but FF -> innerText, FF -> textContent */
- var text = node.innerText || node.textContent;
- if (text && !text.strip()) {
- continue;
- }
+ /* all browsers but FF -> innerText, FF -> textContent */
+ var text = node.innerText || node.textContent;
+ if (text && ! text.strip()) {
+ continue;
+ }
} else {
stripped.push(node);
}
@@ -440,7 +453,10 @@
return stripped;
}
-/* convenience function that returns a DOM node based on req's result.
+/**
+ * .. function:: getDomFromResponse(response)
+ *
+ * convenience function that returns a DOM node based on req's result.
* XXX clarify the need to clone
* */
function getDomFromResponse(response) {
@@ -460,18 +476,123 @@
return jQuery(children[0]).clone().context;
}
// several children => wrap them in a single node and return the wrap
- return DIV({'cubicweb:type': "cwResponseWrapper"},
- map(function(node) {
- return jQuery(node).clone().context;
- }, children));
-}
-
-function postJSON(url, data, callback) {
- return jQuery.post(url, data, callback, 'json');
-}
-
-function getJSON(url, data, callback){
- return jQuery.get(url, data, callback, 'json');
+ return DIV({
+ 'cubicweb:type': "cwResponseWrapper"
+ },
+ map(function(node) {
+ return jQuery(node).clone().context;
+ },
+ children));
}
CubicWeb.provide('ajax.js');
+
+/* DEPRECATED *****************************************************************/
+
+preprocessAjaxLoad = cw.utils.deprecatedFunction(
+ '[3.9] preprocessAjaxLoad() is deprecated, use loadAjaxHtmlHead instead',
+ function(node, newdomnode) {
+ return loadAjaxHtmlHead(newdomnode);
+ }
+);
+
+reloadComponent = cw.utils.deprecatedFunction(
+ '[3.9] reloadComponent() is deprecated, use loadxhtml instead',
+ function(compid, rql, registry, nodeid, extraargs) {
+ registry = registry || 'components';
+ rql = rql || '';
+ nodeid = nodeid || (compid + 'Component');
+ extraargs = extraargs || {};
+ var node = jqNode(nodeid);
+ return node.loadxhtml('json', ajaxFuncArgs('component', null, compid,
+ rql, registry, extraargs));
+ }
+);
+
+reloadBox = cw.utils.deprecatedFunction(
+ '[3.9] reloadBox() is deprecated, use loadxhtml instead',
+ function(boxid, rql) {
+ return reloadComponent(boxid, rql, 'boxes', boxid);
+ }
+);
+
+replacePageChunk = cw.utils.deprecatedFunction(
+ '[3.9] replacePageChunk() is deprecated, use loadxhtml instead',
+ function(nodeId, rql, vid, extraparams, /* ... */ swap, callback) {
+ var params = null;
+ if (callback) {
+ params = {
+ callback: callback
+ };
+ }
+ var node = jQuery('#' + nodeId)[0];
+ var props = {};
+ if (node) {
+ props['rql'] = rql;
+ props['fname'] = 'view';
+ props['pageid'] = pageid;
+ if (vid) {
+ props['vid'] = vid;
+ }
+ if (extraparams) {
+ jQuery.extend(props, extraparams);
+ }
+ // FIXME we need to do asURL(props) manually instead of
+ // passing `props` directly to loadxml because replacePageChunk
+ // is sometimes called (abusively) with some extra parameters in `vid`
+ var mode = swap ? 'swap': 'replace';
+ var url = JSON_BASE_URL + asURL(props);
+ jQuery(node).loadxhtml(url, params, 'get', mode);
+ } else {
+ cw.log('Node', nodeId, 'not found');
+ }
+ }
+);
+
+loadxhtml = cw.utils.deprecatedFunction(
+ '[3.9] loadxhtml() function is deprecated, use loadxhtml method instead',
+ function(nodeid, url, /* ... */ replacemode) {
+ jQuery('#' + nodeid).loadxhtml(url, null, 'post', replacemode);
+ }
+);
+
+remoteExec = cw.utils.deprecatedFunction(
+ '[3.9] remoteExec() is deprecated, use loadRemote instead',
+ function(fname /* ... */) {
+ setProgressCursor();
+ var props = {
+ 'fname': fname,
+ 'pageid': pageid,
+ 'arg': map(jQuery.toJSON, sliceList(arguments, 1))
+ };
+ var result = jQuery.ajax({
+ url: JSON_BASE_URL,
+ data: props,
+ async: false
+ }).responseText;
+ if (result) {
+ result = cw.evalJSON(result);
+ }
+ resetCursor();
+ return result;
+ }
+);
+
+asyncRemoteExec = cw.utils.deprecatedFunction(
+ '[3.9] asyncRemoteExec() is deprecated, use loadRemote instead',
+ function(fname /* ... */) {
+ setProgressCursor();
+ var props = {
+ 'fname': fname,
+ 'pageid': pageid,
+ 'arg': map(jQuery.toJSON, sliceList(arguments, 1))
+ };
+ // XXX we should inline the content of loadRemote here
+ var deferred = loadRemote(JSON_BASE_URL, props, 'POST');
+ deferred = deferred.addErrback(remoteCallFailed);
+ deferred = deferred.addErrback(resetCursor);
+ deferred = deferred.addCallback(resetCursor);
+ return deferred;
+ }
+);
+
--- a/web/data/cubicweb.bookmarks.js Thu Jun 03 10:17:44 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-CubicWeb.require('ajax.js');
-
-function removeBookmark(beid) {
- d = asyncRemoteExec('delete_bookmark', beid);
- d.addCallback(function(boxcontent) {
- reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
- document.location.hash = '#header';
- updateMessage(_("bookmark has been removed"));
- });
-}
--- a/web/data/cubicweb.calendar.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.calendar.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,7 +1,7 @@
-/*
+/**
* This file contains Calendar utilities
* :organization: Logilab
- * :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*/
@@ -10,14 +10,14 @@
// IMPORTANT NOTE: the variables DAYNAMES AND MONTHNAMES will be added
// by cubicweb automatically
-
// dynamically computed (and cached)
var _CAL_HEADER = null;
TODAY = new Date();
-
-/*
+/**
+ * .. class:: Calendar
+ *
* Calendar (graphical) widget
* public methods are :
* __init__ :
@@ -31,7 +31,7 @@
*
* toggle():
* show (resp. hide) the calendar if it's hidden (resp. displayed)
- *
+ *
* displayNextMonth(): (resp. displayPreviousMonth())
* update the calendar to display next (resp. previous) month
*/
@@ -39,177 +39,219 @@
this.containerId = containerId;
this.inputId = inputId;
this.year = year;
- this.month = month-1; // Javascript's counter starts at 0 for january
+ this.month = month - 1; // Javascript's counter starts at 0 for january
this.cssclass = cssclass || "popupCalendar";
this.visible = false;
this.domtable = null;
- this.cellprops = { 'onclick' : function() {dateSelected(this, containerId); },
- 'onmouseover' : function() {this.style.fontWeight = 'bold'; },
- 'onmouseout' : function() {this.style.fontWeight = 'normal';}
- }
+ this.cellprops = {
+ 'onclick': function() {
+ dateSelected(this, containerId);
+ },
+ 'onmouseover': function() {
+ this.style.fontWeight = 'bold';
+ },
+ 'onmouseout': function() {
+ this.style.fontWeight = 'normal';
+ }
+ }
- this.todayprops = jQuery.extend({}, this.cellprops, {'class' : 'today'});
+ this.todayprops = jQuery.extend({},
+ this.cellprops, {
+ 'class': 'today'
+ });
this._rowdisplay = function(row) {
- return TR(null, map(partial(TD, this.cellprops), row));
- }
+ var _td = function(elt) {
+ return TD(this.cellprops, elt);
+ };
+ return TR(null, map(_td, row));
+ };
this._makecell = function(cellinfo) {
- return TD(cellinfo[0], cellinfo[1]);
- }
+ return TD(cellinfo[0], cellinfo[1]);
+ };
- /* utility function (the only use for now is inside the calendar) */
- this._uppercaseFirst = function(s) { return s.charAt(0).toUpperCase(); }
-
- /* accepts the cells data and builds the corresponding TR nodes
- * @param rows a list of list of couples (daynum, cssprops)
+ /**
+ * .. function:: Calendar._uppercaseFirst(s)
+ *
+ * utility function (the only use for now is inside the calendar)
*/
- this._domForRows = function(rows) {
- var lines = []
- for (i=0; i<rows.length; i++) {
- lines.push(TR(null, map(this._makecell, rows[i])));
- }
- return lines;
+ this._uppercaseFirst = function(s) {
+ return s.charAt(0).toUpperCase();
}
- /* builds the calendar headers */
+ /**
+ * .. function:: Calendar._domForRows(rows)
+ *
+ * accepts the cells data and builds the corresponding TR nodes
+ *
+ * * `rows`, a list of list of couples (daynum, cssprops)
+ */
+ this._domForRows = function(rows) {
+ var lines = [];
+ for (i = 0; i < rows.length; i++) {
+ lines.push(TR(null, map(this._makecell, rows[i])));
+ }
+ return lines;
+ };
+
+ /**
+ * .. function:: Calendar._headdisplay(row)
+ *
+ * builds the calendar headers
+ */
this._headdisplay = function(row) {
- if (_CAL_HEADER) {
- return _CAL_HEADER;
- }
- daynames = map(this._uppercaseFirst, DAYNAMES);
- _CAL_HEADER = TR(null, map(partial(TH, null), daynames));
- return _CAL_HEADER;
- }
-
+ if (_CAL_HEADER) {
+ return _CAL_HEADER;
+ }
+ var self = this;
+ var _th = function(day) {
+ return TH(null, self._uppercaseFirst(day));
+ };
+ return TR(null, map(_th, DAYNAMES));
+ };
+
this._getrows = function() {
- var rows = [];
- var firstday = new Date(this.year, this.month, 1);
- var stopdate = firstday.nextMonth();
- var curdate = firstday.sub(firstday.getRealDay());
- while (curdate.getTime() < stopdate) {
- var row = []
- for (var i=0; i<7; i++) {
- if (curdate.getMonth() == this.month) {
- props = curdate.equals(TODAY) ? this.todayprops:this.cellprops;
- row.push([props, curdate.getDate()]);
- } else {
- row.push([this.cellprops, ""]);
- }
- curdate.iadd(1);
- }
- rows.push(row);
- }
- return rows;
+ var rows = [];
+ var firstday = new Date(this.year, this.month, 1);
+ var stopdate = firstday.nextMonth();
+ var curdate = firstday.sub(firstday.getRealDay());
+ while (curdate.getTime() < stopdate) {
+ var row = []
+ for (var i = 0; i < 7; i++) {
+ if (curdate.getMonth() == this.month) {
+ props = curdate.equals(TODAY) ? this.todayprops: this.cellprops;
+ row.push([props, curdate.getDate()]);
+ } else {
+ row.push([this.cellprops, ""]);
+ }
+ curdate.iadd(1);
+ }
+ rows.push(row);
+ }
+ return rows;
}
this._makecal = function() {
- var rows = this._getrows();
- var monthname = MONTHNAMES[this.month] + " " + this.year;
- var prevlink = "javascript: togglePreviousMonth('" + this.containerId + "');";
- var nextlink = "javascript: toggleNextMonth('" + this.containerId + "');";
- this.domtable = TABLE({'class': this.cssclass},
- THEAD(null, TR(null,
- TH(null, A({'href' : prevlink}, "<<")),
- // IE 6/7 requires colSpan instead of colspan
- TH({'colSpan': 5, 'colspan':5, 'style' : "text-align: center;"}, monthname),
- TH(null, A({'href' : nextlink}, ">>")))),
- TBODY(null,
- this._headdisplay(),
- this._domForRows(rows))
- );
- return this.domtable;
+ var rows = this._getrows();
+ var monthname = MONTHNAMES[this.month] + " " + this.year;
+ var prevlink = "javascript: togglePreviousMonth('" + this.containerId + "');";
+ var nextlink = "javascript: toggleNextMonth('" + this.containerId + "');";
+ this.domtable = TABLE({
+ 'class': this.cssclass
+ },
+ THEAD(null, TR(null, TH(null, A({
+ 'href': prevlink
+ },
+ "<<")),
+ // IE 6/7 requires colSpan instead of colspan
+ TH({
+ 'colSpan': 5,
+ 'colspan': 5,
+ 'style': "text-align: center;"
+ },
+ monthname), TH(null, A({
+ 'href': nextlink
+ },
+ ">>")))), TBODY(null, this._headdisplay(), this._domForRows(rows)));
+ return this.domtable;
}
this._updateDiv = function() {
- if (!this.domtable) {
- this._makecal();
- }
- jqNode(this.containerId).empty().append(this.domtable);
- // replaceChildNodes($(this.containerId), this.domtable);
+ if (!this.domtable) {
+ this._makecal();
+ }
+ cw.jqNode(this.containerId).empty().append(this.domtable);
+ // replaceChildNodes($(this.containerId), this.domtable);
}
this.displayNextMonth = function() {
- this.domtable = null;
- if (this.month == 11) {
- this.year++;
- }
- this.month = (this.month+1) % 12;
- this._updateDiv();
+ this.domtable = null;
+ if (this.month == 11) {
+ this.year++;
+ }
+ this.month = (this.month + 1) % 12;
+ this._updateDiv();
}
this.displayPreviousMonth = function() {
- this.domtable = null;
- if (this.month == 0) {
- this.year--;
- }
- this.month = (this.month+11) % 12;
- this._updateDiv();
+ this.domtable = null;
+ if (this.month == 0) {
+ this.year--;
+ }
+ this.month = (this.month + 11) % 12;
+ this._updateDiv();
}
-
+
this.show = function() {
- if (!this.visible) {
- container = jqNode(this.containerId);
- if (!this.domtable) {
- this._makecal();
- }
- container.empty().append(this.domtable);
- toggleVisibility(container);
- this.visible = true;
- }
+ if (!this.visible) {
+ container = cw.jqNode(this.containerId);
+ if (!this.domtable) {
+ this._makecal();
+ }
+ container.empty().append(this.domtable);
+ toggleVisibility(container);
+ this.visible = true;
+ }
}
this.hide = function(event) {
- var self;
- if (event) {
- self = event.data.self;
- } else {
- self = this;
- }
- if (self.visible) {
- toggleVisibility(self.containerId);
- self.visible = false;
- }
+ var self;
+ if (event) {
+ self = event.data.self;
+ } else {
+ self = this;
+ }
+ if (self.visible) {
+ toggleVisibility(self.containerId);
+ self.visible = false;
+ }
}
this.toggle = function() {
- if (this.visible) {
- this.hide();
- }
- else {
- this.show();
- }
+ if (this.visible) {
+ this.hide();
+ }
+ else {
+ this.show();
+ }
}
// call hide() when the user explicitly sets the focus on the matching input
- jqNode(inputId).bind('focus', {'self': this}, this.hide); // connect(inputId, 'onfocus', this, 'hide');
+ cw.jqNode(inputId).bind('focus', {
+ 'self': this
+ },
+ this.hide); // connect(inputId, 'onfocus', this, 'hide');
};
// keep track of each calendar created
Calendar.REGISTRY = {};
-/*
+/**
+ * .. function:: toggleCalendar(containerId, inputId, year, month)
+ *
* popup / hide calendar associated to `containerId`
- */
+ */
function toggleCalendar(containerId, inputId, year, month) {
var cal = Calendar.REGISTRY[containerId];
if (!cal) {
- cal = new Calendar(containerId, inputId, year, month);
- Calendar.REGISTRY[containerId] = cal;
+ cal = new Calendar(containerId, inputId, year, month);
+ Calendar.REGISTRY[containerId] = cal;
}
/* hide other calendars */
for (containerId in Calendar.REGISTRY) {
- var othercal = Calendar.REGISTRY[containerId];
- if (othercal !== cal) {
- othercal.hide();
- }
+ var othercal = Calendar.REGISTRY[containerId];
+ if (othercal !== cal) {
+ othercal.hide();
+ }
}
cal.toggle();
}
-
-/*
+/**
+ * .. function:: toggleNextMonth(containerId)
+ *
* ask for next month to calendar displayed in `containerId`
*/
function toggleNextMonth(containerId) {
@@ -217,7 +259,9 @@
cal.displayNextMonth();
}
-/*
+/**
+ * .. function:: togglePreviousMonth(containerId)
+ *
* ask for previous month to calendar displayed in `containerId`
*/
function togglePreviousMonth(containerId) {
@@ -225,8 +269,9 @@
cal.displayPreviousMonth();
}
-
-/*
+/**
+ * .. function:: dateSelected(cell, containerId)
+ *
* Callback called when the user clicked on a cell in the popup calendar
*/
function dateSelected(cell, containerId) {
@@ -236,86 +281,82 @@
// the only way understood by both IE and Mozilla. Otherwise,
// IE accepts innerText and mozilla accepts textContent
var selectedDate = new Date(cal.year, cal.month, cell.innerHTML, 12);
- var xxx = remoteExec("format_date", toISOTimestamp(selectedDate));
+ var xxx = remoteExec("format_date", cw.utils.toISOTimestamp(selectedDate));
input.value = xxx;
cal.hide();
}
-function whichElement(e)
-{
-var targ;
-if (!e)
- {
- var e=window.event;
- }
-if (e.target)
- {
- targ=e.target;
- }
-else if (e.srcElement)
- {
- targ=e.srcElement;
- }
-if (targ.nodeType==3) // defeat Safari bug
- {
- targ = targ.parentNode;
- }
- return targ;
+function whichElement(e) {
+ var targ;
+ if (!e) {
+ var e = window.event;
+ }
+ if (e.target) {
+ targ = e.target;
+ }
+ else if (e.srcElement) {
+ targ = e.srcElement;
+ }
+ if (targ.nodeType == 3) // defeat Safari bug
+ {
+ targ = targ.parentNode;
+ }
+ return targ;
}
function getPosition(element) {
- var left;
- var top;
- var offset;
- // TODO: deal scrollbar positions also!
- left = element.offsetLeft;
- top = element.offsetTop;
+ var left;
+ var top;
+ var offset;
+ // TODO: deal scrollbar positions also!
+ left = element.offsetLeft;
+ top = element.offsetTop;
- if (element.offsetParent != null)
- {
- offset = getPosition(element.offsetParent);
- left = left + offset[0];
- top = top + offset[1];
-
+ if (element.offsetParent != null) {
+ offset = getPosition(element.offsetParent);
+ left = left + offset[0];
+ top = top + offset[1];
+
}
- return [left, top];
+ return [left, top];
}
function getMouseInBlock(event) {
- var elt = event.target;
- var x = event.clientX;
- var y = event.clientY;
- var w = elt.clientWidth;
- var h = elt.clientHeight;
- var offset = getPosition(elt);
+ var elt = event.target;
+ var x = event.clientX;
+ var y = event.clientY;
+ var w = elt.clientWidth;
+ var h = elt.clientHeight;
+ var offset = getPosition(elt);
- x = 1.0*(x-offset[0])/w;
- y = 1.0*(y-offset[1])/h;
- return [x, y];
+ x = 1.0 * (x - offset[0]) / w;
+ y = 1.0 * (y - offset[1]) / h;
+ return [x, y];
}
function getHourFromMouse(event, hmin, hmax) {
- var pos = getMouseInBlock(event);
- var y = pos[1];
- return Math.floor((hmax-hmin)*y + hmin);
+ var pos = getMouseInBlock(event);
+ var y = pos[1];
+ return Math.floor((hmax - hmin) * y + hmin);
}
function addCalendarItem(event, hmin, hmax, year, month, day, duration, baseurl) {
- var hour = getHourFromMouse(event, hmin, hmax);
+ var hour = getHourFromMouse(event, hmin, hmax);
+
+ if (0 <= hour && hour < 24) {
+ baseurl += "&start=" + year + "%2F" + month + "%2F" + day + "%20" + hour + ":00";
+ baseurl += "&stop=" + year + "%2F" + month + "%2F" + day + "%20" + (hour + duration) + ":00";
- if (0<=hour && hour < 24) {
- baseurl += "&start="+year+"%2F"+month+"%2F"+day+"%20"+hour+":00";
- baseurl += "&stop="+year+"%2F"+month+"%2F"+day+"%20"+(hour+duration)+":00";
-
- stopPropagation(event);
- window.location.assign(baseurl);
- return false;
- }
- return true;
+ stopPropagation(event);
+ window.location.assign(baseurl);
+ return false;
+ }
+ return true;
}
function stopPropagation(event) {
- event.cancelBubble = true;
- if (event.stopPropagation) event.stopPropagation();
+ event.cancelBubble = true;
+ if (event.stopPropagation) event.stopPropagation();
}
-
+
CubicWeb.provide('calendar.js');
+
--- a/web/data/cubicweb.compat.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.compat.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,546 +1,201 @@
-/* MochiKit -> jQuery compatibility module */
-
-function forEach(array, func) {
- for (var i=0, length=array.length; i<length; i++) {
- func(array[i]);
- }
-}
-
-// XXX looks completely unused (candidate for removal)
-function getElementsByTagAndClassName(tag, klass, root) {
- root = root || document;
- // FIXME root is not used in this compat implementation
- return jQuery(tag + '.' + klass);
-}
-
-/* jQUery flattens arrays returned by the mapping function:
- >>> y = ['a:b:c', 'd:e']
- >>> jQuery.map(y, function(y) { return y.split(':');})
- ["a", "b", "c", "d", "e"]
- // where one would expect:
- [ ["a", "b", "c"], ["d", "e"] ]
- XXX why not the same argument order as $.map and forEach ?
-*/
-function map(func, array) {
- var result = [];
- for (var i=0, length=array.length;
- i<length;
- i++) {
- result.push(func(array[i]));
- }
- return result;
-}
-
-function findValue(array, element) {
- return jQuery.inArray(element, array);
-}
-
-function filter(func, array) {
- return jQuery.grep(array, func);
-}
-
-function noop() {}
-
-function addElementClass(node, klass) {
- jQuery(node).addClass(klass);
-}
-
-// XXX looks completely unused (candidate for removal)
-function toggleElementClass(node, klass) {
- jQuery(node).toggleClass(klass);
-}
-
-function removeElementClass(node, klass) {
- jQuery(node).removeClass(klass);
-}
-
-hasElementClass = jQuery.className.has;
+cw.utils.movedToNamespace(['log', 'jqNode', 'getNode', 'evalJSON', 'urlEncode',
+ 'swapDOM'], cw);
+cw.utils.movedToNamespace(['nodeWalkDepthFirst', 'formContents', 'isArray',
+ 'isString', 'isArrayLike', 'sliceList',
+ 'toISOTimestamp'], cw.utils);
-function partial(func) {
- var args = sliceList(arguments, 1);
- return function() {
- return func.apply(null, merge(args, arguments));
- };
-}
-
-
-function log() {
- // XXX dummy implementation
- // console.log.apply(arguments); ???
- var args = [];
- for (var i=0; i<arguments.length; i++) {
- args.push(arguments[i]);
- }
- if (typeof(window) != "undefined" && window.console
- && window.console.log) {
- window.console.log(args.join(' '));
- }
-}
-
-function getNodeAttribute(node, attribute) {
- return jQuery(node).attr(attribute);
-}
-
-function isArray(it){ // taken from dojo
- return it && (it instanceof Array || typeof it == "array");
-}
-
-function isString(it){ // taken from dojo
- return !!arguments.length && it != null && (typeof it == "string" || it instanceof String);
-}
-
-
-function isArrayLike(it) { // taken from dojo
- return (it && it !== undefined &&
- // keep out built-in constructors (Number, String, ...) which have length
- // properties
- !isString(it) && !jQuery.isFunction(it) &&
- !(it.tagName && it.tagName.toLowerCase() == 'form') &&
- (isArray(it) || isFinite(it.length)));
-}
-
-
-function getNode(node) {
- if (typeof(node) == 'string') {
- return document.getElementById(node);
- }
- return node;
-}
-
-/* safe version of jQuery('#nodeid') because we use ':' in nodeids
- * which messes with jQuery selection mechanism
- */
-function jqNode(node) {
- node = getNode(node);
- if (node) {
- return jQuery(node);
- }
- return null;
-}
-
-function evalJSON(json) { // trust source
- return eval("(" + json + ")");
-}
-
-function urlEncode(str) {
- if (typeof(encodeURIComponent) != "undefined") {
- return encodeURIComponent(str).replace(/\'/g, '%27');
- } else {
- return escape(str).replace(/\+/g, '%2B').replace(/\"/g,'%22').rval.replace(/\'/g, '%27');
- }
+if ($.noop === undefined) {
+ function noop() {}
+} else {
+ noop = cw.utils.deprecatedFunction(
+ '[3.9] noop() is deprecated, use $.noop() instead (XXX requires jQuery 1.4)',
+ $.noop);
}
-function swapDOM(dest, src) {
- dest = getNode(dest);
- var parent = dest.parentNode;
- if (src) {
- src = getNode(src);
- parent.replaceChild(src, dest);
- } else {
- parent.removeChild(dest);
+// ========== ARRAY EXTENSIONS ========== ///
+Array.prototype.contains = cw.utils.deprecatedFunction(
+ '[3.9] array.contains(elt) is deprecated, use $.inArray(elt, array) instead',
+ function(element) {
+ return jQuery.inArray(element, this) != - 1;
}
- return src;
-}
+);
-function replaceChildNodes(node/*, nodes...*/) {
- var elem = getNode(node);
- arguments[0] = elem;
- var child;
- while ((child = elem.firstChild)) {
- elem.removeChild(child);
+// ========== END OF ARRAY EXTENSIONS ========== ///
+forEach = cw.utils.deprecatedFunction(
+ '[3.9] forEach() is deprecated, use $.each() instead',
+ function(array, func) {
+ return $.each(array, func);
}
- if (arguments.length < 2) {
- return elem;
- } else {
- for (var i=1; i<arguments.length; i++) {
- elem.appendChild(arguments[i]);
- }
- return elem;
- }
-}
-
-update = jQuery.extend;
-
-
-function createDomFunction(tag) {
+);
- function builddom(params, children) {
- var node = document.createElement(tag);
- for (key in params) {
- var value = params[key];
- if (key.substring(0, 2) == 'on') {
- // this is an event handler definition
- if (typeof value == 'string') {
- // litteral definition
- value = new Function(value);
- }
- node[key] = value;
- } else { // normal node attribute
- jQuery(node).attr(key, params[key]);
- }
- }
- if (children) {
- if (!isArrayLike(children)) {
- children = [children];
- for (var i=2; i<arguments.length; i++) {
- var arg = arguments[i];
- if (isArray(arg)) {
- children = merge(children, arg);
- } else {
- children.push(arg);
- }
- }
- }
- for (var i=0; i<children.length; i++) {
- var child = children[i];
- if (typeof child == "string" || typeof child == "number") {
- child = document.createTextNode(child);
- }
- node.appendChild(child);
- }
- }
- return node;
+/**
+ * .. function:: cw.utils.deprecatedFunction(msg, function)
+ *
+ * jQUery flattens arrays returned by the mapping function:
+ * >>> y = ['a:b:c', 'd:e']
+ * >>> jQuery.map(y, function(y) { return y.split(':');})
+ * ["a", "b", "c", "d", "e"]
+ * // where one would expect:
+ * [ ["a", "b", "c"], ["d", "e"] ]
+ * XXX why not the same argument order as $.map and forEach ?
+ */
+map = cw.utils.deprecatedFunction(
+ '[3.9] map() is deprecated, use $.map instead',
+ function(func, array) {
+ var result = [];
+ for (var i = 0, length = array.length; i < length; i++) {
+ result.push(func(array[i]));
+ }
+ return result;
}
- return builddom;
-}
+);
+
+findValue = cw.utils.deprecatedFunction(
+ '[3.9] findValue(array, elt) is deprecated, use $.inArray(elt, array) instead',
+ function(array, element) {
+ return jQuery.inArray(element, array);
+ }
+);
-A = createDomFunction('a');
-BUTTON = createDomFunction('button');
-BR = createDomFunction('br');
-CANVAS = createDomFunction('canvas');
-DD = createDomFunction('dd');
-DIV = createDomFunction('div');
-DL = createDomFunction('dl');
-DT = createDomFunction('dt');
-FIELDSET = createDomFunction('fieldset');
-FORM = createDomFunction('form');
-H1 = createDomFunction('H1');
-H2 = createDomFunction('H2');
-H3 = createDomFunction('H3');
-H4 = createDomFunction('H4');
-H5 = createDomFunction('H5');
-H6 = createDomFunction('H6');
-HR = createDomFunction('hr');
-IMG = createDomFunction('img');
-INPUT = createDomFunction('input');
-LABEL = createDomFunction('label');
-LEGEND = createDomFunction('legend');
-LI = createDomFunction('li');
-OL = createDomFunction('ol');
-OPTGROUP = createDomFunction('optgroup');
-OPTION = createDomFunction('option');
-P = createDomFunction('p');
-PRE = createDomFunction('pre');
-SELECT = createDomFunction('select');
-SPAN = createDomFunction('span');
-STRONG = createDomFunction('strong');
-TABLE = createDomFunction('table');
-TBODY = createDomFunction('tbody');
-TD = createDomFunction('td');
-TEXTAREA = createDomFunction('textarea');
-TFOOT = createDomFunction('tfoot');
-TH = createDomFunction('th');
-THEAD = createDomFunction('thead');
-TR = createDomFunction('tr');
-TT = createDomFunction('tt');
-UL = createDomFunction('ul');
+filter = cw.utils.deprecatedFunction(
+ '[3.9] filter(func, array) is deprecated, use $.grep(array, f) instead',
+ function(func, array) {
+ return $.grep(array, func);
+ }
+);
+
+addElementClass = cw.utils.deprecatedFunction(
+ '[3.9] addElementClass(node, cls) is depcreated, use $(node).addClass(cls) instead',
+ function(node, klass) {
+ $(node).addClass(klass);
+ }
+);
+
+removeElementClass = cw.utils.deprecatedFunction(
+ '[3.9] removeElementClass(node, cls) is depcreated, use $(node).removeClass(cls) instead',
+ function(node, klass) {
+ $(node).removeClass(klass);
+ }
+);
-// cubicweb specific
-//IFRAME = createDomFunction('iframe');
-function IFRAME(params){
- if ('name' in params){
- try {
- var node = document.createElement('<iframe name="'+params['name']+'">');
- } catch (ex) {
- var node = document.createElement('iframe');
- node.id = node.name = params.name;
+hasElementClass = cw.utils.deprecatedFunction(
+ '[3.9] hasElementClass(node, cls) is depcreated, use $.className.has(node, cls)',
+ function(node, klass) {
+ return $.className.has(node, klass);
+ }
+);
+
+getNodeAttribute = cw.utils.deprecatedFunction(
+ '[3.9] getNodeAttribute(node, attr) is deprecated, use $(node).attr(attr)',
+ function(node, attribute) {
+ return $(node).attr(attribute);
}
- }
- else{
- var node = document.createElement('iframe');
- }
- for (key in params) {
- if (key != 'name'){
- var value = params[key];
- if (key.substring(0, 2) == 'on') {
- // this is an event handler definition
- if (typeof value == 'string') {
- // litteral definition
- value = new Function(value);
- }
- node[key] = value;
- } else { // normal node attribute
- node.setAttribute(key, params[key]);
- }
+);
+
+getNode = cw.utils.deprecatedFunction(
+ '[3.9] getNode(nodeid) is deprecated, use $(#nodeid) instead',
+ function(node) {
+ if (typeof node == 'string') {
+ return document.getElementById(node);
+ }
+ return node;
}
- }
- return node;
-}
+);
-
-// dummy ultra minimalist implementation on deferred for jQuery
+/**
+ * .. function:: Deferred
+ *
+ * dummy ultra minimalist implementation on deferred for jQuery
+ */
function Deferred() {
this.__init__(this);
}
jQuery.extend(Deferred.prototype, {
__init__: function() {
- this._onSuccess = [];
- this._onFailure = [];
- this._req = null;
+ this._onSuccess = [];
+ this._onFailure = [];
+ this._req = null;
this._result = null;
this._error = null;
},
addCallback: function(callback) {
if (this._req.readyState == 4) {
- if (this._result) { callback.apply(null, this._result, this._req); }
+ if (this._result) {
+ var args = [this._result, this._req];
+ jQuery.merge(args, cw.utils.sliceList(arguments, 1));
+ callback.apply(null, args);
+ }
}
- else { this._onSuccess.push([callback, sliceList(arguments, 1)]); }
- return this;
+ else {
+ this._onSuccess.push([callback, cw.utils.sliceList(arguments, 1)]);
+ }
+ return this;
},
addErrback: function(callback) {
if (this._req.readyState == 4) {
- if (this._error) { callback.apply(null, this._error, this._req); }
+ if (this._error) {
+ callback.apply(null, [this._error, this._req]);
+ }
}
- else { this._onFailure.push([callback, sliceList(arguments, 1)]); }
- return this;
+ else {
+ this._onFailure.push([callback, cw.utils.sliceList(arguments, 1)]);
+ }
+ return this;
},
success: function(result) {
this._result = result;
- try {
- for (var i=0; i<this._onSuccess.length; i++) {
- var callback = this._onSuccess[i][0];
- var args = merge([result, this._req], this._onSuccess[i][1]);
- callback.apply(null, args);
- }
- } catch (error) {
- this.error(this.xhr, null, error);
- }
+ try {
+ for (var i = 0; i < this._onSuccess.length; i++) {
+ var callback = this._onSuccess[i][0];
+ var args = [result, this._req];
+ jQuery.merge(args, this._onSuccess[i][1]);
+ callback.apply(null, args);
+ }
+ } catch(error) {
+ this.error(this.xhr, null, error);
+ }
},
error: function(xhr, status, error) {
this._error = error;
- for (var i=0; i<this._onFailure.length; i++) {
- var callback = this._onFailure[i][0];
- var args = merge([error, this._req], this._onFailure[i][1]);
- callback.apply(null, args);
- }
+ for (var i = 0; i < this._onFailure.length; i++) {
+ var callback = this._onFailure[i][0];
+ var args = [error, this._req];
+ jQuery.merge(args, this._onFailure[i][1]);
+ callback.apply(null, args);
+ }
}
});
-
-/*
- * Asynchronously load an url and return a deferred
- * whose callbacks args are decoded according to
- * the Content-Type response header
- */
-function loadRemote(url, data, reqtype) {
- var d = new Deferred();
- jQuery.ajax({
- url: url,
- type: reqtype,
- data: data,
-
- beforeSend: function(xhr) {
- d._req = xhr;
- },
-
- success: function(data, status) {
- if (d._req.getResponseHeader("content-type") == 'application/json') {
- data = evalJSON(data);
- }
- d.success(data);
- },
-
- error: function(xhr, status, error) {
- try {
- if (xhr.status == 500) {
- var reason_dict = evalJSON(xhr.responseText);
- d.error(xhr, status, reason_dict['reason']);
- return;
- }
- } catch(exc) {
- log('error with server side error report:' + exc);
- }
- d.error(xhr, status, null);
- }
- });
- return d;
-}
-
-
-/** @id MochiKit.DateTime.toISOTime */
-toISOTime = function (date, realISO/* = false */) {
- if (typeof(date) == "undefined" || date === null) {
- return null;
- }
- var hh = date.getHours();
- var mm = date.getMinutes();
- var ss = date.getSeconds();
- var lst = [
- ((realISO && (hh < 10)) ? "0" + hh : hh),
- ((mm < 10) ? "0" + mm : mm),
- ((ss < 10) ? "0" + ss : ss)
- ];
- return lst.join(":");
-};
-
-_padTwo = function (n) {
- return (n > 9) ? n : "0" + n;
-};
-
-/** @id MochiKit.DateTime.toISODate */
-toISODate = function (date) {
- if (typeof(date) == "undefined" || date === null) {
- return null;
- }
- return [
- date.getFullYear(),
- _padTwo(date.getMonth() + 1),
- _padTwo(date.getDate())
- ].join("-");
-};
-
-
-/** @id MochiKit.DateTime.toISOTimeStamp */
-toISOTimestamp = function (date, realISO/* = false*/) {
- if (typeof(date) == "undefined" || date === null) {
- return null;
- }
- var sep = realISO ? "T" : " ";
- var foot = realISO ? "Z" : "";
- if (realISO) {
- date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
- }
- return toISODate(date) + sep + toISOTime(date, realISO) + foot;
-};
-
-
-
-/* depth-first implementation of the nodeWalk function found
- * in MochiKit.Base
- * cf. http://mochikit.com/doc/html/MochiKit/Base.html#fn-nodewalk
+/**
+ * The only known usage of KEYS is in the tag cube. Once cubicweb-tag 1.7.0 is out,
+ * this current definition can be removed.
*/
-function nodeWalkDepthFirst(node, visitor) {
- var children = visitor(node);
- if (children) {
- for(var i=0; i<children.length; i++) {
- nodeWalkDepthFirst(children[i], visitor);
- }
- }
-}
-
-
-/* Returns true if all the given Array-like or string arguments are not empty (obj.length > 0) */
-function isNotEmpty(obj) {
- for (var i = 0; i < arguments.length; i++) {
- var o = arguments[i];
- if (!(o && o.length)) {
- return false;
- }
- }
- return true;
-}
-
-/** this implementation comes from MochiKit */
-function formContents(elem/* = document.body */) {
- var names = [];
- var values = [];
- if (typeof(elem) == "undefined" || elem === null) {
- elem = document.body;
- } else {
- elem = getNode(elem);
- }
- nodeWalkDepthFirst(elem, function (elem) {
- var name = elem.name;
- if (isNotEmpty(name)) {
- var tagName = elem.tagName.toUpperCase();
- if (tagName === "INPUT"
- && (elem.type == "radio" || elem.type == "checkbox")
- && !elem.checked
- ) {
- return null;
- }
- if (tagName === "SELECT") {
- if (elem.type == "select-one") {
- if (elem.selectedIndex >= 0) {
- var opt = elem.options[elem.selectedIndex];
- var v = opt.value;
- if (!v) {
- var h = opt.outerHTML;
- // internet explorer sure does suck.
- if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
- v = opt.text;
- }
- }
- names.push(name);
- values.push(v);
- return null;
- }
- // no form elements?
- names.push(name);
- values.push("");
- return null;
- } else {
- var opts = elem.options;
- if (!opts.length) {
- names.push(name);
- values.push("");
- return null;
- }
- for (var i = 0; i < opts.length; i++) {
- var opt = opts[i];
- if (!opt.selected) {
- continue;
- }
- var v = opt.value;
- if (!v) {
- var h = opt.outerHTML;
- // internet explorer sure does suck.
- if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
- v = opt.text;
- }
- }
- names.push(name);
- values.push(v);
- }
- return null;
- }
- }
- if (tagName === "FORM" || tagName === "P" || tagName === "SPAN"
- || tagName === "DIV"
- ) {
- return elem.childNodes;
- }
- names.push(name);
- values.push(elem.value || '');
- return null;
- }
- return elem.childNodes;
- });
- return [names, values];
-}
-
-function merge(array1, array2) {
- var result = [];
- for (var i=0,length=arguments.length; i<length; i++) {
- var array = arguments[i];
- for (var j=0,alength=array.length; j<alength; j++) {
- result.push(array[j]);
- }
- }
- return result;
-}
-
var KEYS = {
KEY_ESC: 27,
KEY_ENTER: 13
};
+// XXX avoid crashes / backward compat
+CubicWeb = {
+ require: function(module) {},
+ provide: function(module) {}
+};
+jQuery(document).ready(function() {
+ jQuery(CubicWeb).trigger('server-response', [false, document]);
+});
+// XXX as of 2010-04-07, no known cube uses this
+jQuery(CubicWeb).bind('ajax-loaded', function() {
+ log('[3.7] "ajax-loaded" event is deprecated, use "server-response" instead');
+ jQuery(CubicWeb).trigger('server-response', [false, document]);
+});
+
+CubicWeb.provide('python.js');
--- a/web/data/cubicweb.edition.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.edition.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,141 +1,174 @@
-/*
+/**
+ * Functions dedicated to edition.
+ *
* :organization: Logilab
* :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+ *
*/
CubicWeb.require('python.js');
CubicWeb.require('htmlhelpers.js');
CubicWeb.require('ajax.js');
-
//============= Eproperty form functions =====================================//
-
-/* called on Eproperty key selection:
+/**
+ * .. function:: setPropValueWidget(varname, tabindex)
+ *
+ * called on Eproperty key selection:
* - get the selected value
* - get a widget according to the key by a sync query to the server
* - fill associated div with the returned html
*
- * @param varname the name of the variable as used in the original creation form
- * @param tabindex the tabindex that should be set on the widget
+ * * `varname`, the name of the variable as used in the original creation form
+ * * `tabindex`, the tabindex that should be set on the widget
*/
function setPropValueWidget(varname, tabindex) {
- var key = firstSelected(document.getElementById('pkey:'+varname));
+ var key = firstSelected(document.getElementById('pkey:' + varname));
if (key) {
- var args = {fname: 'prop_widget', pageid: pageid,
- arg: map(jQuery.toJSON, [key, varname, tabindex])};
- jqNode('div:value:'+varname).loadxhtml(JSON_BASE_URL, args, 'post');
+ var args = {
+ fname: 'prop_widget',
+ pageid: pageid,
+ arg: map(jQuery.toJSON, [key, varname, tabindex])
+ };
+ jqNode('div:value:' + varname).loadxhtml(JSON_BASE_URL, args, 'post');
}
}
-
// *** EDITION FUNCTIONS ****************************************** //
-
-/*
+/**
+ * .. function:: reorderTabindex(start, formid)
+ *
* this function is called when an AJAX form was generated to
* make sure tabindex remains consistent
*/
function reorderTabindex(start, formid) {
var form = getNode(formid || 'entityForm');
var inputTypes = ['INPUT', 'SELECT', 'TEXTAREA'];
- var tabindex = (start==null)?15:start;
+ var tabindex = (start == null) ? 15: start;
nodeWalkDepthFirst(form, function(elem) {
var tagName = elem.tagName.toUpperCase();
- if (inputTypes.contains(tagName)) {
- if (getNodeAttribute(elem, 'tabindex') != null) {
- tabindex += 1;
- elem.setAttribute('tabindex', tabindex);
- }
- return null;
- }
- return filter(isElementNode, elem.childNodes);
+ if (inputTypes.contains(tagName)) {
+ if (jQuery(elem).attr('tabindex') != null) {
+ tabindex += 1;
+ jQuery(elem).attr('tabindex', tabindex);
+ }
+ return null;
+ }
+ return jQuery.grep(elem.childNodes, isElementNode);
});
}
-
function showMatchingSelect(selectedValue, eid) {
if (selectedValue) {
- divId = 'div' + selectedValue + '_' + eid;
- var divNode = jQuery('#' + divId);
- if (!divNode.length) {
- var args = {vid: 'unrelateddivs', relation: selectedValue,
- rql: rql_for_eid(eid), '__notemplate': 1,
- callback: function() {_showMatchingSelect(eid, jQuery('#' + divId));}};
- jQuery('#unrelatedDivs_' + eid).loadxhtml(baseuri() + 'view', args, 'post', 'append');
- } else {
- _showMatchingSelect(eid, divNode);
- }
+ divId = 'div' + selectedValue + '_' + eid;
+ var divNode = jQuery('#' + divId);
+ if (!divNode.length) {
+ var args = {
+ vid: 'unrelateddivs',
+ relation: selectedValue,
+ rql: rql_for_eid(eid),
+ '__notemplate': 1,
+ callback: function() {
+ _showMatchingSelect(eid, jQuery('#' + divId));
+ }
+ };
+ jQuery('#unrelatedDivs_' + eid).loadxhtml(baseuri() + 'view', args, 'post', 'append');
+ } else {
+ _showMatchingSelect(eid, divNode);
+ }
} else {
- _showMatchingSelect(eid, null);
+ _showMatchingSelect(eid, null);
}
}
-
-// @param divNode is a jQuery selection
+/**
+ * .. function:: _showMatchingSelect(eid, divNode)
+ *
+ * * `divNode`, a jQuery selection
+ */
function _showMatchingSelect(eid, divNode) {
// hide all divs, and then show the matching one
// (would actually be better to directly hide the displayed one)
jQuery('#unrelatedDivs_' + eid).children().hide();
// divNode not found means 'no relation selected' (i.e. first blank item)
if (divNode && divNode.length) {
- divNode.show();
+ divNode.show();
}
}
-// this function builds a Handle to cancel pending insertion
+/**
+ * .. function:: buildPendingInsertHandle(elementId, element_name, selectNodeId, eid)
+ *
+ * this function builds a Handle to cancel pending insertion
+ */
function buildPendingInsertHandle(elementId, element_name, selectNodeId, eid) {
- jscall = "javascript: cancelPendingInsert('" + [elementId, element_name, selectNodeId, eid].join("', '") + "')";
- return A({'class' : 'handle', 'href' : jscall,
- 'title' : _("cancel this insert")}, '[x]');
+ jscall = "javascript: cancelPendingInsert('" + [elementId, element_name, selectNodeId, eid].join("', '") + "')";
+ return A({
+ 'class': 'handle',
+ 'href': jscall,
+ 'title': _("cancel this insert")
+ },
+ '[x]');
}
function buildEntityLine(relationName, selectedOptionNode, comboId, eid) {
- // textContent doesn't seem to work on selectedOptionNode
- var content = selectedOptionNode.firstChild.nodeValue;
- var handle = buildPendingInsertHandle(selectedOptionNode.id, 'tr', comboId, eid);
- var link = A({'href' : 'view?rql=' + selectedOptionNode.value,
- 'class' : 'editionPending', 'id' : 'a' + selectedOptionNode.id},
- content);
- var tr = TR({'id' : 'tr' + selectedOptionNode.id}, [ TH(null, relationName),
- TD(null, [handle, link])
- ]);
- try {
- var separator = getNode('relationSelectorRow_' + eid);
- //dump('relationSelectorRow_' + eid) XXX warn dump is not implemented in konqueror (at least)
- // XXX Warning: separator.parentNode is not (always ?) the
- // table itself, but an intermediate node (TableSectionElement)
- var tableBody = separator.parentNode;
- tableBody.insertBefore(tr, separator);
- } catch(ex) {
- log("got exception(2)!" + ex);
- }
+ // textContent doesn't seem to work on selectedOptionNode
+ var content = selectedOptionNode.firstChild.nodeValue;
+ var handle = buildPendingInsertHandle(selectedOptionNode.id, 'tr', comboId, eid);
+ var link = A({
+ 'href': 'view?rql=' + selectedOptionNode.value,
+ 'class': 'editionPending',
+ 'id': 'a' + selectedOptionNode.id
+ },
+ content);
+ var tr = TR({
+ 'id': 'tr' + selectedOptionNode.id
+ },
+ [TH(null, relationName), TD(null, [handle, link])]);
+ try {
+ var separator = getNode('relationSelectorRow_' + eid);
+ //dump('relationSelectorRow_' + eid) XXX warn dump is not implemented in konqueror (at least)
+ // XXX Warning: separator.parentNode is not (always ?) the
+ // table itself, but an intermediate node (TableSectionElement)
+ var tableBody = separator.parentNode;
+ tableBody.insertBefore(tr, separator);
+ } catch(ex) {
+ log("got exception(2)!" + ex);
+ }
}
function buildEntityCell(relationName, selectedOptionNode, comboId, eid) {
var handle = buildPendingInsertHandle(selectedOptionNode.id, 'div_insert_', comboId, eid);
- var link = A({'href' : 'view?rql=' + selectedOptionNode.value,
- 'class' : 'editionPending', 'id' : 'a' + selectedOptionNode.id},
- content);
- var div = DIV({'id' : 'div_insert_' + selectedOptionNode.id}, [handle, link]);
+ var link = A({
+ 'href': 'view?rql=' + selectedOptionNode.value,
+ 'class': 'editionPending',
+ 'id': 'a' + selectedOptionNode.id
+ },
+ content);
+ var div = DIV({
+ 'id': 'div_insert_' + selectedOptionNode.id
+ },
+ [handle, link]);
try {
- var td = jQuery('#cell'+ relationName +'_'+eid);
- td.appendChild(div);
+ var td = jQuery('#cell' + relationName + '_' + eid);
+ td.appendChild(div);
} catch(ex) {
- alert("got exception(3)!" + ex);
+ alert("got exception(3)!" + ex);
}
}
function addPendingInsert(optionNode, eid, cell, relname) {
- var value = getNodeAttribute(optionNode, 'value');
+ var value = jQuery(optionNode).attr('value');
if (!value) {
- // occurs when the first element in the box is selected (which is not
- // an entity but the combobox title)
+ // occurs when the first element in the box is selected (which is not
+ // an entity but the combobox title)
return;
}
// 2nd special case
if (value.indexOf('http') == 0) {
- document.location = value;
- return;
+ document.location = value;
+ return;
}
// add hidden parameter
var entityForm = jQuery('#entityForm');
@@ -146,16 +179,16 @@
selectNode.removeChild(optionNode);
// add line in table
if (cell) {
- // new relation as a cell in multiple edit
- // var relation_name = relationSelected.getAttribute('value');
- // relation_name = relation_name.slice(0, relation_name.lastIndexOf('_'));
- buildEntityCell(relname, optionNode, selectNode.id, eid);
+ // new relation as a cell in multiple edit
+ // var relation_name = relationSelected.getAttribute('value');
+ // relation_name = relation_name.slice(0, relation_name.lastIndexOf('_'));
+ buildEntityCell(relname, optionNode, selectNode.id, eid);
}
else {
- var relationSelector = getNode('relationSelector_'+eid);
- var relationSelected = relationSelector.options[relationSelector.selectedIndex];
- // new relation as a line in simple edit
- buildEntityLine(relationSelected.text, optionNode, selectNode.id, eid);
+ var relationSelector = getNode('relationSelector_' + eid);
+ var relationSelected = relationSelector.options[relationSelector.selectedIndex];
+ // new relation as a line in simple edit
+ buildEntityLine(relationSelected.text, optionNode, selectNode.id, eid);
}
}
@@ -164,90 +197,122 @@
var entityView = jqNode('a' + elementId).text();
jqNode(element_name + elementId).remove();
if (comboId) {
- // re-insert option in combobox if it was taken from there
- var selectNode = getNode(comboId);
+ // re-insert option in combobox if it was taken from there
+ var selectNode = getNode(comboId);
// XXX what on object relation
- if (selectNode){
- var options = selectNode.options;
- var node_id = elementId.substring(0, elementId.indexOf(':'));
- options[options.length] = OPTION({'id' : elementId, 'value' : node_id}, entityView);
- }
+ if (selectNode) {
+ var options = selectNode.options;
+ var node_id = elementId.substring(0, elementId.indexOf(':'));
+ options[options.length] = OPTION({
+ 'id': elementId,
+ 'value': node_id
+ },
+ entityView);
+ }
}
elementId = elementId.substring(2, elementId.length);
remoteExec('remove_pending_insert', elementId.split(':'));
}
-// this function builds a Handle to cancel pending insertion
+/**
+ * .. function:: buildPendingDeleteHandle(elementId, eid)
+ *
+ * this function builds a Handle to cancel pending insertion
+ */
function buildPendingDeleteHandle(elementId, eid) {
- var jscall = "javascript: addPendingDelete('" + elementId + ', ' + eid + "');";
- return A({'href' : jscall, 'class' : 'pendingDeleteHandle',
- 'title' : _("delete this relation")}, '[x]');
+ var jscall = "javascript: addPendingDelete('" + elementId + ', ' + eid + "');";
+ return A({
+ 'href': jscall,
+ 'class': 'pendingDeleteHandle',
+ 'title': _("delete this relation")
+ },
+ '[x]');
}
-// @param nodeId eid_from:r_type:eid_to
+/**
+ * .. function:: addPendingDelete(nodeId, eid)
+ *
+ * * `nodeId`, eid_from:r_type:eid_to
+ */
function addPendingDelete(nodeId, eid) {
- var d = asyncRemoteExec('add_pending_delete', nodeId.split(':'));
- d.addCallback(function () {
- // and strike entity view
- jqNode('span' + nodeId).addClass('pendingDelete');
- // replace handle text
- jqNode('handle' + nodeId).text('+');
+ var d = loadRemote('json', ajaxFuncArgs('add_pending_delete', null, nodeId.split(':')));
+ d.addCallback(function() {
+ // and strike entity view
+ jqNode('span' + nodeId).addClass('pendingDelete');
+ // replace handle text
+ jqNode('handle' + nodeId).text('+');
});
}
-// @param nodeId eid_from:r_type:eid_to
+/**
+ * .. function:: cancelPendingDelete(nodeId, eid)
+ *
+ * * `nodeId`, eid_from:r_type:eid_to
+ */
function cancelPendingDelete(nodeId, eid) {
- var d = asyncRemoteExec('remove_pending_delete', nodeId.split(':'));
- d.addCallback(function () {
- // reset link's CSS class
- jqNode('span' + nodeId).removeClass('pendingDelete');
- // replace handle text
- jqNode('handle' + nodeId).text('x');
+ var d = loadRemote('json', ajaxFuncArgs('remove_pending_delete', null, nodeId.split(':')));
+ d.addCallback(function() {
+ // reset link's CSS class
+ jqNode('span' + nodeId).removeClass('pendingDelete');
+ // replace handle text
+ jqNode('handle' + nodeId).text('x');
});
}
-// @param nodeId eid_from:r_type:eid_to
+/**
+ * .. function:: togglePendingDelete(nodeId, eid)
+ *
+ * * `nodeId`, eid_from:r_type:eid_to
+ */
function togglePendingDelete(nodeId, eid) {
// node found means we should cancel deletion
- if ( hasElementClass(getNode('span' + nodeId), 'pendingDelete') ) {
- cancelPendingDelete(nodeId, eid);
+ if (jQuery.className.has(getNode('span' + nodeId), 'pendingDelete')) {
+ cancelPendingDelete(nodeId, eid);
} else {
- addPendingDelete(nodeId, eid);
+ addPendingDelete(nodeId, eid);
}
}
-
function selectForAssociation(tripletIdsString, originalEid) {
- var tripletlist = map(function (x) { return x.split(':'); },
- tripletIdsString.split('-'));
- var d = asyncRemoteExec('add_pending_inserts', tripletlist);
- d.addCallback(function () {
- var args = {vid: 'edition', __mode: 'normal',
- rql: rql_for_eid(originalEid)};
- document.location = 'view?' + asURL(args);
+ var tripletlist = map(function(x) {
+ return x.split(':');
+ },
+ tripletIdsString.split('-'));
+ var d = loadRemote('json', ajaxFuncArgs('add_pending_inserts', null, tripletlist));
+ d.addCallback(function() {
+ var args = {
+ vid: 'edition',
+ __mode: 'normal',
+ rql: rql_for_eid(originalEid)
+ };
+ document.location = 'view?' + asURL(args);
});
}
-
function updateInlinedEntitiesCounters(rtype, role) {
- jQuery('div.inline-' + rtype + '-' + role + '-slot span.icounter').each(function (i) {
- this.innerHTML = i+1;
+ jQuery('div.inline-' + rtype + '-' + role + '-slot span.icounter').each(function(i) {
+ this.innerHTML = i + 1;
});
}
-
-/*
+/**
+ * .. function:: addInlineCreationForm(peid, petype, ttype, rtype, role, i18nctx, insertBefore)
+ *
* makes an AJAX request to get an inline-creation view's content
- * @param peid : the parent entity eid
- * @param petype : the parent entity type
- * @param ttype : the target (inlined) entity type
- * @param rtype : the relation type between both entities
+ * * `peid`, the parent entity eid
+ *
+ * * `petype`, the parent entity type
+ *
+ * * `ttype`, the target (inlined) entity type
+ *
+ * * `rtype`, the relation type between both entities
*/
function addInlineCreationForm(peid, petype, ttype, rtype, role, i18nctx, insertBefore) {
insertBefore = insertBefore || getNode('add' + rtype + ':' + peid + 'link').parentNode;
- var d = asyncRemoteExec('inline_creation_form', peid, petype, ttype, rtype, role, i18nctx);
- d.addCallback(function (response) {
+ var args = ajaxFuncArgs('inline_creation_form', null, peid, petype, ttype, rtype, role, i18nctx);
+ var d = loadRemote('json', args);
+ d.addCallback(function(response) {
var dom = getDomFromResponse(response);
preprocessAjaxLoad(null, dom);
var form = jQuery(dom);
@@ -259,49 +324,54 @@
// if the inlined form contains a file input, we must force
// the form enctype to multipart/form-data
if (form.find('input:file').length) {
- // NOTE: IE doesn't support dynamic enctype modification, we have
- // to set encoding too.
- form.closest('form').attr('enctype', 'multipart/form-data')
- .attr('encoding', 'multipart/form-data');
+ // NOTE: IE doesn't support dynamic enctype modification, we have
+ // to set encoding too.
+ form.closest('form').attr('enctype', 'multipart/form-data').attr('encoding', 'multipart/form-data');
}
postAjaxLoad(dom);
});
- d.addErrback(function (xxx) {
+ d.addErrback(function(xxx) {
log('xxx =', xxx);
});
}
-/*
+/**
+ * .. function:: removeInlineForm(peid, rtype, role, eid, showaddnewlink)
+ *
* removes the part of the form used to edit an inlined entity
*/
function removeInlineForm(peid, rtype, role, eid, showaddnewlink) {
jqNode(['div', peid, rtype, eid].join('-')).slideUp('fast', function() {
- $(this).remove();
- updateInlinedEntitiesCounters(rtype, role);
+ $(this).remove();
+ updateInlinedEntitiesCounters(rtype, role);
});
if (showaddnewlink) {
- toggleVisibility(showaddnewlink);
+ toggleVisibility(showaddnewlink);
}
}
-/*
+/**
+ * .. function:: removeInlinedEntity(peid, rtype, eid)
+ *
* alternatively adds or removes the hidden input that make the
* edition of the relation `rtype` possible between `peid` and `eid`
- * @param peid : the parent entity eid
- * @param rtype : the relation type between both entities
- * @param eid : the inlined entity eid
+ * * `peid`, the parent entity eid
+ *
+ * * `rtype`, the relation type between both entities
+ *
+ * * `eid`, the inlined entity eid
*/
function removeInlinedEntity(peid, rtype, eid) {
// XXX work around the eid_param thing (eid + ':' + eid) for #471746
var nodeid = ['rel', peid, rtype, eid + ':' + eid].join('-');
var node = jqNode(nodeid);
- if (! node.attr('cubicweb:type')) {
+ if (!node.attr('cubicweb:type')) {
node.attr('cubicweb:type', node.val());
node.val('');
- var divid = ['div', peid, rtype, eid].join('-');
- jqNode(divid).fadeTo('fast', 0.5);
- var noticeid = ['notice', peid, rtype, eid].join('-');
- jqNode(noticeid).fadeIn('fast');
+ var divid = ['div', peid, rtype, eid].join('-');
+ jqNode(divid).fadeTo('fast', 0.5);
+ var noticeid = ['notice', peid, rtype, eid].join('-');
+ jqNode(noticeid).fadeIn('fast');
}
}
@@ -312,23 +382,23 @@
if (node.attr('cubicweb:type')) {
node.val(node.attr('cubicweb:type'));
node.attr('cubicweb:type', '');
- jqNode(['fs', peid, rtype, eid].join('-')).append(node);
+ jqNode(['fs', peid, rtype, eid].join('-')).append(node);
var divid = ['div', peid, rtype, eid].join('-');
- jqNode(divid).fadeTo('fast', 1);
+ jqNode(divid).fadeTo('fast', 1);
var noticeid = ['notice', peid, rtype, eid].join('-');
- jqNode(noticeid).hide();
+ jqNode(noticeid).hide();
}
}
function _clearPreviousErrors(formid) {
// on some case (eg max request size exceeded, we don't know the formid
if (formid) {
- jQuery('#' + formid + 'ErrorMessage').remove();
- jQuery('#' + formid + ' span.errorMsg').remove();
- jQuery('#' + formid + ' .error').removeClass('error');
+ jQuery('#' + formid + 'ErrorMessage').remove();
+ jQuery('#' + formid + ' span.errorMsg').remove();
+ jQuery('#' + formid + ' .error').removeClass('error');
} else {
- jQuery('span.errorMsg').remove();
- jQuery('.error').removeClass('error');
+ jQuery('span.errorMsg').remove();
+ jQuery('.error').removeClass('error');
}
}
@@ -336,69 +406,75 @@
var globalerrors = [];
var firsterrfield = null;
for (fieldname in errors) {
- var errmsg = errors[fieldname];
- if (!fieldname) {
- globalerrors.push(errmsg);
- } else {
- var fieldid = fieldname + ':' + eid;
- var suffixes = ['', '-subject', '-object'];
- var found = false;
- // XXX remove suffixes at some point
- for (var i=0, length=suffixes.length; i<length;i++) {
- var field = jqNode(fieldname + suffixes[i] + ':' + eid);
- if (field && getNodeAttribute(field, 'type') != 'hidden') {
- if ( !firsterrfield ) {
- firsterrfield = 'err-' + fieldid;
- }
- addElementClass(field, 'error');
- var span = SPAN({'id': 'err-' + fieldid, 'class': "errorMsg"}, errmsg);
- field.before(span);
- found = true;
- break;
- }
- }
- if (!found) {
- firsterrfield = formid;
- globalerrors.push(_(fieldname) + ' : ' + errmsg);
- }
- }
+ var errmsg = errors[fieldname];
+ if (!fieldname) {
+ globalerrors.push(errmsg);
+ } else {
+ var fieldid = fieldname + ':' + eid;
+ var suffixes = ['', '-subject', '-object'];
+ var found = false;
+ // XXX remove suffixes at some point
+ for (var i = 0, length = suffixes.length; i < length; i++) {
+ var field = jqNode(fieldname + suffixes[i] + ':' + eid);
+ if (field && jQuery(field).attr('type') != 'hidden') {
+ if (!firsterrfield) {
+ firsterrfield = 'err-' + fieldid;
+ }
+ jQuery(field).addClass('error');
+ var span = SPAN({
+ 'id': 'err-' + fieldid,
+ 'class': "errorMsg"
+ },
+ errmsg);
+ field.before(span);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ firsterrfield = formid;
+ globalerrors.push(_(fieldname) + ' : ' + errmsg);
+ }
+ }
}
if (globalerrors.length) {
- if (globalerrors.length == 1) {
- var innernode = SPAN(null, globalerrors[0]);
- } else {
- var innernode = UL(null, map(partial(LI, null), globalerrors));
- }
- // insert DIV and innernode before the form
- var div = DIV({'class' : "errorMessage", 'id': formid + 'ErrorMessage'});
- div.appendChild(innernode);
- jQuery('#' + formid).before(div);
+ if (globalerrors.length == 1) {
+ var innernode = SPAN(null, globalerrors[0]);
+ } else {
+ var innernode = UL(null, map(partial(LI, null), globalerrors));
+ }
+ // insert DIV and innernode before the form
+ var div = DIV({
+ 'class': "errorMessage",
+ 'id': formid + 'ErrorMessage'
+ });
+ div.appendChild(innernode);
+ jQuery('#' + formid).before(div);
}
return firsterrfield || formid;
}
-
function handleFormValidationResponse(formid, onsuccess, onfailure, result, cbargs) {
// Success
if (result[0]) {
- if (onsuccess) {
- onsuccess(result, formid, cbargs);
- } else {
- document.location.href = result[1];
- }
- return true;
+ if (onsuccess) {
+ onsuccess(result, formid, cbargs);
+ } else {
+ document.location.href = result[1];
+ }
+ return true;
}
- if (onfailure && !onfailure(result, formid, cbargs)) {
- return false;
+ if (onfailure && ! onfailure(result, formid, cbargs)) {
+ return false;
}
unfreezeFormButtons(formid);
// Failures
_clearPreviousErrors(formid);
var descr = result[1];
// Unknown structure
- if ( !isArrayLike(descr) || descr.length != 2 ) {
- updateMessage(descr);
- return false;
+ if (!isArrayLike(descr) || descr.length != 2) {
+ updateMessage(descr);
+ return false;
}
_displayValidationerrors(formid, descr[0], descr[1]);
updateMessage(_('please correct errors below'));
@@ -407,68 +483,102 @@
return false;
}
-
-/* unfreeze form buttons when the validation process is over*/
+/**
+ * .. function:: unfreezeFormButtons(formid)
+ *
+ * unfreeze form buttons when the validation process is over
+ */
function unfreezeFormButtons(formid) {
jQuery('#progress').hide();
// on some case (eg max request size exceeded, we don't know the formid
if (formid) {
- jQuery('#' + formid + ' .validateButton').removeAttr('disabled');
+ jQuery('#' + formid + ' .validateButton').removeAttr('disabled');
} else {
- jQuery('.validateButton').removeAttr('disabled');
+ jQuery('.validateButton').removeAttr('disabled');
}
return true;
}
-/* disable form buttons while the validation is being done */
+/**
+ * .. function:: freezeFormButtons(formid)
+ *
+ * disable form buttons while the validation is being done
+ */
function freezeFormButtons(formid) {
jQuery('#progress').show();
jQuery('#' + formid + ' .validateButton').attr('disabled', 'disabled');
return true;
}
-/* used by additional submit buttons to remember which button was clicked */
+/**
+ * .. function:: postForm(bname, bvalue, formid)
+ *
+ * used by additional submit buttons to remember which button was clicked
+ */
function postForm(bname, bvalue, formid) {
var form = getNode(formid);
if (bname) {
- var child = form.appendChild(INPUT({type: 'hidden', name: bname, value: bvalue}));
+ var child = form.appendChild(INPUT({
+ type: 'hidden',
+ name: bname,
+ value: bvalue
+ }));
}
var onsubmit = form.onsubmit;
if (!onsubmit || (onsubmit && onsubmit())) {
- form.submit();
+ form.submit();
}
if (bname) {
- jQuery(child).remove(); /* cleanup */
+ jQuery(child).remove();
+ /* cleanup */
}
}
-
-/* called on load to set target and iframeso object.
- * NOTE: this is a hack to make the XHTML compliant.
- * NOTE2: `object` nodes might be a potential replacement for iframes
- * NOTE3: there is a XHTML module allowing iframe elements but there
- * is still the problem of the form's `target` attribute
+/**
+ * .. function:: setFormsTarget(node)
+ *
+ * called on load to set target and iframeso object.
+ *
+ * .. note::
+ *
+ * this is a hack to make the XHTML compliant.
+ *
+ * .. note::
+ *
+ * `object` nodes might be a potential replacement for iframes
+ *
+ * .. note::
+ *
+ * there is a XHTML module allowing iframe elements but there
+ * is still the problem of the form's `target` attribute
*/
function setFormsTarget(node) {
var $node = jQuery(node || document.body);
- $node.find('form').each(function () {
- var form = jQuery(this);
- var target = form.attr('cubicweb:target');
- if (target) {
- form.attr('target', target);
- /* do not use display: none because some browsers ignore iframe
+ $node.find('form').each(function() {
+ var form = jQuery(this);
+ var target = form.attr('cubicweb:target');
+ if (target) {
+ form.attr('target', target);
+ /* do not use display: none because some browsers ignore iframe
* with no display */
- form.append(IFRAME({name: target, id: target,
- src: 'javascript: void(0)',
- width: '0px', height: '0px'}));
- }
+ form.append(IFRAME({
+ name: target,
+ id: target,
+ src: 'javascript: void(0)',
+ width: '0px',
+ height: '0px'
+ }));
+ }
});
}
-jQuery(document).ready(function() {setFormsTarget();});
+jQuery(document).ready(function() {
+ setFormsTarget();
+});
-
-/*
+/**
+ * .. function:: validateForm(formid, action, onsuccess, onfailure)
+ *
* called on traditionnal form submission : the idea is to try
* to post the form. If the post is successful, `validateForm` redirects
* to the appropriate URL. Otherwise, the validation errors are displayed
@@ -476,69 +586,110 @@
*/
function validateForm(formid, action, onsuccess, onfailure) {
try {
- var zipped = formContents(formid);
- var d = asyncRemoteExec('validate_form', action, zipped[0], zipped[1]);
- } catch (ex) {
- log('got exception', ex);
- return false;
+ var zipped = formContents(formid);
+ var args = ajaxFuncArgs('validate_form', null, action, zipped[0], zipped[1]);
+ var d = loadRemote('json', args);
+ } catch(ex) {
+ log('got exception', ex);
+ return false;
}
function _callback(result, req) {
- handleFormValidationResponse(formid, onsuccess, onfailure, result);
+ handleFormValidationResponse(formid, onsuccess, onfailure, result);
}
d.addCallback(_callback);
return false;
}
-/*
+/**
+ * .. function:: inlineValidateRelationFormOptions(rtype, eid, divid, options)
+ *
* called by reledit forms to submit changes
- * @param formid : the dom id of the form used
- * @param rtype : the attribute being edited
- * @param eid : the eid of the entity being edited
- * @param reload: boolean to reload page if true (when changing URL dependant data)
- * @param default_value : value if the field is empty
- * @param lzone : html fragment (string) for a clic-zone triggering actual edition
+ * * `rtype`, the attribute being edited
+ *
+ * * `eid`, the eid of the entity being edited
+ *
+ * * `options`, a dictionnary of options used by the form validation handler such
+ * as ``role``, ``onsuccess``, ``onfailure``, ``reload``, ``vid``, ``lzone``
+ * and ``default_value``:
+ *
+ * * `onsucess`, javascript function to execute on success, default is noop
+ *
+ * * `onfailure`, javascript function to execute on failure, default is noop
+ *
+ * * `default_value`, value if the field is empty
+ *
+ * * `lzone`, html fragment (string) for a clic-zone triggering actual edition
*/
-function inlineValidateRelationForm(rtype, role, eid, divid, reload, vid,
- default_value, lzone) {
+function inlineValidateRelationFormOptions(rtype, eid, divid, options) {
try {
- var form = getNode(divid+'-form');
+ var form = getNode(divid + '-form');
var relname = rtype + ':' + eid;
var newtarget = jQuery('[name=' + relname + ']').val();
- var zipped = formContents(form);
- var d = asyncRemoteExec('validate_form', 'apply', zipped[0], zipped[1]);
- } catch (ex) {
- return false;
+ var zipped = cw.utils.formContents(form);
+ var args = ajaxFuncArgs('validate_form', null, 'apply', zipped[0], zipped[1]);
+ var d = loadRemote(JSON_BASE_URL, args, 'POST')
+ } catch(ex) {
+ return false;
}
- d.addCallback(function (result, req) {
- if (handleFormValidationResponse(divid+'-form', noop, noop, result)) {
- if (reload) {
+ d.addCallback(function(result, req) {
+ execFormValidationResponse(rtype, eid, divid, options, result);
+ });
+ return false;
+}
+
+function execFormValidationResponse(rtype, eid, divid, options, result) {
+ options = $.extend({onsuccess: noop,
+ onfailure: noop
+ }, options);
+ if (handleFormValidationResponse(divid + '-form', options.onsucess , options.onfailure, result)) {
+ if (options.reload) {
document.location.reload();
- } else {
- var args = {fname: 'reledit_form', rtype: rtype, role: role, eid: eid, divid: divid,
- reload: reload, vid: vid, default_value: default_value, landing_zone: lzone};
- jQuery('#'+divid+'-reledit').parent().loadxhtml(JSON_BASE_URL, args, 'post');
- }
- }
- return false;
- });
- return false;
+ } else {
+ var args = {
+ fname: 'reledit_form',
+ rtype: rtype,
+ role: options.role,
+ eid: eid,
+ divid: divid,
+ reload: options.reload,
+ vid: options.vid,
+ default_value: options.default_value,
+ landing_zone: options.lzone
+ };
+ jQuery('#' + divid + '-reledit').parent().loadxhtml(JSON_BASE_URL, args, 'post');
+ }
+ }
+
}
-/**** inline edition ****/
-function loadInlineEditionForm(eid, rtype, role, divid, reload, vid,
- default_value, lzone) {
- var args = {fname: 'reledit_form', rtype: rtype, role: role, eid: eid, divid: divid,
- reload: reload, vid: vid, default_value: default_value, landing_zone: lzone,
- callback: function () {showInlineEditionForm(eid, rtype, divid);}};
- jQuery('#'+divid+'-reledit').parent().loadxhtml(JSON_BASE_URL, args, 'post');
+/**
+ * .. function:: loadInlineEditionFormOptions(eid, rtype, divid, options)
+ *
+ * inline edition
+ */
+function loadInlineEditionFormOptions(eid, rtype, divid, options) {
+ var args = {
+ fname: 'reledit_form',
+ rtype: rtype,
+ role: options.role,
+ eid: eid,
+ divid: divid,
+ reload: options.reload,
+ vid: options.vid,
+ default_value: options.default_value,
+ landing_zone: options.lzone,
+ callback: function() {
+ showInlineEditionForm(eid, rtype, divid);
+ }
+ };
+ jQuery('#' + divid + '-reledit').parent().loadxhtml(JSON_BASE_URL, args, 'post');
}
-
function showInlineEditionForm(eid, rtype, divid) {
jQuery('#' + divid).hide();
- jQuery('#' + divid + '-value' ).hide();
- jQuery('#' + divid+ '-form').show();
+ jQuery('#' + divid + '-value').hide();
+ jQuery('#' + divid + '-form').show();
}
function hideInlineEdit(eid, rtype, divid) {
@@ -546,7 +697,56 @@
jQuery('div.errorMessage').remove();
jQuery('#' + divid).show();
jQuery('#' + divid + '-value').show();
- jQuery('#' + divid +'-form').hide();
+ jQuery('#' + divid + '-form').hide();
}
CubicWeb.provide('edition.js');
+
+// ======================= DEPRECATED FUNCTIONS ========================= //
+inlineValidateRelationForm = cw.utils.deprecatedFunction(
+ '[3.9] inlineValidateRelationForm() function is deprecated, use inlineValidateRelationFormOptions instead',
+ function(rtype, role, eid, divid, reload, vid, default_value, lzone, onsucess, onfailure) {
+ try {
+ var form = getNode(divid + '-form');
+ var relname = rtype + ':' + eid;
+ var newtarget = jQuery('[name=' + relname + ']').val();
+ var zipped = formContents(form);
+ var d = asyncRemoteExec('validate_form', 'apply', zipped[0], zipped[1]);
+ } catch(ex) {
+ return false;
+ }
+ d.addCallback(function(result, req) {
+ var options = {role : role,
+ reload: reload,
+ vid: vid,
+ default_value: default_value,
+ lzone: lzone,
+ onsucess: onsucess || $.noop,
+ onfailure: onfailure || $.noop
+ };
+ execFormValidationResponse(rtype, eid, divid, options);
+ });
+ return false;
+ }
+);
+
+loadInlineEditionForm = cw.utils.deprecatedFunction(
+ '[3.9] loadInlineEditionForm() function is deprecated, use loadInlineEditionFormOptions instead',
+ function(eid, rtype, role, divid, reload, vid, default_value, lzone) {
+ var args = {
+ fname: 'reledit_form',
+ rtype: rtype,
+ role: role,
+ eid: eid,
+ divid: divid,
+ reload: reload,
+ vid: vid,
+ default_value: default_value,
+ landing_zone: lzone,
+ callback: function() {
+ showInlineEditionForm(eid, rtype, divid);
+ }
+ };
+ jQuery('#' + divid + '-reledit').parent().loadxhtml(JSON_BASE_URL, args, 'post');
+ }
+);
--- a/web/data/cubicweb.facets.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.facets.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,6 +1,6 @@
-/*
+/**
* :organization: Logilab
- * :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*/
@@ -9,215 +9,233 @@
//============= filter form functions ========================================//
function copyParam(origparams, newparams, param) {
- var index = findValue(origparams[0], param);
- if (index > -1) {
- newparams[param] = origparams[1][index];
+ var index = jQuery.inArray(param, origparams[0]);
+ if (index > - 1) {
+ newparams[param] = origparams[1][index];
}
}
function facetFormContent(form) {
var names = [];
var values = [];
- jQuery(form).find('.facet').each(function () {
+ jQuery(form).find('.facet').each(function() {
var facetName = jQuery(this).find('.facetTitle').attr('cubicweb:facetName');
var facetValues = jQuery(this).find('.facetValueSelected').each(function(x) {
- names.push(facetName);
- values.push(this.getAttribute('cubicweb:value'));
+ names.push(facetName);
+ values.push(this.getAttribute('cubicweb:value'));
});
});
- jQuery(form).find('input').each(function () {
+ jQuery(form).find('input').each(function() {
names.push(this.name);
values.push(this.value);
});
- jQuery(form).find('select option[selected]').each(function () {
- names.push(this.parentNode.name);
- values.push(this.value);
+ jQuery(form).find('select option[selected]').each(function() {
+ names.push(this.parentNode.name);
+ values.push(this.value);
});
return [names, values];
}
function buildRQL(divid, vid, paginate, vidargs) {
jQuery(CubicWeb).trigger('facets-content-loading', [divid, vid, paginate, vidargs]);
- var form = getNode(divid+'Form');
+ var form = getNode(divid + 'Form');
var zipped = facetFormContent(form);
zipped[0].push('facetargs');
zipped[1].push(vidargs);
- var d = asyncRemoteExec('filter_build_rql', zipped[0], zipped[1]);
+ var d = loadRemote('json', ajaxFuncArgs('filter_build_rql', null, zipped[0], zipped[1]));
d.addCallback(function(result) {
- var rql = result[0];
- var $bkLink = jQuery('#facetBkLink');
- if ($bkLink.length) {
- var bkPath = 'view?rql=' + escape(rql);
- if (vid) {
- bkPath += '&vid=' + escape(vid);
- }
- var bkUrl = $bkLink.attr('cubicweb:target') + '&path=' + escape(bkPath);
- $bkLink.attr('href', bkUrl);
- }
- var toupdate = result[1];
- var extraparams = vidargs;
- var displayactions = jQuery('#' + divid).attr('cubicweb:displayactions');
- if (displayactions) { extraparams['displayactions'] = displayactions; }
- if (paginate) { extraparams['paginate'] = '1'; }
- // copy some parameters
- // XXX cleanup vid/divid mess
- // if vid argument is specified , the one specified in form params will
- // be overriden by replacePageChunk
- copyParam(zipped, extraparams, 'vid');
- extraparams['divid'] = divid;
- copyParam(zipped, extraparams, 'divid');
- copyParam(zipped, extraparams, 'subvid');
- copyParam(zipped, extraparams, 'fromformfilter');
- // paginate used to know if the filter box is acting, in which case we
- // want to reload action box to match current selection (we don't want
- // this from a table filter)
- replacePageChunk(divid, rql, vid, extraparams, true, function() {
- jQuery(CubicWeb).trigger('facets-content-loaded', [divid, rql, vid, extraparams]);
- });
- if (paginate) {
- // FIXME the edit box might not be displayed in which case we don't
- // know where to put the potential new one, just skip this case
- // for now
- if (jQuery('#edit_box').length) {
- reloadComponent('edit_box', rql, 'boxes', 'edit_box');
- }
- if (jQuery('#breadcrumbs').length) {
- reloadComponent('breadcrumbs', rql, 'components', 'breadcrumbs');
- }
- }
- var d = asyncRemoteExec('filter_select_content', toupdate, rql);
- d.addCallback(function(updateMap) {
- for (facetId in updateMap) {
- var values = updateMap[facetId];
- jqNode(facetId).find('.facetCheckBox').each(function () {
- var value = this.getAttribute('cubicweb:value');
- if (!values.contains(value)) {
- if (!jQuery(this).hasClass('facetValueDisabled')) {
- jQuery(this).addClass('facetValueDisabled');
- }
- } else {
- if (jQuery(this).hasClass('facetValueDisabled')) {
- jQuery(this).removeClass('facetValueDisabled');
- }
- }
- });
- }
- });
+ var rql = result[0];
+ var $bkLink = jQuery('#facetBkLink');
+ if ($bkLink.length) {
+ var bkPath = 'view?rql=' + escape(rql);
+ if (vid) {
+ bkPath += '&vid=' + escape(vid);
+ }
+ var bkUrl = $bkLink.attr('cubicweb:target') + '&path=' + escape(bkPath);
+ $bkLink.attr('href', bkUrl);
+ }
+ var toupdate = result[1];
+ var extraparams = vidargs;
+ var displayactions = jQuery('#' + divid).attr('cubicweb:displayactions');
+ if (displayactions) {
+ extraparams['displayactions'] = displayactions;
+ }
+ if (paginate) {
+ extraparams['paginate'] = '1';
+ }
+ // copy some parameters
+ // XXX cleanup vid/divid mess
+ // if vid argument is specified , the one specified in form params will
+ // be overriden by replacePageChunk
+ copyParam(zipped, extraparams, 'vid');
+ extraparams['divid'] = divid;
+ copyParam(zipped, extraparams, 'divid');
+ copyParam(zipped, extraparams, 'subvid');
+ copyParam(zipped, extraparams, 'fromformfilter');
+ // paginate used to know if the filter box is acting, in which case we
+ // want to reload action box to match current selection (we don't want
+ // this from a table filter)
+ extraparams['rql'] = rql;
+ extraparams['vid'] = vid;
+ d = $('#' + divid).loadxhtml('json', ajaxFuncArgs('view', extraparams));
+ d.addCallback(function() {
+ // XXX rql/vid in extraparams
+ jQuery(CubicWeb).trigger('facets-content-loaded', [divid, rql, vid, extraparams]);
+ });
+ if (paginate) {
+ // FIXME the edit box might not be displayed in which case we don't
+ // know where to put the potential new one, just skip this case
+ // for now
+ var $node = jQuery('#edit_box');
+ if ($node.length) {
+ $node.loadxhtml('json', ajaxFuncArgs('render', {
+ 'rql': rql
+ },
+ 'boxes', 'edit_box'));
+ }
+ $node = jQuery('#breadcrumbs')
+ if ($node.length) {
+ $node.loadxhtml('json', ajaxFuncArgs('render', {
+ 'rql': rql
+ },
+ 'components', 'breadcrumbs'));
+ }
+ }
+ var d = loadRemote('json', ajaxFuncArgs('filter_select_content', null, toupdate, rql));
+ d.addCallback(function(updateMap) {
+ for (facetId in updateMap) {
+ var values = updateMap[facetId];
+ cw.jqNode(facetId).find('.facetCheckBox').each(function() {
+ var value = this.getAttribute('cubicweb:value');
+ if (jQuery.inArray(value, values) == -1) {
+ if (!jQuery(this).hasClass('facetValueDisabled')) {
+ jQuery(this).addClass('facetValueDisabled');
+ }
+ } else {
+ if (jQuery(this).hasClass('facetValueDisabled')) {
+ jQuery(this).removeClass('facetValueDisabled');
+ }
+ }
+ });
+ }
+ });
});
}
-
-var SELECTED_IMG = baseuri()+"data/black-check.png";
-var UNSELECTED_IMG = baseuri()+"data/no-check-no-border.png";
-var UNSELECTED_BORDER_IMG = baseuri()+"data/black-uncheck.png";
+var SELECTED_IMG = baseuri() + "data/black-check.png";
+var UNSELECTED_IMG = baseuri() + "data/no-check-no-border.png";
+var UNSELECTED_BORDER_IMG = baseuri() + "data/black-uncheck.png";
function initFacetBoxEvents(root) {
// facetargs : (divid, vid, paginate, extraargs)
root = root || document;
- jQuery(root).find('form').each(function () {
- var form = jQuery(this);
- // NOTE: don't evaluate facetargs here but in callbacks since its value
- // may changes and we must send its value when the callback is
- // called, not when the page is initialized
- var facetargs = form.attr('cubicweb:facetargs');
- if (facetargs !== undefined) {
- form.submit(function() {
- buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
- return false;
- });
- form.find('div.facet').each(function() {
- var facet = jQuery(this);
- facet.find('div.facetCheckBox').each(function (i) {
- this.setAttribute('cubicweb:idx', i);
- });
- facet.find('div.facetCheckBox').click(function () {
- var $this = jQuery(this);
- // NOTE : add test on the facet operator (i.e. OR, AND)
- // if ($this.hasClass('facetValueDisabled')){
- // return
- // }
- if ($this.hasClass('facetValueSelected')) {
- $this.removeClass('facetValueSelected');
- $this.find('img').each(function (i){
- if (this.getAttribute('cubicweb:unselimg')){
- this.setAttribute('src', UNSELECTED_BORDER_IMG);
- this.setAttribute('alt', (_('not selected')));
- }
- else{
- this.setAttribute('src', UNSELECTED_IMG);
- this.setAttribute('alt', (_('not selected')));
- }
- });
- var index = parseInt($this.attr('cubicweb:idx'));
- // we dont need to move the element when cubicweb:idx == 0
- if (index > 0){
- var shift = jQuery.grep(facet.find('.facetValueSelected'), function (n) {
- var nindex = parseInt(n.getAttribute('cubicweb:idx'));
- return nindex > index;
- }).length;
- index += shift;
- var parent = this.parentNode;
- var $insertAfter = jQuery(parent).find('.facetCheckBox:nth('+index+')');
- if ( ! ($insertAfter.length == 1 && shift == 0) ) {
- // only rearrange element if necessary
- $insertAfter.after(this);
- }
- }
- } else {
- var lastSelected = facet.find('.facetValueSelected:last');
- if (lastSelected.length) {
- lastSelected.after(this);
- } else {
- var parent = this.parentNode;
- jQuery(parent).prepend(this);
- }
- jQuery(this).addClass('facetValueSelected');
- var $img = jQuery(this).find('img');
- $img.attr('src', SELECTED_IMG).attr('alt', (_('selected')));
- }
- buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
- facet.find('.facetBody').animate({scrollTop: 0}, '');
- });
- facet.find('select.facetOperator').change(function() {
- var nbselected = facet.find('div.facetValueSelected').length;
- if (nbselected >= 2) {
- buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
- }
- });
- facet.find('div.facetTitle').click(function() {
- facet.find('div.facetBody').toggleClass('hidden').toggleClass('opened');
- jQuery(this).toggleClass('opened');
- });
+ jQuery(root).find('form').each(function() {
+ var form = jQuery(this);
+ // NOTE: don't evaluate facetargs here but in callbacks since its value
+ // may changes and we must send its value when the callback is
+ // called, not when the page is initialized
+ var facetargs = form.attr('cubicweb:facetargs');
+ if (facetargs !== undefined) {
+ form.submit(function() {
+ buildRQL.apply(null, cw.evalJSON(form.attr('cubicweb:facetargs')));
+ return false;
+ });
+ form.find('div.facet').each(function() {
+ var facet = jQuery(this);
+ facet.find('div.facetCheckBox').each(function(i) {
+ this.setAttribute('cubicweb:idx', i);
+ });
+ facet.find('div.facetCheckBox').click(function() {
+ var $this = jQuery(this);
+ // NOTE : add test on the facet operator (i.e. OR, AND)
+ // if ($this.hasClass('facetValueDisabled')){
+ // return
+ // }
+ if ($this.hasClass('facetValueSelected')) {
+ $this.removeClass('facetValueSelected');
+ $this.find('img').each(function(i) {
+ if (this.getAttribute('cubicweb:unselimg')) {
+ this.setAttribute('src', UNSELECTED_BORDER_IMG);
+ this.setAttribute('alt', (_('not selected')));
+ }
+ else {
+ this.setAttribute('src', UNSELECTED_IMG);
+ this.setAttribute('alt', (_('not selected')));
+ }
+ });
+ var index = parseInt($this.attr('cubicweb:idx'));
+ // we dont need to move the element when cubicweb:idx == 0
+ if (index > 0) {
+ var shift = jQuery.grep(facet.find('.facetValueSelected'), function(n) {
+ var nindex = parseInt(n.getAttribute('cubicweb:idx'));
+ return nindex > index;
+ }).length;
+ index += shift;
+ var parent = this.parentNode;
+ var $insertAfter = jQuery(parent).find('.facetCheckBox:nth(' + index + ')');
+ if (! ($insertAfter.length == 1 && shift == 0)) {
+ // only rearrange element if necessary
+ $insertAfter.after(this);
+ }
+ }
+ } else {
+ var lastSelected = facet.find('.facetValueSelected:last');
+ if (lastSelected.length) {
+ lastSelected.after(this);
+ } else {
+ var parent = this.parentNode;
+ jQuery(parent).prepend(this);
+ }
+ jQuery(this).addClass('facetValueSelected');
+ var $img = jQuery(this).find('img');
+ $img.attr('src', SELECTED_IMG).attr('alt', (_('selected')));
+ }
+ buildRQL.apply(null, cw.evalJSON(form.attr('cubicweb:facetargs')));
+ facet.find('.facetBody').animate({
+ scrollTop: 0
+ },
+ '');
+ });
+ facet.find('select.facetOperator').change(function() {
+ var nbselected = facet.find('div.facetValueSelected').length;
+ if (nbselected >= 2) {
+ buildRQL.apply(null, cw.evalJSON(form.attr('cubicweb:facetargs')));
+ }
+ });
+ facet.find('div.facetTitle').click(function() {
+ facet.find('div.facetBody').toggleClass('hidden').toggleClass('opened');
+ jQuery(this).toggleClass('opened');
+ });
- });
- }
+ });
+ }
});
}
// trigger this function on document ready event if you provide some kind of
// persistent search (eg crih)
-function reorderFacetsItems(root){
+function reorderFacetsItems(root) {
root = root || document;
- jQuery(root).find('form').each(function () {
- var form = jQuery(this);
- if (form.attr('cubicweb:facetargs')) {
- form.find('div.facet').each(function() {
- var facet = jQuery(this);
- var lastSelected = null;
- facet.find('div.facetCheckBox').each(function (i) {
- var $this = jQuery(this);
- if ($this.hasClass('facetValueSelected')) {
- if (lastSelected) {
- lastSelected.after(this);
- } else {
- var parent = this.parentNode;
- jQuery(parent).prepend(this);
- }
- lastSelected = $this;
- }
- });
- });
- }
+ jQuery(root).find('form').each(function() {
+ var form = jQuery(this);
+ if (form.attr('cubicweb:facetargs')) {
+ form.find('div.facet').each(function() {
+ var facet = jQuery(this);
+ var lastSelected = null;
+ facet.find('div.facetCheckBox').each(function(i) {
+ var $this = jQuery(this);
+ if ($this.hasClass('facetValueSelected')) {
+ if (lastSelected) {
+ lastSelected.after(this);
+ } else {
+ var parent = this.parentNode;
+ jQuery(parent).prepend(this);
+ }
+ lastSelected = $this;
+ }
+ });
+ });
+ }
});
}
@@ -225,6 +243,9 @@
// with one argument or without any argument. If we use `initFacetBoxEvents`
// as the direct callback on the jQuery.ready event, jQuery will pass some argument
// of his, so we use this small anonymous function instead.
-jQuery(document).ready(function() {initFacetBoxEvents();});
+jQuery(document).ready(function() {
+ initFacetBoxEvents();
+});
CubicWeb.provide('facets.js');
+
--- a/web/data/cubicweb.flot.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.flot.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,14 +1,14 @@
function showTooltip(x, y, contents) {
- $('<div id="tooltip">' + contents + '</div>').css( {
- position: 'absolute',
+ $('<div id="tooltip">' + contents + '</div>').css({
+ position: 'absolute',
display: 'none',
top: y + 5,
- left: x + 5,
- border: '1px solid #fdd',
- padding: '2px',
- 'background-color': '#fee',
- opacity: 0.80
- }).appendTo("body").fadeIn(200);
+ left: x + 5,
+ border: '1px solid #fdd',
+ padding: '2px',
+ 'background-color': '#fee',
+ opacity: 0.80
+ }).appendTo("body").fadeIn(200);
}
var previousPoint = null;
@@ -18,19 +18,19 @@
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0].toFixed(2),
- y = item.datapoint[1].toFixed(2);
+ y = item.datapoint[1].toFixed(2);
if (item.datapoint.length == 3) {
x = new Date(item.datapoint[2]);
x = x.toLocaleDateString() + ' ' + x.toLocaleTimeString();
} else if (item.datapoint.length == 4) {
- x = new Date(item.datapoint[2]);
- x = x.strftime(item.datapoint[3]);
+ x = new Date(item.datapoint[2]);
+ x = x.strftime(item.datapoint[3]);
}
- showTooltip(item.pageX, item.pageY,
- item.series.label + ': (' + x + ' ; ' + y + ')');
+ showTooltip(item.pageX, item.pageY, item.series.label + ': (' + x + ' ; ' + y + ')');
}
} else {
$("#tooltip").remove();
previousPoint = null;
}
}
+
--- a/web/data/cubicweb.gmap.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.gmap.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,72 +1,72 @@
-/*
+/**
* :organization: Logilab
- * :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
- *
- *
*/
Widgets.GMapWidget = defclass('GMapWidget', null, {
- __init__: function(wdgnode) {
- // Assume we have imported google maps JS
- if (GBrowserIsCompatible()) {
- var uselabelstr = wdgnode.getAttribute('cubicweb:uselabel');
- var uselabel = true;
- if (uselabelstr){
- if (uselabelstr == 'True'){
- uselabel = true;
- }
- else{
- uselabel = false;
- }
- }
- var map = new GMap2(wdgnode);
- map.addControl(new GSmallMapControl());
- var jsonurl = wdgnode.getAttribute('cubicweb:loadurl');
- var self = this; // bind this to a local variable
- jQuery.getJSON(jsonurl, function(geodata) {
- if (geodata.center) {
- var zoomLevel = geodata.zoomlevel;
- map.setCenter(new GLatLng(geodata.center.latitude, geodata.center.longitude),
- zoomLevel);
- }
- for (var i=0; i<geodata.markers.length; i++) {
- var marker = geodata.markers[i];
- self.createMarker(map, marker, i+1, uselabel);
- }
- });
- jQuery(wdgnode).after(this.legendBox);
- } else { // incompatible browser
- jQuery.unload(GUnload);
- }
- },
+ __init__: function(wdgnode) {
+ // Assume we have imported google maps JS
+ if (GBrowserIsCompatible()) {
+ var uselabelstr = wdgnode.getAttribute('cubicweb:uselabel');
+ var uselabel = true;
+ if (uselabelstr) {
+ if (uselabelstr == 'True') {
+ uselabel = true;
+ }
+ else {
+ uselabel = false;
+ }
+ }
+ var map = new GMap2(wdgnode);
+ map.addControl(new GSmallMapControl());
+ var jsonurl = wdgnode.getAttribute('cubicweb:loadurl');
+ var self = this; // bind this to a local variable
+ jQuery.getJSON(jsonurl, function(geodata) {
+ if (geodata.center) {
+ var zoomLevel = geodata.zoomlevel;
+ map.setCenter(new GLatLng(geodata.center.latitude, geodata.center.longitude), zoomLevel);
+ }
+ for (var i = 0; i < geodata.markers.length; i++) {
+ var marker = geodata.markers[i];
+ self.createMarker(map, marker, i + 1, uselabel);
+ }
+ });
+ jQuery(wdgnode).after(this.legendBox);
+ } else { // incompatible browser
+ jQuery.unload(GUnload);
+ }
+ },
- createMarker: function(map, marker, i, uselabel) {
- var point = new GLatLng(marker.latitude, marker.longitude);
- var icon = new GIcon();
- icon.image = marker.icon[0];
- icon.iconSize = new GSize(marker.icon[1][0], marker.icon[1][1]) ;
- icon.iconAnchor = new GPoint(marker.icon[2][0], marker.icon[2][1]);
- if(marker.icon[3]){
- icon.shadow4 = marker.icon[3];
- }
- if (typeof LabeledMarker == "undefined") {
- var gmarker = new GMarker(point, {icon: icon,
- title: marker.title});
- } else {
- var gmarker = new LabeledMarker(point, {
- icon: icon,
- title: marker.title,
- labelText: uselabel?'<strong>' + i + '</strong>':'',
- labelOffset: new GSize(2, -32)
+ createMarker: function(map, marker, i, uselabel) {
+ var point = new GLatLng(marker.latitude, marker.longitude);
+ var icon = new GIcon();
+ icon.image = marker.icon[0];
+ icon.iconSize = new GSize(marker.icon[1][0], marker.icon[1][1]);
+ icon.iconAnchor = new GPoint(marker.icon[2][0], marker.icon[2][1]);
+ if (marker.icon[3]) {
+ icon.shadow4 = marker.icon[3];
+ }
+ if (typeof LabeledMarker == "undefined") {
+ var gmarker = new GMarker(point, {
+ icon: icon,
+ title: marker.title
+ });
+ } else {
+ var gmarker = new LabeledMarker(point, {
+ icon: icon,
+ title: marker.title,
+ labelText: uselabel ? '<strong>' + i + '</strong>': '',
+ labelOffset: new GSize(2, - 32)
+ });
+ }
+ map.addOverlay(gmarker);
+ GEvent.addListener(gmarker, 'click', function() {
+ jQuery.post(marker.bubbleUrl, function(data) {
+ map.openInfoWindowHtml(point, data);
+ });
});
}
- map.addOverlay(gmarker);
- GEvent.addListener(gmarker, 'click', function() {
- jQuery.post(marker.bubbleUrl, function(data) {
- map.openInfoWindowHtml(point, data);
- });
- });
- }
});
+
--- a/web/data/cubicweb.goa.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.goa.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,10 +1,17 @@
-/*
+/**
* functions specific to cubicweb on google appengine
*
* :organization: Logilab
- * :copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2008-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*/
-/* overrides rql_for_eid function from htmlhelpers.hs */
-function rql_for_eid(eid) { return 'Any X WHERE X eid "' + eid + '"'; }
+/**
+ * .. function:: rql_for_eid(eid)
+ *
+ * overrides rql_for_eid function from htmlhelpers.hs
+ */
+function rql_for_eid(eid) {
+ return 'Any X WHERE X eid "' + eid + '"';
+}
+
--- a/web/data/cubicweb.htmlhelpers.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.htmlhelpers.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,31 +1,37 @@
CubicWeb.require('python.js');
CubicWeb.require('jquery.corner.js');
-/* returns the document's baseURI. (baseuri() uses document.baseURI if
+/**
+ * .. function:: baseuri()
+ *
+ * returns the document's baseURI. (baseuri() uses document.baseURI if
* available and inspects the <base> tag manually otherwise.)
-*/
+ */
function baseuri() {
var uri = document.baseURI;
if (uri) { // some browsers don't define baseURI
- return uri;
+ return uri;
}
- var basetags = document.getElementsByTagName('base');
- if (basetags.length) {
- return getNodeAttribute(basetags[0], 'href');
- }
- return '';
+ return jQuery('base').attr('href');
}
-
-/* set body's cursor to 'progress' */
+/**
+ * .. function:: setProgressCursor()
+ *
+ * set body's cursor to 'progress'
+ */
function setProgressCursor() {
var body = document.getElementsByTagName('body')[0];
body.style.cursor = 'progress';
}
-/* reset body's cursor to default (mouse cursor). The main
+/**
+ * .. function:: resetCursor(result)
+ *
+ * reset body's cursor to default (mouse cursor). The main
* purpose of this function is to be used as a callback in the
- * deferreds' callbacks chain. */
+ * deferreds' callbacks chain.
+ */
function resetCursor(result) {
var body = document.getElementsByTagName('body')[0];
body.style.cursor = 'default';
@@ -34,14 +40,19 @@
}
function updateMessage(msg) {
- var msgdiv = DIV({'class':'message'});
+ var msgdiv = DIV({
+ 'class': 'message'
+ });
// don't pass msg to DIV() directly because DIV will html escape it
// and msg should alreay be html escaped at this point.
msgdiv.innerHTML = msg;
jQuery('#appMsg').removeClass('hidden').empty().append(msgdiv);
}
-/* builds an url from an object (used as a dictionnary)
+/**
+ * .. function:: asURL(props)
+ *
+ * builds an url from an object (used as a dictionnary)
*
* >>> asURL({'rql' : "RQL", 'x': [1, 2], 'itemvid' : "oneline"})
* rql=RQL&vid=list&itemvid=oneline&x=1&x=2
@@ -50,122 +61,145 @@
*/
function asURL(props) {
var chunks = [];
- for(key in props) {
- var value = props[key];
- // generate a list of couple key=value if key is multivalued
- if (isArrayLike(value)) {
- for (var i=0; i<value.length;i++) {
- chunks.push(key + '=' + urlEncode(value[i]));
- }
- } else {
- chunks.push(key + '=' + urlEncode(value));
- }
+ for (key in props) {
+ var value = props[key];
+ // generate a list of couple key=value if key is multivalued
+ if (cw.utils.isArrayLike(value)) {
+ for (var i = 0; i < value.length; i++) {
+ chunks.push(key + '=' + urlEncode(value[i]));
+ }
+ } else {
+ chunks.push(key + '=' + urlEncode(value));
+ }
}
return chunks.join('&');
}
-/* return selected value of a combo box if any
+/**
+ * .. function:: firstSelected(selectNode)
+ *
+ * return selected value of a combo box if any
*/
function firstSelected(selectNode) {
- var selection = filter(attrgetter('selected'), selectNode.options);
- return (selection.length > 0) ? getNodeAttribute(selection[0], 'value'):null;
+ var $selection = $(selectNode).find('option:selected:first');
+ return ($selection.length > 0) ? $selection[0] : null;
}
-/* toggle visibility of an element by its id
+/**
+ * .. function:: toggleVisibility(elemId)
+ *
+ * toggle visibility of an element by its id
*/
function toggleVisibility(elemId) {
- jqNode(elemId).toggleClass('hidden');
+ $('#' + elemId).toggleClass('hidden');
}
-
-/* toggles visibility of login popup div */
+/**
+ * .. function:: popupLoginBox()
+ *
+ * toggles visibility of login popup div
+ */
// XXX used exactly ONCE in basecomponents
function popupLoginBox() {
- toggleVisibility('popupLoginBox');
+ $('#popupLoginBox').toggleClass('hidden');
jQuery('#__login:visible').focus();
}
-
-/* returns the list of elements in the document matching the tag name
+/**
+ * .. function getElementsMatching(tagName, properties, \/* optional \*\/ parent)
+ *
+ * returns the list of elements in the document matching the tag name
* and the properties provided
*
- * @param tagName the tag's name
- * @param properties a js Object used as a dict
- * @return an iterator (if a *real* array is needed, you can use the
+ * * `tagName`, the tag's name
+ *
+ * * `properties`, a js Object used as a dict
+ *
+ * Return an iterator (if a *real* array is needed, you can use the
* list() function)
*/
function getElementsMatching(tagName, properties, /* optional */ parent) {
parent = parent || document;
- return filter(function elementMatches(element) {
- for (prop in properties) {
- if (getNodeAttribute(element, prop) != properties[prop]) {
- return false;}}
- return true;},
- parent.getElementsByTagName(tagName));
+ return jQuery.grep(parent.getElementsByTagName(tagName), function elementMatches(element) {
+ for (prop in properties) {
+ if (jQuery(element).attr(prop) != properties[prop]) {
+ return false;
+ }
+ }
+ return true;
+ });
}
-/*
+/**
+ * .. function:: setCheckboxesState(nameprefix, value, checked)
+ *
* sets checked/unchecked status of checkboxes
*/
-function setCheckboxesState(nameprefix, checked){
+
+function setCheckboxesState(nameprefix, value, checked) {
// XXX: this looks in *all* the document for inputs
- var elements = getElementsMatching('input', {'type': "checkbox"});
- filterfunc = function(cb) { return nameprefix && cb.name.startsWith(nameprefix); };
- forEach(filter(filterfunc, elements), function(cb) {cb.checked=checked;});
+ jQuery('input:checkbox[name^=' + nameprefix + ']').each(function() {
+ if (value == null || this.value == value) {
+ this.checked = checked;
+ }
+ });
}
-function setCheckboxesState2(nameprefix, value, checked){
- // XXX: this looks in *all* the document for inputs
- var elements = getElementsMatching('input', {'type': "checkbox"});
- filterfunc = function(cb) { return nameprefix && cb.name.startsWith(nameprefix) && cb.value == value; };
- forEach(filter(filterfunc, elements), function(cb) {cb.checked=checked;});
-}
-
-
-/* this function is a hack to build a dom node from html source */
+/**
+ * .. function:: html2dom(source)
+ *
+ * this function is a hack to build a dom node from html source
+ */
function html2dom(source) {
var tmpNode = SPAN();
tmpNode.innerHTML = source;
if (tmpNode.childNodes.length == 1) {
- return tmpNode.firstChild;
+ return tmpNode.firstChild;
}
else {
- // we leave the span node when `source` has no root node
- // XXX This is cleary not the best solution, but css/html-wise,
- /// a span not should not be too much disturbing
- return tmpNode;
+ // we leave the span node when `source` has no root node
+ // XXX This is cleary not the best solution, but css/html-wise,
+ /// a span not should not be too much disturbing
+ return tmpNode;
}
}
-
// *** HELPERS **************************************************** //
-function rql_for_eid(eid) { return 'Any X WHERE X eid ' + eid; }
-function isTextNode(domNode) { return domNode.nodeType == 3; }
-function isElementNode(domNode) { return domNode.nodeType == 1; }
+function rql_for_eid(eid) {
+ return 'Any X WHERE X eid ' + eid;
+}
+function isTextNode(domNode) {
+ return domNode.nodeType == 3;
+}
+function isElementNode(domNode) {
+ return domNode.nodeType == 1;
+}
function autogrow(area) {
- if (area.scrollHeight > area.clientHeight && !window.opera) {
- if (area.rows < 20) {
- area.rows += 2;
- }
+ if (area.scrollHeight > area.clientHeight && ! window.opera) {
+ if (area.rows < 20) {
+ area.rows += 2;
+ }
}
}
//============= page loading events ==========================================//
-
-CubicWeb.rounded = [
- ['div.sideBoxBody', 'bottom 6px'],
- ['div.boxTitle, div.sideBoxTitle, th.month', 'top 6px']
- ];
+CubicWeb.rounded = [['div.sideBoxBody', 'bottom 6px'],
+ ['div.boxTitle, div.sideBoxTitle, th.month', 'top 6px']];
function roundedCorners(node) {
- node = jQuery(node);
- for(var r=0; r < CubicWeb.rounded.length; r++) {
- node.find(CubicWeb.rounded[r][0]).corner(CubicWeb.rounded[r][1]);
+ if (jQuery.fn.corner !== undefined) {
+ node = jQuery(node);
+ for (var r = 0; r < CubicWeb.rounded.length; r++) {
+ node.find(CubicWeb.rounded[r][0]).corner(CubicWeb.rounded[r][1]);
+ }
}
}
-jQuery(document).ready(function () {roundedCorners(this.body);});
+jQuery(document).ready(function() {
+ roundedCorners(this.body);
+});
CubicWeb.provide('corners.js');
CubicWeb.provide('htmlhelpers.js');
+
--- a/web/data/cubicweb.iprogress.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.iprogress.js Thu Jun 03 14:51:42 2010 +0200
@@ -6,7 +6,7 @@
this.color_budget = "blue";
this.color_todo = "#cccccc"; // grey
this.height = 16;
- this.middle = this.height/2;
+ this.middle = this.height / 2;
this.radius = 4;
}
@@ -15,14 +15,14 @@
ctx.lineWidth = 1;
ctx.strokeStyle = color;
if (fill) {
- ctx.fillStyle = color;
- ctx.fillRect(0,0,pos,this.middle*2);
+ ctx.fillStyle = color;
+ ctx.fillRect(0, 0, pos, this.middle * 2);
} else {
- ctx.lineWidth = 2;
- ctx.strokeStyle = "black";
- ctx.moveTo(pos,0);
- ctx.lineTo(pos,this.middle*2);
- ctx.stroke();
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "black";
+ ctx.moveTo(pos, 0);
+ ctx.lineTo(pos, this.middle * 2);
+ ctx.stroke();
}
};
@@ -30,36 +30,34 @@
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = color;
- ctx.moveTo(0,this.middle);
- ctx.lineTo(pos,this.middle);
- ctx.arc(pos,this.middle,this.radius,0,Math.PI*2,true);
+ ctx.moveTo(0, this.middle);
+ ctx.lineTo(pos, this.middle);
+ ctx.arc(pos, this.middle, this.radius, 0, Math.PI * 2, true);
ctx.stroke();
};
-
ProgressBar.prototype.draw_circ = function(ctx) {
- this.draw_one_circ(ctx,this.budget,this.color_budget);
- this.draw_one_circ(ctx,this.todo,this.color_todo);
- this.draw_one_circ(ctx,this.done,this.color_done);
+ this.draw_one_circ(ctx, this.budget, this.color_budget);
+ this.draw_one_circ(ctx, this.todo, this.color_todo);
+ this.draw_one_circ(ctx, this.done, this.color_done);
};
-
ProgressBar.prototype.draw_rect = function(ctx) {
- this.draw_one_rect(ctx,this.todo,this.color_todo,true);
- this.draw_one_rect(ctx,this.done,this.color_done,true);
- this.draw_one_rect(ctx,this.budget,this.color_budget,false);
+ this.draw_one_rect(ctx, this.todo, this.color_todo, true);
+ this.draw_one_rect(ctx, this.done, this.color_done, true);
+ this.draw_one_rect(ctx, this.budget, this.color_budget, false);
};
-
function draw_progressbar(cid, done, todo, budget, color) {
var canvas = document.getElementById(cid);
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
- var bar = new ProgressBar();
- bar.budget = budget;
- bar.todo = todo;
- bar.done = done;
+ var bar = new ProgressBar();
+ bar.budget = budget;
+ bar.todo = todo;
+ bar.done = done;
bar.color_done = color;
- bar.draw_rect(ctx);
+ bar.draw_rect(ctx);
}
}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.js Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,370 @@
+cw = {};
+
+jQuery.extend(cw, {
+ log: function () {
+ var args = [];
+ for (var i = 0; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ if (typeof(window) != "undefined" && window.console && window.console.log) {
+ window.console.log(args.join(' '));
+ }
+ },
+
+ //removed: getElementsByTagAndClassName, replaceChildNodes, toggleElementClass
+ // partial, merge, isNotEmpty, update,
+ // String.in_, String.join, list, getattr, attrgetter, methodcaller,
+ // min, max, dict, concat
+ jqNode: function (node) {
+ /**
+ * .. function:: jqNode(node)
+ *
+ * safe version of jQuery('#nodeid') because we use ':' in nodeids
+ * which messes with jQuery selection mechanism
+ */
+ if (typeof(node) == 'string') {
+ node = document.getElementById(node);
+ }
+ if (node) {
+ return $(node);
+ }
+ return null;
+ },
+
+ getNode: function (node) {
+ if (typeof(node) == 'string') {
+ return document.getElementById(node);
+ }
+ return node;
+ },
+
+ evalJSON: function (json) { // trust source
+ return eval("(" + json + ")");
+ },
+
+ urlEncode: function (str) {
+ if (typeof(encodeURIComponent) != "undefined") {
+ return encodeURIComponent(str).replace(/\'/g, '%27');
+ } else {
+ return escape(str).replace(/\+/g, '%2B').replace(/\"/g, '%22').
+ rval.replace(/\'/g, '%27');
+ }
+ },
+
+ swapDOM: function (dest, src) {
+ dest = getNode(dest);
+ var parent = dest.parentNode;
+ if (src) {
+ src = getNode(src);
+ parent.replaceChild(src, dest);
+ } else {
+ parent.removeChild(dest);
+ }
+ return src;
+ }
+});
+
+
+cw.utils = {
+
+ deprecatedFunction: function (msg, newfunc) {
+ return function () {
+ cw.log(msg);
+ return newfunc.apply(this, arguments);
+ };
+ },
+
+ movedToNamespace: function (funcnames, namespace) {
+ for (var i = 0; i < funcnames.length; i++) {
+ var funcname = funcnames[i];
+ var msg = '[3.9] ' + funcname + ' is deprecated, use cw.' + funcname + ' instead';
+ window[funcname] = cw.utils.deprecatedFunction(msg, namespace[funcname]);
+ }
+ },
+
+ createDomFunction: function (tag) {
+ function builddom(params, children) {
+ var node = document.createElement(tag);
+ for (key in params) {
+ var value = params[key];
+ if (key.substring(0, 2) == 'on') {
+ // this is an event handler definition
+ if (typeof value == 'string') {
+ // litteral definition
+ value = new Function(value);
+ }
+ node[key] = value;
+ } else { // normal node attribute
+ jQuery(node).attr(key, params[key]);
+ }
+ }
+ if (children) {
+ if (!cw.utils.isArrayLike(children)) {
+ children = [children];
+ for (var i = 2; i < arguments.length; i++) {
+ var arg = arguments[i];
+ if (cw.utils.isArray(arg)) {
+ jQuery.merge(children, arg);
+ } else {
+ children.push(arg);
+ }
+ }
+ }
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ if (typeof child == "string" || typeof child == "number") {
+ child = document.createTextNode(child);
+ }
+ node.appendChild(child);
+ }
+ }
+ return node;
+ }
+ return builddom;
+ },
+
+ /**
+ * .. function:: toISOTimestamp(date)
+ *
+ */
+ toISOTimestamp: function (date) {
+ if (typeof(date) == "undefined" || date === null) {
+ return null;
+ }
+
+ function _padTwo(n) {
+ return (n > 9) ? n : "0" + n;
+ }
+ var isoTime = [_padTwo(date.getHours()), _padTwo(date.getMinutes()),
+ _padTwo(date.getSeconds())].join(':');
+ var isoDate = [date.getFullYear(), _padTwo(date.getMonth() + 1),
+ _padTwo(date.getDate())].join("-");
+ return isoDate + " " + isoTime;
+ },
+
+ /**
+ * .. function:: nodeWalkDepthFirst(node, visitor)
+ *
+ * depth-first implementation of the nodeWalk function found
+ * in `MochiKit.Base <http://mochikit.com/doc/html/MochiKit/Base.html#fn-nodewalk>`_
+ */
+ nodeWalkDepthFirst: function (node, visitor) {
+ var children = visitor(node);
+ if (children) {
+ for (var i = 0; i < children.length; i++) {
+ nodeWalkDepthFirst(children[i], visitor);
+ }
+ }
+ },
+
+ isArray: function (it) { // taken from dojo
+ return it && (it instanceof Array || typeof it == "array");
+ },
+
+ isString: function (it) { // taken from dojo
+ return !!arguments.length && it != null && (typeof it == "string" || it instanceof String);
+ },
+
+ isArrayLike: function (it) { // taken from dojo
+ return (it && it !== undefined &&
+ // keep out built-in constructors (Number, String, ...)
+ // which have length properties
+ !cw.utils.isString(it) && !jQuery.isFunction(it) &&
+ !(it.tagName && it.tagName.toLowerCase() == 'form') &&
+ (cw.utils.isArray(it) || isFinite(it.length)));
+ },
+
+ /**
+ * .. function:: formContents(elem \/* = document.body *\/)
+ *
+ * this implementation comes from MochiKit
+ */
+ formContents: function (elem /* = document.body */ ) {
+ var names = [];
+ var values = [];
+ if (typeof(elem) == "undefined" || elem === null) {
+ elem = document.body;
+ } else {
+ elem = getNode(elem);
+ }
+ cw.utils.nodeWalkDepthFirst(elem, function (elem) {
+ var name = elem.name;
+ if (name && name.length) {
+ var tagName = elem.tagName.toUpperCase();
+ if (tagName === "INPUT" && (elem.type == "radio" || elem.type == "checkbox") && !elem.checked) {
+ return null;
+ }
+ if (tagName === "SELECT") {
+ if (elem.type == "select-one") {
+ if (elem.selectedIndex >= 0) {
+ var opt = elem.options[elem.selectedIndex];
+ var v = opt.value;
+ if (!v) {
+ var h = opt.outerHTML;
+ // internet explorer sure does suck.
+ if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
+ v = opt.text;
+ }
+ }
+ names.push(name);
+ values.push(v);
+ return null;
+ }
+ // no form elements?
+ names.push(name);
+ values.push("");
+ return null;
+ } else {
+ var opts = elem.options;
+ if (!opts.length) {
+ names.push(name);
+ values.push("");
+ return null;
+ }
+ for (var i = 0; i < opts.length; i++) {
+ var opt = opts[i];
+ if (!opt.selected) {
+ continue;
+ }
+ var v = opt.value;
+ if (!v) {
+ var h = opt.outerHTML;
+ // internet explorer sure does suck.
+ if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
+ v = opt.text;
+ }
+ }
+ names.push(name);
+ values.push(v);
+ }
+ return null;
+ }
+ }
+ if (tagName === "FORM" || tagName === "P" || tagName === "SPAN" || tagName === "DIV") {
+ return elem.childNodes;
+ }
+ names.push(name);
+ values.push(elem.value || '');
+ return null;
+ }
+ return elem.childNodes;
+ });
+ return [names, values];
+ },
+
+ /**
+ * .. function:: sliceList(lst, start, stop, step)
+ *
+ * returns a subslice of `lst` using `start`/`stop`/`step`
+ * start, stop might be negative
+ *
+ * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], 2)
+ * ['c', 'd', 'e', 'f']
+ * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], 2, -2)
+ * ['c', 'd']
+ * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], -3)
+ * ['d', 'e', 'f']
+ */
+ sliceList: function (lst, start, stop, step) {
+ start = start || 0;
+ stop = stop || lst.length;
+ step = step || 1;
+ if (stop < 0) {
+ stop = Math.max(lst.length + stop, 0);
+ }
+ if (start < 0) {
+ start = Math.min(lst.length + start, lst.length);
+ }
+ var result = [];
+ for (var i = start; i < stop; i += step) {
+ result.push(lst[i]);
+ }
+ return result;
+ }
+
+
+};
+
+String.prototype.startsWith = cw.utils.deprecatedFunction('[3.9] str.startsWith() is deprecated, use str.startswith() instead', function (prefix) {
+ return this.startswith(prefix);
+});
+
+String.prototype.endsWith = cw.utils.deprecatedFunction('[3.9] str.endsWith() is deprecated, use str.endswith() instead', function (suffix) {
+ return this.endswith(prefix);
+});
+
+/** DOM factories ************************************************************/
+A = cw.utils.createDomFunction('a');
+BUTTON = cw.utils.createDomFunction('button');
+BR = cw.utils.createDomFunction('br');
+CANVAS = cw.utils.createDomFunction('canvas');
+DD = cw.utils.createDomFunction('dd');
+DIV = cw.utils.createDomFunction('div');
+DL = cw.utils.createDomFunction('dl');
+DT = cw.utils.createDomFunction('dt');
+FIELDSET = cw.utils.createDomFunction('fieldset');
+FORM = cw.utils.createDomFunction('form');
+H1 = cw.utils.createDomFunction('H1');
+H2 = cw.utils.createDomFunction('H2');
+H3 = cw.utils.createDomFunction('H3');
+H4 = cw.utils.createDomFunction('H4');
+H5 = cw.utils.createDomFunction('H5');
+H6 = cw.utils.createDomFunction('H6');
+HR = cw.utils.createDomFunction('hr');
+IMG = cw.utils.createDomFunction('img');
+INPUT = cw.utils.createDomFunction('input');
+LABEL = cw.utils.createDomFunction('label');
+LEGEND = cw.utils.createDomFunction('legend');
+LI = cw.utils.createDomFunction('li');
+OL = cw.utils.createDomFunction('ol');
+OPTGROUP = cw.utils.createDomFunction('optgroup');
+OPTION = cw.utils.createDomFunction('option');
+P = cw.utils.createDomFunction('p');
+PRE = cw.utils.createDomFunction('pre');
+SELECT = cw.utils.createDomFunction('select');
+SPAN = cw.utils.createDomFunction('span');
+STRONG = cw.utils.createDomFunction('strong');
+TABLE = cw.utils.createDomFunction('table');
+TBODY = cw.utils.createDomFunction('tbody');
+TD = cw.utils.createDomFunction('td');
+TEXTAREA = cw.utils.createDomFunction('textarea');
+TFOOT = cw.utils.createDomFunction('tfoot');
+TH = cw.utils.createDomFunction('th');
+THEAD = cw.utils.createDomFunction('thead');
+TR = cw.utils.createDomFunction('tr');
+TT = cw.utils.createDomFunction('tt');
+UL = cw.utils.createDomFunction('ul');
+
+// cubicweb specific
+//IFRAME = cw.utils.createDomFunction('iframe');
+
+
+function IFRAME(params) {
+ if ('name' in params) {
+ try {
+ var node = document.createElement('<iframe name="' + params['name'] + '">');
+ } catch (ex) {
+ var node = document.createElement('iframe');
+ node.id = node.name = params.name;
+ }
+ }
+ else {
+ var node = document.createElement('iframe');
+ }
+ for (key in params) {
+ if (key != 'name') {
+ var value = params[key];
+ if (key.substring(0, 2) == 'on') {
+ // this is an event handler definition
+ if (typeof value == 'string') {
+ // litteral definition
+ value = new Function(value);
+ }
+ node[key] = value;
+ } else { // normal node attribute
+ node.setAttribute(key, params[key]);
+ }
+ }
+ }
+ return node;
+}
--- a/web/data/cubicweb.lazy.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.lazy.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,10 +1,9 @@
-
function load_now(eltsel, holesel, reloadable) {
var lazydiv = jQuery(eltsel);
var hole = lazydiv.children(holesel);
- if ((hole.length == 0) && !reloadable) {
- /* the hole is already filled */
- return;
+ if ((hole.length == 0) && ! reloadable) {
+ /* the hole is already filled */
+ return;
}
lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
}
@@ -12,3 +11,4 @@
function trigger_load(divid) {
jQuery('#lazy-' + divid).trigger('load_' + divid);
}
+
--- a/web/data/cubicweb.massmailing.js Thu Jun 03 10:17:44 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-
-function insertText(text, areaId) {
- var textarea = jQuery('#' + areaId);
- if (document.selection) { // IE
- var selLength;
- textarea.focus();
- sel = document.selection.createRange();
- selLength = sel.text.length;
- sel.text = text;
- sel.moveStart('character', selLength-text.length);
- sel.select();
- } else if (textarea.selectionStart || textarea.selectionStart == '0') { // mozilla
- var startPos = textarea.selectionStart;
- var endPos = textarea.selectionEnd;
- // insert text so that it replaces the [startPos, endPos] part
- textarea.value = textarea.value.substring(0,startPos) + text + textarea.value.substring(endPos,textarea.value.length);
- // set cursor pos at the end of the inserted text
- textarea.selectionStart = textarea.selectionEnd = startPos+text.length;
- textarea.focus();
- } else { // safety belt for other browsers
- textarea.value += text;
- }
-}
--- a/web/data/cubicweb.preferences.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.preferences.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,4 +1,5 @@
-/* toggle visibility of an element by its id
+/**
+ * toggle visibility of an element by its id
* & set current visibility status in a cookie
* XXX whenever used outside of preferences, don't forget to
* move me in a more appropriate place
@@ -11,56 +12,62 @@
jQuery('#' + elemId).toggleClass('hidden');
}
-function closeFieldset(fieldsetid){
+function closeFieldset(fieldsetid) {
var linklabel = _('open all');
- var linkhref = 'javascript:openFieldset("' +fieldsetid + '")';
+ var linkhref = 'javascript:openFieldset("' + fieldsetid + '")';
_toggleFieldset(fieldsetid, 1, linklabel, linkhref);
}
-function openFieldset(fieldsetid){
+function openFieldset(fieldsetid) {
var linklabel = _('close all');
- var linkhref = 'javascript:closeFieldset("'+ fieldsetid + '")';
+ var linkhref = 'javascript:closeFieldset("' + fieldsetid + '")';
_toggleFieldset(fieldsetid, 0, linklabel, linkhref);
}
-function _toggleFieldset(fieldsetid, closeaction, linklabel, linkhref){
- jQuery('#'+fieldsetid).find('div.openlink').each(function(){
- var link = A({'href' : "javascript:noop();",
- 'onclick' : linkhref},
- linklabel);
- jQuery(this).empty().append(link);
- });
- jQuery('#'+fieldsetid).find('fieldset[id]').each(function(){
- var fieldset = jQuery(this);
- if(closeaction){
- fieldset.addClass('hidden');
- }else{
- fieldset.removeClass('hidden');
- linkLabel = (_('open all'));
- }
- });
+function _toggleFieldset(fieldsetid, closeaction, linklabel, linkhref) {
+ jQuery('#' + fieldsetid).find('div.openlink').each(function() {
+ var link = A({
+ 'href': "javascript:noop();",
+ 'onclick': linkhref
+ },
+ linklabel);
+ jQuery(this).empty().append(link);
+ });
+ jQuery('#' + fieldsetid).find('fieldset[id]').each(function() {
+ var fieldset = jQuery(this);
+ if (closeaction) {
+ fieldset.addClass('hidden');
+ } else {
+ fieldset.removeClass('hidden');
+ linkLabel = (_('open all'));
+ }
+ });
}
-function validatePrefsForm(formid){
+function validatePrefsForm(formid) {
clearPreviousMessages();
clearPreviousErrors(formid);
- return validateForm(formid, null, submitSucces, submitFailure);
+ return validateForm(formid, null, submitSucces, submitFailure);
}
-function submitFailure(formid){
- var form = jQuery('#'+formid);
- var dom = DIV({'class':'critical'},
- _("please correct errors below"));
+function submitFailure(formid) {
+ var form = jQuery('#' + formid);
+ var dom = DIV({
+ 'class': 'critical'
+ },
+ _("please correct errors below"));
jQuery(form).find('div.formsg').empty().append(dom);
// clearPreviousMessages()
jQuery(form).find('span.error').next().focus();
}
-function submitSucces(url, formid){
- var form = jQuery('#'+formid);
+function submitSucces(url, formid) {
+ var form = jQuery('#' + formid);
setCurrentValues(form);
- var dom = DIV({'class':'msg'},
- _("changes applied"));
+ var dom = DIV({
+ 'class': 'msg'
+ },
+ _("changes applied"));
jQuery(form).find('div.formsg').empty().append(dom);
jQuery(form).find('input').removeClass('changed');
checkValues(form, true);
@@ -76,78 +83,79 @@
jQuery('#err-value:' + formid).remove();
}
-function checkValues(form, success){
+function checkValues(form, success) {
var unfreezeButtons = false;
- jQuery(form).find('select').each(function () {
- unfreezeButtons = _checkValue(jQuery(this), unfreezeButtons);
- });
- jQuery(form).find('[type=text]').each(function () {
- unfreezeButtons = _checkValue(jQuery(this), unfreezeButtons);
- });
- jQuery(form).find('input[type=radio]:checked').each(function () {
- unfreezeButtons = _checkValue(jQuery(this), unfreezeButtons);
- });
+ jQuery(form).find('select').each(function() {
+ unfreezeButtons = _checkValue(jQuery(this), unfreezeButtons);
+ });
+ jQuery(form).find('[type=text]').each(function() {
+ unfreezeButtons = _checkValue(jQuery(this), unfreezeButtons);
+ });
+ jQuery(form).find('input[type=radio]:checked').each(function() {
+ unfreezeButtons = _checkValue(jQuery(this), unfreezeButtons);
+ });
- if (unfreezeButtons){
- unfreezeFormButtons(form.attr('id'));
- }else{
- if (!success){
- clearPreviousMessages();
- }
- clearPreviousErrors(form.attr('id'));
- freezeFormButtons(form.attr('id'));
+ if (unfreezeButtons) {
+ unfreezeFormButtons(form.attr('id'));
+ } else {
+ if (!success) {
+ clearPreviousMessages();
+ }
+ clearPreviousErrors(form.attr('id'));
+ freezeFormButtons(form.attr('id'));
}
}
-function _checkValue(input, unfreezeButtons){
+function _checkValue(input, unfreezeButtons) {
var currentValue = prefsValues[input.attr('name')];
- if (currentValue != input.val()){
- input.addClass('changed');
- unfreezeButtons = true;
- }else{
- input.removeClass('changed');
- jQuery("span[id=err-" + input.attr('id') + "]").remove();
- }
- input.removeClass('error');
- return unfreezeButtons;
+ if (currentValue != input.val()) {
+ input.addClass('changed');
+ unfreezeButtons = true;
+ } else {
+ input.removeClass('changed');
+ jQuery("span[id=err-" + input.attr('id') + "]").remove();
+ }
+ input.removeClass('error');
+ return unfreezeButtons;
}
-function setCurrentValues(form){
- jQuery(form).find('[name^=value]').each(function () {
- var input = jQuery(this);
- var name = input.attr('name');
- if(input.attr('type') == 'radio'){
- // NOTE: there seems to be a bug with jQuery(input).attr('checked')
- // in our case, we can't rely on its value, we use
- // the DOM API instead.
- if(input[0].checked){
- prefsValues[name] = input.val();
- }
- }else{
- prefsValues[name] = input.val();
- }
- jQuery(form).find('input[name=edits-'+ name + ']').val(prefsValues[name]);
+function setCurrentValues(form) {
+ jQuery(form).find('[name^=value]').each(function() {
+ var input = jQuery(this);
+ var name = input.attr('name');
+ if (input.attr('type') == 'radio') {
+ // NOTE: there seems to be a bug with jQuery(input).attr('checked')
+ // in our case, we can't rely on its value, we use
+ // the DOM API instead.
+ if (input[0].checked) {
+ prefsValues[name] = input.val();
+ }
+ } else {
+ prefsValues[name] = input.val();
+ }
+ jQuery(form).find('input[name=edits-' + name + ']').val(prefsValues[name]);
});
}
-function initEvents(){
+function initEvents() {
jQuery('form').each(function() {
- var form = jQuery(this);
- //freezeFormButtons(form.attr('id'));
- form.find('.validateButton').attr('disabled', 'disabled');
- form.find('input[type=text]').keyup(function(){
- checkValues(form);
- });
- form.find('input[type=radio]').change(function(){
- checkValues(form);
- });
- form.find('select').change(function(){
- checkValues(form);
- });
- setCurrentValues(form);
+ var form = jQuery(this);
+ //freezeFormButtons(form.attr('id'));
+ form.find('.validateButton').attr('disabled', 'disabled');
+ form.find('input[type=text]').keyup(function() {
+ checkValues(form);
+ });
+ form.find('input[type=radio]').change(function() {
+ checkValues(form);
+ });
+ form.find('select').change(function() {
+ checkValues(form);
+ });
+ setCurrentValues(form);
});
}
$(document).ready(function() {
- initEvents();
+ initEvents();
});
+
--- a/web/data/cubicweb.python.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.python.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,18 +1,14 @@
-/*
+/**
* This file contains extensions for standard javascript types
*
*/
ONE_DAY = 86400000; // (in milliseconds)
-
// ========== DATE EXTENSIONS ========== ///
-
Date.prototype.equals = function(other) {
/* compare with other date ignoring time differences */
- if (this.getYear() == other.getYear() &&
- this.getMonth() == other.getMonth() &&
- this.getDate() == other.getDate()) {
- return true;
+ if (this.getYear() == other.getYear() && this.getMonth() == other.getMonth() && this.getDate() == other.getDate()) {
+ return true;
}
return false;
};
@@ -24,7 +20,7 @@
};
Date.prototype.sub = function(days) {
- return this.add(-days);
+ return this.add( - days);
};
Date.prototype.iadd = function(days) {
@@ -39,33 +35,37 @@
this.setTime(this.getTime() - (days * ONE_DAY));
};
-/*
+/**
+ * .. function:: Date.prototype.nextMonth()
+ *
* returns the first day of the next month
*/
Date.prototype.nextMonth = function() {
if (this.getMonth() == 11) {
- var d =new Date(this.getFullYear()+1, 0, 1);
- return d;
+ var d = new Date(this.getFullYear() + 1, 0, 1);
+ return d;
} else {
- var d2 = new Date(this.getFullYear(), this.getMonth()+1, 1);
- return d2;
+ var d2 = new Date(this.getFullYear(), this.getMonth() + 1, 1);
+ return d2;
}
};
-/*
+/**
+ * .. function:: Date.prototype.getRealDay()
+ *
* returns the day of week, 0 being monday, 6 being sunday
*/
Date.prototype.getRealDay = function() {
// getDay() returns 0 for Sunday ==> 6 for Saturday
- return (this.getDay()+6) % 7;
+ return (this.getDay() + 6) % 7;
};
Date.prototype.strftime = function(fmt) {
if (this.toLocaleFormat !== undefined) { // browser dependent
- return this.toLocaleFormat(fmt);
+ return this.toLocaleFormat(fmt);
}
// XXX implement at least a decent fallback implementation
- return this.getFullYear() + '/' + (this.getMonth()+1) + '/' + this.getDate();
+ return this.getFullYear() + '/' + (this.getMonth() + 1) + '/' + this.getDate();
};
var _DATE_FORMAT_REGXES = {
@@ -74,231 +74,131 @@
'm': new RegExp('^[0-9]{1,2}'),
'H': new RegExp('^[0-9]{1,2}'),
'M': new RegExp('^[0-9]{1,2}')
-}
+};
-/*
+/**
+ * .. function:: _parseDate(datestring, format)
+ *
* _parseData does the actual parsing job needed by `strptime`
*/
function _parseDate(datestring, format) {
var skip0 = new RegExp('^0*[0-9]+');
var parsed = {};
- for (var i1=0,i2=0;i1<format.length;i1++,i2++) {
- var c1 = format.charAt(i1);
- var c2 = datestring.charAt(i2);
- if (c1 == '%') {
- c1 = format.charAt(++i1);
- var data = _DATE_FORMAT_REGXES[c1].exec(datestring.substring(i2));
- if (!data.length) {
- return null;
- }
- data = data[0];
- i2 += data.length-1;
- var value = parseInt(data, 10);
- if (isNaN(value)) {
- return null;
- }
- parsed[c1] = value;
- continue;
- }
- if (c1 != c2) {
- return null;
- }
+ for (var i1 = 0, i2 = 0; i1 < format.length; i1++, i2++) {
+ var c1 = format.charAt(i1);
+ var c2 = datestring.charAt(i2);
+ if (c1 == '%') {
+ c1 = format.charAt(++i1);
+ var data = _DATE_FORMAT_REGXES[c1].exec(datestring.substring(i2));
+ if (!data.length) {
+ return null;
+ }
+ data = data[0];
+ i2 += data.length - 1;
+ var value = parseInt(data, 10);
+ if (isNaN(value)) {
+ return null;
+ }
+ parsed[c1] = value;
+ continue;
+ }
+ if (c1 != c2) {
+ return null;
+ }
}
return parsed;
}
-/*
+/**
+ * .. function:: strptime(datestring, format)
+ *
* basic implementation of strptime. The only recognized formats
* defined in _DATE_FORMAT_REGEXES (i.e. %Y, %d, %m, %H, %M)
*/
function strptime(datestring, format) {
var parsed = _parseDate(datestring, format);
if (!parsed) {
- return null;
+ return null;
}
// create initial date (!!! year=0 means 1900 !!!)
var date = new Date(0, 0, 1, 0, 0);
date.setFullYear(0); // reset to year 0
if (parsed.Y) {
- date.setFullYear(parsed.Y);
+ date.setFullYear(parsed.Y);
}
if (parsed.m) {
- if (parsed.m < 1 || parsed.m > 12) {
- return null;
- }
- // !!! month indexes start at 0 in javascript !!!
- date.setMonth(parsed.m - 1);
+ if (parsed.m < 1 || parsed.m > 12) {
+ return null;
+ }
+ // !!! month indexes start at 0 in javascript !!!
+ date.setMonth(parsed.m - 1);
}
if (parsed.d) {
- if (parsed.m < 1 || parsed.m > 31) {
- return null;
- }
- date.setDate(parsed.d);
+ if (parsed.m < 1 || parsed.m > 31) {
+ return null;
+ }
+ date.setDate(parsed.d);
}
if (parsed.H) {
- if (parsed.H < 0 || parsed.H > 23) {
- return null;
- }
- date.setHours(parsed.H);
+ if (parsed.H < 0 || parsed.H > 23) {
+ return null;
+ }
+ date.setHours(parsed.H);
}
if (parsed.M) {
- if (parsed.M < 0 || parsed.M > 59) {
- return null;
- }
- date.setMinutes(parsed.M);
+ if (parsed.M < 0 || parsed.M > 59) {
+ return null;
+ }
+ date.setMinutes(parsed.M);
}
return date;
}
// ========== END OF DATE EXTENSIONS ========== ///
-
-
-
-// ========== ARRAY EXTENSIONS ========== ///
-Array.prototype.contains = function(element) {
- return findValue(this, element) != -1;
-};
-
-// ========== END OF ARRAY EXTENSIONS ========== ///
-
-
-
// ========== STRING EXTENSIONS ========== //
-
-/* python-like startsWith method for js strings
+/**
+ * .. function:: String.prototype.startswith(prefix)
+ *
+ * python-like startsWith method for js strings
* >>>
*/
-String.prototype.startsWith = function(prefix) {
+String.prototype.startswith = function(prefix) {
return this.indexOf(prefix) == 0;
};
-/* python-like endsWith method for js strings */
-String.prototype.endsWith = function(suffix) {
+/**
+ * .. function:: String.prototype.endswith(suffix)
+ *
+ * python-like endsWith method for js strings
+ */
+String.prototype.endswith = function(suffix) {
var startPos = this.length - suffix.length;
- if (startPos < 0) { return false; }
+ if (startPos < 0) {
+ return false;
+ }
return this.lastIndexOf(suffix, startPos) == startPos;
};
-/* python-like strip method for js strings */
+/**
+ * .. function:: String.prototype.strip()
+ *
+ * python-like strip method for js strings
+ */
String.prototype.strip = function() {
return this.replace(/^\s*(.*?)\s*$/, "$1");
};
-/* py-equiv: string in list */
-String.prototype.in_ = function(values) {
- return findValue(values, this) != -1;
-};
-
-/* py-equiv: str.join(list) */
-String.prototype.join = function(args) {
- return args.join(this);
-};
+// ========= class factories ========= //
-/* python-like list builtin
- * transforms an iterable in a js sequence
- * >>> gen = ifilter(function(x) {return x%2==0}, range(10))
- * >>> s = list(gen)
- * [0,2,4,6,8]
- */
-function list(iterable) {
- var iterator = iter(iterable);
- var result = [];
- while (true) {
- /* iterates until StopIteration occurs */
- try {
- result.push(iterator.next());
- } catch (exc) {
- if (exc != StopIteration) { throw exc; }
- return result;
- }
- }
-}
-
-/* py-equiv: getattr(obj, attrname, default=None) */
-function getattr(obj, attrname, defaultValue) {
- // when not passed, defaultValue === undefined
- return obj[attrname] || defaultValue;
-}
-
-/* py-equiv: operator.attrgetter */
-function attrgetter(attrname) {
- return function(obj) { return getattr(obj, attrname); };
-}
-
-
-/* returns a subslice of `lst` using `start`/`stop`/`step`
- * start, stop might be negative
+/**
+ * .. function:: makeUnboundMethod(meth)
*
- * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], 2)
- * ['c', 'd', 'e', 'f']
- * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], 2, -2)
- * ['c', 'd']
- * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], -3)
- * ['d', 'e', 'f']
+ * transforms a function into an unbound method
*/
-function sliceList(lst, start, stop, step) {
- start = start || 0;
- stop = stop || lst.length;
- step = step || 1;
- if (stop < 0) {
- stop = max(lst.length+stop, 0);
- }
- if (start < 0) {
- start = min(lst.length+start, lst.length);
- }
- var result = [];
- for (var i=start; i < stop; i+=step) {
- result.push(lst[i]);
- }
- return result;
-}
-
-/* returns a partial func that calls a mehod on its argument
- * py-equiv: return lambda obj: getattr(obj, methname)(*args)
- */
-// XXX looks completely unused (candidate for removal)
-function methodcaller(methname) {
- var args = sliceList(arguments, 1);
- return function(obj) {
- return obj[methname].apply(obj, args);
- };
-}
-
-/* use MochiKit's listMin / listMax */
-function min() { return listMin(arguments); }
-function max() { return listMax(arguments); }
-
-/*
- * >>> d = dict(["x", "y", "z"], [0, 1, 2])
- * >>> d['y']
- * 1
- * >>> d.y
- * 1
- */
-function dict(keys, values) {
- if (keys.length != values.length) {
- throw "got different number of keys and values !";
- }
- var newobj = {};
- for(var i=0; i<keys.length; i++) {
- newobj[keys[i]] = values[i];
- }
- return newobj;
-}
-
-
-function concat() {
- return ''.join(list(arguments));
-}
-
-
-/**** class factories ****/
-
-// transforms a function into an unbound method
function makeUnboundMethod(meth) {
function unboundMeth(self) {
- var newargs = sliceList(arguments, 1);
- return meth.apply(self, newargs);
+ var newargs = sliceList(arguments, 1);
+ return meth.apply(self, newargs);
}
unboundMeth.__name__ = meth.__name__;
return unboundMeth;
@@ -312,29 +212,40 @@
cls.prototype[methname] = meth; // for the instance
}
-// simple internal function that tells if the attribute should
-// be copied from baseclasses or not
+/**
+ * .. function:: _isAttrSkipped(attrname)
+ *
+ * simple internal function that tells if the attribute should
+ * be copied from baseclasses or not
+ */
function _isAttrSkipped(attrname) {
var skipped = ['__class__', '__dict__', '__bases__', 'prototype'];
- for (var i=0; i < skipped.length; i++) {
- if (skipped[i] == attrname) {
- return true;
- }
+ for (var i = 0; i < skipped.length; i++) {
+ if (skipped[i] == attrname) {
+ return true;
+ }
}
return false;
}
-// internal function used to build the class constructor
+/**
+ * .. function:: makeConstructor(userctor)
+ *
+ * internal function used to build the class constructor
+ */
function makeConstructor(userctor) {
return function() {
- // this is a proxy to user's __init__
- if (userctor) {
- userctor.apply(this, arguments);
- }
+ // this is a proxy to user's __init__
+ if (userctor) {
+ userctor.apply(this, arguments);
+ }
};
}
-/* this is a js class factory. objects returned by this function behave
+/**
+ * .. function:: defclass(name, bases, classdict)
+ *
+ * this is a js class factory. objects returned by this function behave
* more or less like a python class. The `class` function prototype is
* inspired by the python `type` builtin
* Important notes :
@@ -347,19 +258,21 @@
// this is the static inheritance approach (<=> differs from python)
var basemeths = {};
var reverseLookup = [];
- for(var i=baseclasses.length-1; i >= 0; i--) {
- reverseLookup.push(baseclasses[i]);
+ for (var i = baseclasses.length - 1; i >= 0; i--) {
+ reverseLookup.push(baseclasses[i]);
}
- reverseLookup.push({'__dict__' : classdict});
+ reverseLookup.push({
+ '__dict__': classdict
+ });
- for(var i=0; i < reverseLookup.length; i++) {
- var cls = reverseLookup[i];
- for (prop in cls.__dict__) {
- // XXX hack to avoid __init__, __bases__...
- if ( !_isAttrSkipped(prop) ) {
- basemeths[prop] = cls.__dict__[prop];
- }
- }
+ for (var i = 0; i < reverseLookup.length; i++) {
+ var cls = reverseLookup[i];
+ for (prop in cls.__dict__) {
+ // XXX hack to avoid __init__, __bases__...
+ if (!_isAttrSkipped(prop)) {
+ basemeths[prop] = cls.__dict__[prop];
+ }
+ }
}
var userctor = basemeths['__init__'];
var constructor = makeConstructor(userctor);
@@ -371,38 +284,8 @@
constructor.prototype.__class__ = constructor;
// make bound / unbound methods
for (methname in basemeths) {
- attachMethodToClass(constructor, methname, basemeths[methname]);
+ attachMethodToClass(constructor, methname, basemeths[methname]);
}
return constructor;
}
-
-// Not really python-like
-CubicWeb = {};
-// XXX backward compatibility
-Erudi = CubicWeb;
-CubicWeb.loaded = [];
-CubicWeb.require = function(module) {
- if (!CubicWeb.loaded.contains(module)) {
- // a CubicWeb.load_javascript(module) function would require a dependency on ajax.js
- log(module, ' is required but not loaded');
- }
-};
-
-CubicWeb.provide = function(module) {
- if (!CubicWeb.loaded.contains(module)) {
- CubicWeb.loaded.push(module);
- }
-};
-
-jQuery(document).ready(function() {
- jQuery(CubicWeb).trigger('server-response', [false, document]);
-});
-
-// XXX as of 2010-04-07, no known cube uses this
-jQuery(CubicWeb).bind('ajax-loaded', function() {
- log('[3.7] "ajax-loaded" event is deprecated, use "server-response" instead');
- jQuery(CubicWeb).trigger('server-response', [false, document]);
-});
-
-CubicWeb.provide('python.js');
--- a/web/data/cubicweb.rhythm.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.rhythm.js Thu Jun 03 14:51:42 2010 +0200
@@ -2,6 +2,6 @@
$('a.rhythm').click(function (event){
$('div#pageContent').toggleClass('rhythm_bg');
$('div#page').toggleClass('rhythm_bg');
- event.preventDefault();
- });
+ event.preventDefault();
});
+});
--- a/web/data/cubicweb.tabs.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.tabs.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,6 +1,7 @@
function set_tab(tabname, cookiename) {
// set appropriate cookie
- asyncRemoteExec('set_cookie', cookiename, tabname);
+ loadRemote('json', ajaxFuncArgs('set_cookie', null, cookiename, tabname));
// trigger show + tabname event
trigger_load(tabname);
}
+
--- a/web/data/cubicweb.timeline-ext.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.timeline-ext.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,49 +1,49 @@
-/*
+/**
* :organization: Logilab
- * :copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2008-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*
*/
-
-/* provide our own custom date parser since the default
+/**
+ * provide our own custom date parser since the default
* one only understands iso8601 and gregorian dates
*/
SimileAjax.NativeDateUnit.getParser = Timeline.NativeDateUnit.getParser = function(format) {
if (typeof format == "string") {
- if (format.indexOf('%') != -1) {
- return function(datestring) {
- if (datestring) {
- return strptime(datestring, format);
- }
- return null;
- };
- }
+ if (format.indexOf('%') != - 1) {
+ return function(datestring) {
+ if (datestring) {
+ return strptime(datestring, format);
+ }
+ return null;
+ };
+ }
format = format.toLowerCase();
}
if (format == "iso8601" || format == "iso 8601") {
- return Timeline.DateTime.parseIso8601DateTime;
+ return Timeline.DateTime.parseIso8601DateTime;
}
return Timeline.DateTime.parseGregorianDateTime;
};
/*** CUBICWEB EVENT PAINTER *****************************************************/
Timeline.CubicWebEventPainter = function(params) {
-// Timeline.OriginalEventPainter.apply(this, arguments);
- this._params = params;
- this._onSelectListeners = [];
+ // Timeline.OriginalEventPainter.apply(this, arguments);
+ this._params = params;
+ this._onSelectListeners = [];
- this._filterMatcher = null;
- this._highlightMatcher = null;
- this._frc = null;
+ this._filterMatcher = null;
+ this._highlightMatcher = null;
+ this._frc = null;
- this._eventIdToElmt = {};
+ this._eventIdToElmt = {};
};
Timeline.CubicWebEventPainter.prototype = new Timeline.OriginalEventPainter();
Timeline.CubicWebEventPainter.prototype._paintEventLabel = function(
- evt, text, left, top, width, height, theme) {
+evt, text, left, top, width, height, theme) {
var doc = this._timeline.getDocument();
var labelDiv = doc.createElement("div");
@@ -54,15 +54,21 @@
labelDiv.style.top = top + "px";
if (evt._obj.onclick) {
- labelDiv.appendChild(A({'href': evt._obj.onclick}, text));
+ labelDiv.appendChild(A({
+ 'href': evt._obj.onclick
+ },
+ text));
} else if (evt._obj.image) {
- labelDiv.appendChild(IMG({src: evt._obj.image, width: '30px', height: '30px'}));
+ labelDiv.appendChild(IMG({
+ src: evt._obj.image,
+ width: '30px',
+ height: '30px'
+ }));
} else {
- labelDiv.innerHTML = text;
+ labelDiv.innerHTML = text;
}
- if(evt._title != null)
- labelDiv.title = evt._title;
+ if (evt._title != null) labelDiv.title = evt._title;
var color = evt.getTextColor();
if (color == null) {
@@ -72,29 +78,31 @@
labelDiv.style.color = color;
}
var classname = evt.getClassName();
- if(classname) labelDiv.className +=' ' + classname;
+ if (classname) labelDiv.className += ' ' + classname;
this._eventLayer.appendChild(labelDiv);
return {
- left: left,
- top: top,
- width: width,
+ left: left,
+ top: top,
+ width: width,
height: height,
- elmt: labelDiv
+ elmt: labelDiv
};
};
+Timeline.CubicWebEventPainter.prototype._showBubble = function(x, y, evt) {
+ var div = DIV({
+ id: 'xxx'
+ });
+ var width = this._params.theme.event.bubble.width;
+ if (!evt._obj.bubbleUrl) {
+ evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
+ }
+ SimileAjax.WindowManager.cancelPopups();
+ SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, width);
+ if (evt._obj.bubbleUrl) {
+ jQuery('#xxx').loadxhtml(evt._obj.bubbleUrl, null, 'post', 'replace');
+ }
+};
-Timeline.CubicWebEventPainter.prototype._showBubble = function(x, y, evt) {
- var div = DIV({id: 'xxx'});
- var width = this._params.theme.event.bubble.width;
- if (!evt._obj.bubbleUrl) {
- evt.fillInfoBubble(div, this._params.theme, this._band.getLabeller());
- }
- SimileAjax.WindowManager.cancelPopups();
- SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, width);
- if (evt._obj.bubbleUrl) {
- jQuery('#xxx').loadxhtml(evt._obj.bubbleUrl, null, 'post', 'replace');
- }
-};
--- a/web/data/cubicweb.widgets.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/cubicweb.widgets.js Thu Jun 03 14:51:42 2010 +0200
@@ -1,6 +1,8 @@
-/*
+/**
+ * Functions dedicated to widgets.
+ *
* :organization: Logilab
- * :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*
*
@@ -9,144 +11,175 @@
// widget namespace
Widgets = {};
-
-/* this function takes a DOM node defining a widget and
+/**
+ * .. function:: buildWidget(wdgnode)
+ *
+ * this function takes a DOM node defining a widget and
* instantiates / builds the appropriate widget class
*/
function buildWidget(wdgnode) {
var wdgclass = Widgets[wdgnode.getAttribute('cubicweb:wdgtype')];
if (wdgclass) {
- var wdg = new wdgclass(wdgnode);
+ var wdg = new wdgclass(wdgnode);
}
}
-/* This function is called on load and is in charge to build
+/**
+ * .. function:: buildWidgets(root)
+ *
+ * This function is called on load and is in charge to build
* JS widgets according to DOM nodes found in the page
*/
function buildWidgets(root) {
root = root || document;
jQuery(root).find('.widget').each(function() {
- if (this.getAttribute('cubicweb:loadtype') == 'auto') {
- buildWidget(this);
- }
+ if (this.getAttribute('cubicweb:loadtype') == 'auto') {
+ buildWidget(this);
+ }
});
}
-
// we need to differenciate cases where initFacetBoxEvents is called
// with one argument or without any argument. If we use `initFacetBoxEvents`
// as the direct callback on the jQuery.ready event, jQuery will pass some argument
// of his, so we use this small anonymous function instead.
-jQuery(document).ready(function() {buildWidgets();});
+jQuery(document).ready(function() {
+ buildWidgets();
+});
+function postJSON(url, data, callback) {
+ return jQuery.post(url, data, callback, 'json');
+}
+
+function getJSON(url, data, callback) {
+ return jQuery.get(url, data, callback, 'json');
+}
Widgets.SuggestField = defclass('SuggestField', null, {
__init__: function(node, options) {
- var multi = node.getAttribute('cubicweb:multi') || "no";
- options = options || {};
- options.multiple = (multi == "yes") ? true : false;
- var dataurl = node.getAttribute('cubicweb:dataurl');
+ var multi = node.getAttribute('cubicweb:multi') || "no";
+ options = options || {};
+ options.multiple = (multi == "yes") ? true: false;
+ var dataurl = node.getAttribute('cubicweb:dataurl');
var method = postJSON;
- if (options.method == 'get'){
- method = function(url, data, callback) {
- // We can't rely on jQuery.getJSON because the server
- // might set the Content-Type's response header to 'text/plain'
- jQuery.get(url, data, function(response) {
- callback(evalJSON(response));
- });
- };
- }
- var self = this; // closure
- method(dataurl, null, function(data) {
- // in case we received a list of couple, we assume that the first
- // element is the real value to be sent, and the second one is the
- // value to be displayed
- if (data.length && data[0].length == 2) {
- options.formatItem = function(row) { return row[1]; };
- self.hideRealValue(node);
- self.setCurrentValue(node, data);
- }
- jQuery(node).autocomplete(data, options);
- });
+ if (options.method == 'get') {
+ method = function(url, data, callback) {
+ // We can't rely on jQuery.getJSON because the server
+ // might set the Content-Type's response header to 'text/plain'
+ jQuery.get(url, data, function(response) {
+ callback(cw.evalJSON(response));
+ });
+ };
+ }
+ var self = this; // closure
+ method(dataurl, null, function(data) {
+ // in case we received a list of couple, we assume that the first
+ // element is the real value to be sent, and the second one is the
+ // value to be displayed
+ if (data.length && data[0].length == 2) {
+ options.formatItem = function(row) {
+ return row[1];
+ };
+ self.hideRealValue(node);
+ self.setCurrentValue(node, data);
+ }
+ jQuery(node).autocomplete(data, options);
+ });
},
hideRealValue: function(node) {
- var hidden = INPUT({'type': "hidden", 'name': node.name, 'value': node.value});
- node.parentNode.appendChild(hidden);
- // remove 'name' attribute from visible input so that it is not submitted
- // and set correct value in the corresponding hidden field
- jQuery(node).removeAttr('name').bind('result', function(_, row, _) {
- hidden.value = row[0];
- });
+ var hidden = INPUT({
+ 'type': "hidden",
+ 'name': node.name,
+ 'value': node.value
+ });
+ node.parentNode.appendChild(hidden);
+ // remove 'name' attribute from visible input so that it is not submitted
+ // and set correct value in the corresponding hidden field
+ jQuery(node).removeAttr('name').bind('result', function(_, row, _) {
+ hidden.value = row[0];
+ });
},
setCurrentValue: function(node, data) {
- // called when the data is loaded to reset the correct displayed
- // value in the visible input field (typically replacing an eid
- // by a displayable value)
- var curvalue = node.value;
- if (!node.value) {
- return;
- }
- for (var i=0,length=data.length; i<length; i++) {
- var row = data[i];
- if (row[0] == curvalue) {
- node.value = row[1];
- return;
- }
- }
+ // called when the data is loaded to reset the correct displayed
+ // value in the visible input field (typically replacing an eid
+ // by a displayable value)
+ var curvalue = node.value;
+ if (!node.value) {
+ return;
+ }
+ for (var i = 0, length = data.length; i < length; i++) {
+ var row = data[i];
+ if (row[0] == curvalue) {
+ node.value = row[1];
+ return;
+ }
+ }
}
});
Widgets.StaticFileSuggestField = defclass('StaticSuggestField', [Widgets.SuggestField], {
- __init__ : function(node) {
- Widgets.SuggestField.__init__(this, node, {method: 'get'});
+ __init__: function(node) {
+ Widgets.SuggestField.__init__(this, node, {
+ method: 'get'
+ });
}
});
Widgets.RestrictedSuggestField = defclass('RestrictedSuggestField', [Widgets.SuggestField], {
- __init__ : function(node) {
- Widgets.SuggestField.__init__(this, node, {mustMatch: true});
+ __init__: function(node) {
+ Widgets.SuggestField.__init__(this, node, {
+ mustMatch: true
+ });
}
});
//remote version of RestrictedSuggestField
Widgets.LazySuggestField = defclass('LazySuggestField', [Widgets.SuggestField], {
__init__: function(node, options) {
- var self = this;
- var multi = "no";
- options = options || {};
- options.max = 50;
- options.delay = 50;
- options.cacheLength=0;
- options.mustMatch = true;
+ var self = this;
+ var multi = "no";
+ options = options || {};
+ options.max = 50;
+ options.delay = 50;
+ options.cacheLength = 0;
+ options.mustMatch = true;
// multiple selection not supported yet (still need to formalize correctly
// initial values / display values)
- var initialvalue = evalJSON(node.getAttribute('cubicweb:initialvalue') || 'null');
+ var initialvalue = cw.evalJSON(node.getAttribute('cubicweb:initialvalue') || 'null');
if (!initialvalue) {
initialvalue = node.value;
}
- options = jQuery.extend({dataType: 'json',
- multiple: (multi == "yes") ? true : false,
- parse: this.parseResult
- }, options);
+ options = jQuery.extend({
+ dataType: 'json',
+ multiple: (multi == "yes") ? true: false,
+ parse: this.parseResult
+ },
+ options);
var dataurl = node.getAttribute('cubicweb:dataurl');
// remove 'name' from original input and add the hidden one that will
// store the actual value
- var hidden = INPUT({'type': "hidden", 'name': node.name, 'value': initialvalue});
+ var hidden = INPUT({
+ 'type': "hidden",
+ 'name': node.name,
+ 'value': initialvalue
+ });
node.parentNode.appendChild(hidden);
- jQuery(node).bind('result', {hinput: hidden, input:node}, self.hideRealValue)
- .removeAttr('name').autocomplete(dataurl, options);
+ jQuery(node).bind('result', {
+ hinput: hidden,
+ input: node
+ },
+ self.hideRealValue).removeAttr('name').autocomplete(dataurl, options);
},
-
hideRealValue: function(evt, data, value) {
- if (!value){
- value="";
- }
+ if (!value) {
+ value = "";
+ }
evt.data.hinput.value = value;
},
@@ -156,68 +189,80 @@
*/
parseResult: function(data) {
var parsed = [];
- for (var i=0; i < data.length; i++) {
- var value = ''+data[i][0]; // a string is required later by jquery.autocomplete.js
- var label = data[i][1];
- parsed[parsed.length] = {
- data: [label],
- value: value,
- result: label
- };
+ for (var i = 0; i < data.length; i++) {
+ var value = '' + data[i][0]; // a string is required later by jquery.autocomplete.js
+ var label = data[i][1];
+ parsed[parsed.length] = {
+ data: [label],
+ value: value,
+ result: label
+ };
};
return parsed;
}
});
-/*
+/**
+ * .. class:: Widgets.SuggestForm
+ *
* suggestform displays a suggest field and associated validate / cancel buttons
* constructor's argumemts are the same that BaseSuggestField widget
*/
Widgets.SuggestForm = defclass("SuggestForm", null, {
- __init__ : function(inputid, initfunc, varargs, validatefunc, options) {
- this.validatefunc = validatefunc || noop;
- this.sgfield = new Widgets.BaseSuggestField(inputid, initfunc,
- varargs, options);
- this.oklabel = options.oklabel || 'ok';
- this.cancellabel = options.cancellabel || 'cancel';
- bindMethods(this);
- connect(this.sgfield, 'validate', this, this.entryValidated);
+ __init__: function(inputid, initfunc, varargs, validatefunc, options) {
+ this.validatefunc = validatefunc || noop;
+ this.sgfield = new Widgets.BaseSuggestField(inputid, initfunc, varargs, options);
+ this.oklabel = options.oklabel || 'ok';
+ this.cancellabel = options.cancellabel || 'cancel';
+ bindMethods(this);
+ connect(this.sgfield, 'validate', this, this.entryValidated);
},
- show : function(parentnode) {
- var sgnode = this.sgfield.builddom();
- var buttons = DIV({'class' : "sgformbuttons"},
- [A({'href' : "javascript: noop();",
- 'onclick' : this.onValidateClicked}, this.oklabel),
- ' / ',
- A({'href' : "javascript: noop();",
- 'onclick' : this.destroy}, escapeHTML(this.cancellabel))]);
- var formnode = DIV({'class' : "sgform"}, [sgnode, buttons]);
- appendChildNodes(parentnode, formnode);
- this.sgfield.textinput.focus();
- this.formnode = formnode;
- return formnode;
+ show: function(parentnode) {
+ var sgnode = this.sgfield.builddom();
+ var buttons = DIV({
+ 'class': "sgformbuttons"
+ },
+ [A({
+ 'href': "javascript: noop();",
+ 'onclick': this.onValidateClicked
+ },
+ this.oklabel), ' / ', A({
+ 'href': "javascript: noop();",
+ 'onclick': this.destroy
+ },
+ escapeHTML(this.cancellabel))]);
+ var formnode = DIV({
+ 'class': "sgform"
+ },
+ [sgnode, buttons]);
+ appendChildNodes(parentnode, formnode);
+ this.sgfield.textinput.focus();
+ this.formnode = formnode;
+ return formnode;
},
- destroy : function() {
- signal(this, 'destroy');
- this.sgfield.destroy();
- removeElement(this.formnode);
+ destroy: function() {
+ signal(this, 'destroy');
+ this.sgfield.destroy();
+ removeElement(this.formnode);
},
- onValidateClicked : function() {
- this.validatefunc(this, this.sgfield.taglist());
+ onValidateClicked: function() {
+ this.validatefunc(this, this.sgfield.taglist());
},
/* just an indirection to pass the form instead of the sgfield as first parameter */
- entryValidated : function(sgfield, taglist) {
- this.validatefunc(this, taglist);
+ entryValidated: function(sgfield, taglist) {
+ this.validatefunc(this, taglist);
}
});
-
-/* called when the use clicks on a tree node
+/**
+ * .. function:: toggleTree(event)
+ *
+ * called when the use clicks on a tree node
* - if the node has a `cubicweb:loadurl` attribute, replace the content of the node
* by the url's content.
* - else, there's nothing to do, let the jquery plugin handle it.
@@ -227,91 +272,136 @@
var url = linode.attr('cubicweb:loadurl');
if (url) {
linode.find('ul.placeholder').remove();
- linode.loadxhtml(url, {callback: function(domnode) {
- linode.removeAttr('cubicweb:loadurl');
- jQuery(domnode).treeview({toggle: toggleTree,
- prerendered: true});
- return null;
- }}, 'post', 'append');
+ linode.loadxhtml(url, {
+ callback: function(domnode) {
+ linode.removeAttr('cubicweb:loadurl');
+ jQuery(domnode).treeview({
+ toggle: toggleTree,
+ prerendered: true
+ });
+ return null;
+ }
+ },
+ 'post', 'append');
}
}
-
-/* widget based on SIMILE's timeline widget
+/**
+ * .. class:: Widgets.TimelineWidget
+ *
+ * widget based on SIMILE's timeline widget
* http://code.google.com/p/simile-widgets/
*
* Beware not to mess with SIMILE's Timeline JS namepsace !
*/
Widgets.TimelineWidget = defclass("TimelineWidget", null, {
- __init__: function (wdgnode) {
- var tldiv = DIV({id: "tl", style: 'height: 200px; border: 1px solid #ccc;'});
- wdgnode.appendChild(tldiv);
- var tlunit = wdgnode.getAttribute('cubicweb:tlunit') || 'YEAR';
- var eventSource = new Timeline.DefaultEventSource();
- var bandData = {
- eventPainter: Timeline.CubicWebEventPainter,
- eventSource: eventSource,
- width: "100%",
- intervalUnit: Timeline.DateTime[tlunit.toUpperCase()],
- intervalPixels: 100
- };
- var bandInfos = [ Timeline.createBandInfo(bandData) ];
- var tl = Timeline.create(tldiv, bandInfos);
- var loadurl = wdgnode.getAttribute('cubicweb:loadurl');
- Timeline.loadJSON(loadurl, function(json, url) {
- eventSource.loadJSON(json, url); });
+ __init__: function(wdgnode) {
+ var tldiv = DIV({
+ id: "tl",
+ style: 'height: 200px; border: 1px solid #ccc;'
+ });
+ wdgnode.appendChild(tldiv);
+ var tlunit = wdgnode.getAttribute('cubicweb:tlunit') || 'YEAR';
+ var eventSource = new Timeline.DefaultEventSource();
+ var bandData = {
+ eventPainter: Timeline.CubicWebEventPainter,
+ eventSource: eventSource,
+ width: "100%",
+ intervalUnit: Timeline.DateTime[tlunit.toUpperCase()],
+ intervalPixels: 100
+ };
+ var bandInfos = [Timeline.createBandInfo(bandData)];
+ var tl = Timeline.create(tldiv, bandInfos);
+ var loadurl = wdgnode.getAttribute('cubicweb:loadurl');
+ Timeline.loadJSON(loadurl, function(json, url) {
+ eventSource.loadJSON(json, url);
+ });
}
});
Widgets.TemplateTextField = defclass("TemplateTextField", null, {
- __init__ : function(wdgnode) {
- this.variables = getNodeAttribute(wdgnode, 'cubicweb:variables').split(',');
- this.options = {'name' : wdgnode.getAttribute('cubicweb:inputid'),
- 'rows' : wdgnode.getAttribute('cubicweb:rows') || 40,
- 'cols' : wdgnode.getAttribute('cubicweb:cols') || 80
- };
- // this.variableRegexp = /%\((\w+)\)s/;
- this.errorField = DIV({'class' : "errorMessage"});
- this.textField = TEXTAREA(this.options);
- jQuery(this.textField).bind('keyup', {'self': this}, this.highlightInvalidVariables);
- jQuery('#substitutions').prepend(this.errorField);
- jQuery('#substitutions .errorMessage').hide();
- wdgnode.appendChild(this.textField);
+ __init__: function(wdgnode) {
+ this.variables = jQuery(wdgnode).attr('cubicweb:variables').split(',');
+ this.options = {
+ name: wdgnode.getAttribute('cubicweb:inputid'),
+ rows: wdgnode.getAttribute('cubicweb:rows') || 40,
+ cols: wdgnode.getAttribute('cubicweb:cols') || 80
+ };
+ // this.variableRegexp = /%\((\w+)\)s/;
+ this.errorField = DIV({
+ 'class': "errorMessage"
+ });
+ this.textField = TEXTAREA(this.options);
+ jQuery(this.textField).bind('keyup', {
+ 'self': this
+ },
+ this.highlightInvalidVariables);
+ jQuery('#substitutions').prepend(this.errorField);
+ jQuery('#substitutions .errorMessage').hide();
+ wdgnode.appendChild(this.textField);
},
/* signal callbacks */
- highlightInvalidVariables : function(event) {
- var self = event.data.self;
- var text = self.textField.value;
- var unknownVariables = [];
- var it = 0;
- var group = null;
- var variableRegexp = /%\((\w+)\)s/g;
- // emulates rgx.findAll()
- while ( group=variableRegexp.exec(text) ) {
- if ( !self.variables.contains(group[1]) ) {
- unknownVariables.push(group[1]);
- }
- it++;
- if (it > 5) {
- break;
- }
- }
- var errText = '';
- if (unknownVariables.length) {
- errText = "Detected invalid variables : " + ", ".join(unknownVariables);
- jQuery('#substitutions .errorMessage').show();
- } else {
- jQuery('#substitutions .errorMessage').hide();
- }
- self.errorField.innerHTML = errText;
+ highlightInvalidVariables: function(event) {
+ var self = event.data.self;
+ var text = self.textField.value;
+ var unknownVariables = [];
+ var it = 0;
+ var group = null;
+ var variableRegexp = /%\((\w+)\)s/g;
+ // emulates rgx.findAll()
+ while (group = variableRegexp.exec(text)) {
+ if (!self.variables.contains(group[1])) {
+ unknownVariables.push(group[1]);
+ }
+ it++;
+ if (it > 5) {
+ break;
+ }
+ }
+ var errText = '';
+ if (unknownVariables.length) {
+ errText = "Detected invalid variables : " + unknownVariables.join(', ');
+ jQuery('#substitutions .errorMessage').show();
+ } else {
+ jQuery('#substitutions .errorMessage').hide();
+ }
+ self.errorField.innerHTML = errText;
}
});
-
-CubicWeb.provide('widgets.js');
+cw.widgets = {
+ /**
+ * .. function:: insertText(text, areaId)
+ *
+ * inspects textarea with id `areaId` and replaces the current selected text
+ * with `text`. Cursor is then set at the end of the inserted text.
+ */
+ insertText: function (text, areaId) {
+ var textarea = jQuery('#' + areaId);
+ if (document.selection) { // IE
+ var selLength;
+ textarea.focus();
+ var sel = document.selection.createRange();
+ selLength = sel.text.length;
+ sel.text = text;
+ sel.moveStart('character', selLength - text.length);
+ sel.select();
+ } else if (textarea.selectionStart || textarea.selectionStart == '0') { // mozilla
+ var startPos = textarea.selectionStart;
+ var endPos = textarea.selectionEnd;
+ // insert text so that it replaces the [startPos, endPos] part
+ textarea.value = textarea.value.substring(0, startPos) + text + textarea.value.substring(endPos, textarea.value.length);
+ // set cursor pos at the end of the inserted text
+ textarea.selectionStart = textarea.selectionEnd = startPos + text.length;
+ textarea.focus();
+ } else { // safety belt for other browsers
+ textarea.value += text;
+ }
+ }
+};
\ No newline at end of file
--- a/web/data/jquery.tablesorter.js Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/jquery.tablesorter.js Thu Jun 03 14:51:42 2010 +0200
@@ -705,10 +705,10 @@
ts.addParser({
id: "json",
is: function(s) {
- return s.startsWith('json:');
+ return s.startswith('json:');
},
format: function(s,table,cell) {
- return evalJSON(s.slice(5));
+ return cw.evalJSON(s.slice(5));
},
type: "text"
});
--- a/web/data/uiprops.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/data/uiprops.py Thu Jun 03 14:51:42 2010 +0200
@@ -12,6 +12,7 @@
JAVASCRIPTS = [data('jquery.js'),
data('jquery.corner.js'),
data('jquery.json.js'),
+ data('cubicweb.js'),
data('cubicweb.compat.js'),
data('cubicweb.python.js'),
data('cubicweb.htmlhelpers.js')]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/ajax_url0.html Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,3 @@
+<div id="ajaxroot">
+ <h1>Hello</h1>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/ajax_url1.html Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,6 @@
+<div id="ajaxroot">
+ <div class="ajaxHtmlHead">
+ <script src="http://foo.js" type="text/javascript"> </script>
+ </div>
+ <h1>Hello</h1>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/ajax_url2.html Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,7 @@
+<div id="ajaxroot">
+ <div class="ajaxHtmlHead">
+ <script src="http://foo.js" type="text/javascript"> </script>
+ <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+ </div>
+ <h1>Hello</h1>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/ajaxresult.json Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,1 @@
+['foo', 'bar']
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/qunit.css Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,119 @@
+
+ol#qunit-tests {
+ font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ margin:0;
+ padding:0;
+ list-style-position:inside;
+
+ font-size: smaller;
+}
+ol#qunit-tests li{
+ padding:0.4em 0.5em 0.4em 2.5em;
+ border-bottom:1px solid #fff;
+ font-size:small;
+ list-style-position:inside;
+}
+ol#qunit-tests li ol{
+ box-shadow: inset 0px 2px 13px #999;
+ -moz-box-shadow: inset 0px 2px 13px #999;
+ -webkit-box-shadow: inset 0px 2px 13px #999;
+ margin-top:0.5em;
+ margin-left:0;
+ padding:0.5em;
+ background-color:#fff;
+ border-radius:15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+}
+ol#qunit-tests li li{
+ border-bottom:none;
+ margin:0.5em;
+ background-color:#fff;
+ list-style-position: inside;
+ padding:0.4em 0.5em 0.4em 0.5em;
+}
+
+ol#qunit-tests li li.pass{
+ border-left:26px solid #C6E746;
+ background-color:#fff;
+ color:#5E740B;
+ }
+ol#qunit-tests li li.fail{
+ border-left:26px solid #EE5757;
+ background-color:#fff;
+ color:#710909;
+}
+ol#qunit-tests li.pass{
+ background-color:#D2E0E6;
+ color:#528CE0;
+}
+ol#qunit-tests li.fail{
+ background-color:#EE5757;
+ color:#000;
+}
+ol#qunit-tests li strong {
+ cursor:pointer;
+}
+h1#qunit-header{
+ background-color:#0d3349;
+ margin:0;
+ padding:0.5em 0 0.5em 1em;
+ color:#fff;
+ font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ border-top-right-radius:15px;
+ border-top-left-radius:15px;
+ -moz-border-radius-topright:15px;
+ -moz-border-radius-topleft:15px;
+ -webkit-border-top-right-radius:15px;
+ -webkit-border-top-left-radius:15px;
+ text-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px;
+}
+h2#qunit-banner{
+ font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ height:5px;
+ margin:0;
+ padding:0;
+}
+h2#qunit-banner.qunit-pass{
+ background-color:#C6E746;
+}
+h2#qunit-banner.qunit-fail, #qunit-testrunner-toolbar {
+ background-color:#EE5757;
+}
+#qunit-testrunner-toolbar {
+ font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ padding:0;
+ /*width:80%;*/
+ padding:0em 0 0.5em 2em;
+ font-size: small;
+}
+h2#qunit-userAgent {
+ font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ background-color:#2b81af;
+ margin:0;
+ padding:0;
+ color:#fff;
+ font-size: small;
+ padding:0.5em 0 0.5em 2.5em;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+p#qunit-testresult{
+ font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+ margin:0;
+ font-size: small;
+ color:#2b81af;
+ border-bottom-right-radius:15px;
+ border-bottom-left-radius:15px;
+ -moz-border-radius-bottomright:15px;
+ -moz-border-radius-bottomleft:15px;
+ -webkit-border-bottom-right-radius:15px;
+ -webkit-border-bottom-left-radius:15px;
+ background-color:#D2E0E6;
+ padding:0.5em 0.5em 0.5em 2.5em;
+}
+strong b.fail{
+ color:#710909;
+ }
+strong b.pass{
+ color:#5E740B;
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/qunit.js Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,1069 @@
+/*
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2009 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ */
+
+(function(window) {
+
+var QUnit = {
+
+ // Initialize the configuration options
+ init: function() {
+ config = {
+ stats: { all: 0, bad: 0 },
+ moduleStats: { all: 0, bad: 0 },
+ started: +new Date,
+ updateRate: 1000,
+ blocking: false,
+ autorun: false,
+ assertions: [],
+ filters: [],
+ queue: []
+ };
+
+ var tests = id("qunit-tests"),
+ banner = id("qunit-banner"),
+ result = id("qunit-testresult");
+
+ if ( tests ) {
+ tests.innerHTML = "";
+ }
+
+ if ( banner ) {
+ banner.className = "";
+ }
+
+ if ( result ) {
+ result.parentNode.removeChild( result );
+ }
+ },
+
+ // call on start of module test to prepend name to all tests
+ module: function(name, testEnvironment) {
+ config.currentModule = name;
+
+ synchronize(function() {
+ if ( config.currentModule ) {
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
+ }
+
+ config.currentModule = name;
+ config.moduleTestEnvironment = testEnvironment;
+ config.moduleStats = { all: 0, bad: 0 };
+
+ QUnit.moduleStart( name, testEnvironment );
+ });
+ },
+
+ asyncTest: function(testName, expected, callback) {
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = 0;
+ }
+
+ QUnit.test(testName, expected, callback, true);
+ },
+
+ test: function(testName, expected, callback, async) {
+ var name = testName, testEnvironment, testEnvironmentArg;
+
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+ // is 2nd argument a testEnvironment?
+ if ( expected && typeof expected === 'object') {
+ testEnvironmentArg = expected;
+ expected = null;
+ }
+
+ if ( config.currentModule ) {
+ name = config.currentModule + " module: " + name;
+ }
+
+ if ( !validTest(name) ) {
+ return;
+ }
+
+ synchronize(function() {
+ QUnit.testStart( testName );
+
+ testEnvironment = extend({
+ setup: function() {},
+ teardown: function() {}
+ }, config.moduleTestEnvironment);
+ if (testEnvironmentArg) {
+ extend(testEnvironment,testEnvironmentArg);
+ }
+
+ // allow utility functions to access the current test environment
+ QUnit.current_testEnvironment = testEnvironment;
+
+ config.assertions = [];
+ config.expected = expected;
+
+ try {
+ if ( !config.pollution ) {
+ saveGlobal();
+ }
+
+ testEnvironment.setup.call(testEnvironment);
+ } catch(e) {
+ QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
+ }
+
+ if ( async ) {
+ QUnit.stop();
+ }
+
+ try {
+ callback.call(testEnvironment);
+ } catch(e) {
+ fail("Test " + name + " died, exception and test follows", e, callback);
+ QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Restart the tests if they're blocking
+ if ( config.blocking ) {
+ start();
+ }
+ }
+ });
+
+ synchronize(function() {
+ try {
+ checkPollution();
+ testEnvironment.teardown.call(testEnvironment);
+ } catch(e) {
+ QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
+ }
+
+ try {
+ QUnit.reset();
+ } catch(e) {
+ fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
+ }
+
+ if ( config.expected && config.expected != config.assertions.length ) {
+ QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
+ }
+
+ var good = 0, bad = 0,
+ tests = id("qunit-tests");
+
+ config.stats.all += config.assertions.length;
+ config.moduleStats.all += config.assertions.length;
+
+ if ( tests ) {
+ var ol = document.createElement("ol");
+ ol.style.display = "none";
+
+ for ( var i = 0; i < config.assertions.length; i++ ) {
+ var assertion = config.assertions[i];
+
+ var li = document.createElement("li");
+ li.className = assertion.result ? "pass" : "fail";
+ li.appendChild(document.createTextNode(assertion.message || "(no message)"));
+ ol.appendChild( li );
+
+ if ( assertion.result ) {
+ good++;
+ } else {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+
+ var b = document.createElement("strong");
+ b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
+
+ addEvent(b, "click", function() {
+ var next = b.nextSibling, display = next.style.display;
+ next.style.display = display === "none" ? "block" : "none";
+ });
+
+ addEvent(b, "dblclick", function(e) {
+ var target = e && e.target ? e.target : window.event.srcElement;
+ if ( target.nodeName.toLowerCase() === "strong" ) {
+ var text = "", node = target.firstChild;
+
+ while ( node.nodeType === 3 ) {
+ text += node.nodeValue;
+ node = node.nextSibling;
+ }
+
+ text = text.replace(/(^\s*|\s*$)/g, "");
+
+ if ( window.location ) {
+ window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
+ }
+ }
+ });
+
+ var li = document.createElement("li");
+ li.className = bad ? "fail" : "pass";
+ li.appendChild( b );
+ li.appendChild( ol );
+ tests.appendChild( li );
+
+ if ( bad ) {
+ var toolbar = id("qunit-testrunner-toolbar");
+ if ( toolbar ) {
+ toolbar.style.display = "block";
+ id("qunit-filter-pass").disabled = null;
+ id("qunit-filter-missing").disabled = null;
+ }
+ }
+
+ } else {
+ for ( var i = 0; i < config.assertions.length; i++ ) {
+ if ( !config.assertions[i].result ) {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+ }
+
+ QUnit.testDone( testName, bad, config.assertions.length );
+
+ if ( !window.setTimeout && !config.queue.length ) {
+ done();
+ }
+ });
+
+ if ( window.setTimeout && !config.doneTimer ) {
+ config.doneTimer = window.setTimeout(function(){
+ if ( !config.queue.length ) {
+ done();
+ } else {
+ synchronize( done );
+ }
+ }, 13);
+ }
+ },
+
+ /**
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
+ */
+ expect: function(asserts) {
+ config.expected = asserts;
+ },
+
+ /**
+ * Asserts true.
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
+ */
+ ok: function(a, msg) {
+ QUnit.log(a, msg);
+
+ config.assertions.push({
+ result: !!a,
+ message: msg
+ });
+ },
+
+ /**
+ * Checks that the first two arguments are equal, with an optional message.
+ * Prints out both actual and expected values.
+ *
+ * Prefered to ok( actual == expected, message )
+ *
+ * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
+ *
+ * @param Object actual
+ * @param Object expected
+ * @param String message (optional)
+ */
+ equal: function(actual, expected, message) {
+ push(expected == actual, actual, expected, message);
+ },
+
+ notEqual: function(actual, expected, message) {
+ push(expected != actual, actual, expected, message);
+ },
+
+ deepEqual: function(a, b, message) {
+ push(QUnit.equiv(a, b), a, b, message);
+ },
+
+ notDeepEqual: function(a, b, message) {
+ push(!QUnit.equiv(a, b), a, b, message);
+ },
+
+ strictEqual: function(actual, expected, message) {
+ push(expected === actual, actual, expected, message);
+ },
+
+ notStrictEqual: function(actual, expected, message) {
+ push(expected !== actual, actual, expected, message);
+ },
+
+ start: function() {
+ // A slight delay, to avoid any current callbacks
+ if ( window.setTimeout ) {
+ window.setTimeout(function() {
+ if ( config.timeout ) {
+ clearTimeout(config.timeout);
+ }
+
+ config.blocking = false;
+ process();
+ }, 13);
+ } else {
+ config.blocking = false;
+ process();
+ }
+ },
+
+ stop: function(timeout) {
+ config.blocking = true;
+
+ if ( timeout && window.setTimeout ) {
+ config.timeout = window.setTimeout(function() {
+ QUnit.ok( false, "Test timed out" );
+ QUnit.start();
+ }, timeout);
+ }
+ },
+
+ /**
+ * Resets the test setup. Useful for tests that modify the DOM.
+ */
+ reset: function() {
+ if ( window.jQuery ) {
+ jQuery("#main").html( config.fixture );
+ jQuery.event.global = {};
+ jQuery.ajaxSettings = extend({}, config.ajaxSettings);
+ }
+ },
+
+ /**
+ * Trigger an event on an element.
+ *
+ * @example triggerEvent( document.body, "click" );
+ *
+ * @param DOMElement elem
+ * @param String type
+ */
+ triggerEvent: function( elem, type, event ) {
+ if ( document.createEvent ) {
+ event = document.createEvent("MouseEvents");
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ elem.dispatchEvent( event );
+
+ } else if ( elem.fireEvent ) {
+ elem.fireEvent("on"+type);
+ }
+ },
+
+ // Safe object type checking
+ is: function( type, obj ) {
+ return Object.prototype.toString.call( obj ) === "[object "+ type +"]";
+ },
+
+ // Logging callbacks
+ done: function(failures, total) {},
+ log: function(result, message) {},
+ testStart: function(name) {},
+ testDone: function(name, failures, total) {},
+ moduleStart: function(name, testEnvironment) {},
+ moduleDone: function(name, failures, total) {}
+};
+
+// Backwards compatibility, deprecated
+QUnit.equals = QUnit.equal;
+QUnit.same = QUnit.deepEqual;
+
+// Maintain internal state
+var config = {
+ // The queue of tests to run
+ queue: [],
+
+ // block until document ready
+ blocking: true
+};
+
+// Load paramaters
+(function() {
+ var location = window.location || { search: "", protocol: "file:" },
+ GETParams = location.search.slice(1).split('&');
+
+ for ( var i = 0; i < GETParams.length; i++ ) {
+ GETParams[i] = decodeURIComponent( GETParams[i] );
+ if ( GETParams[i] === "noglobals" ) {
+ GETParams.splice( i, 1 );
+ i--;
+ config.noglobals = true;
+ } else if ( GETParams[i].search('=') > -1 ) {
+ GETParams.splice( i, 1 );
+ i--;
+ }
+ }
+
+ // restrict modules/tests by get parameters
+ config.filters = GETParams;
+
+ // Figure out if we're running the tests from a server or not
+ QUnit.isLocal = !!(location.protocol === 'file:');
+})();
+
+// Expose the API as global variables, unless an 'exports'
+// object exists, in that case we assume we're in CommonJS
+if ( typeof exports === "undefined" || typeof require === "undefined" ) {
+ extend(window, QUnit);
+ window.QUnit = QUnit;
+} else {
+ extend(exports, QUnit);
+ exports.QUnit = QUnit;
+}
+
+if ( typeof document === "undefined" || document.readyState === "complete" ) {
+ config.autorun = true;
+}
+
+addEvent(window, "load", function() {
+ // Initialize the config, saving the execution queue
+ var oldconfig = extend({}, config);
+ QUnit.init();
+ extend(config, oldconfig);
+
+ config.blocking = false;
+
+ var userAgent = id("qunit-userAgent");
+ if ( userAgent ) {
+ userAgent.innerHTML = navigator.userAgent;
+ }
+
+ var toolbar = id("qunit-testrunner-toolbar");
+ if ( toolbar ) {
+ toolbar.style.display = "none";
+
+ var filter = document.createElement("input");
+ filter.type = "checkbox";
+ filter.id = "qunit-filter-pass";
+ filter.disabled = true;
+ addEvent( filter, "click", function() {
+ var li = document.getElementsByTagName("li");
+ for ( var i = 0; i < li.length; i++ ) {
+ if ( li[i].className.indexOf("pass") > -1 ) {
+ li[i].style.display = filter.checked ? "none" : "";
+ }
+ }
+ });
+ toolbar.appendChild( filter );
+
+ var label = document.createElement("label");
+ label.setAttribute("for", "qunit-filter-pass");
+ label.innerHTML = "Hide passed tests";
+ toolbar.appendChild( label );
+
+ var missing = document.createElement("input");
+ missing.type = "checkbox";
+ missing.id = "qunit-filter-missing";
+ missing.disabled = true;
+ addEvent( missing, "click", function() {
+ var li = document.getElementsByTagName("li");
+ for ( var i = 0; i < li.length; i++ ) {
+ if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
+ li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
+ }
+ }
+ });
+ toolbar.appendChild( missing );
+
+ label = document.createElement("label");
+ label.setAttribute("for", "qunit-filter-missing");
+ label.innerHTML = "Hide missing tests (untested code is broken code)";
+ toolbar.appendChild( label );
+ }
+
+ var main = id('main');
+ if ( main ) {
+ config.fixture = main.innerHTML;
+ }
+
+ if ( window.jQuery ) {
+ config.ajaxSettings = window.jQuery.ajaxSettings;
+ }
+
+ QUnit.start();
+});
+
+function done() {
+ if ( config.doneTimer && window.clearTimeout ) {
+ window.clearTimeout( config.doneTimer );
+ config.doneTimer = null;
+ }
+
+ if ( config.queue.length ) {
+ config.doneTimer = window.setTimeout(function(){
+ if ( !config.queue.length ) {
+ done();
+ } else {
+ synchronize( done );
+ }
+ }, 13);
+
+ return;
+ }
+
+ config.autorun = true;
+
+ // Log the last module results
+ if ( config.currentModule ) {
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
+ }
+
+ var banner = id("qunit-banner"),
+ tests = id("qunit-tests"),
+ html = ['Tests completed in ',
+ +new Date - config.started, ' milliseconds.<br/>',
+ '<span class="passed">', config.stats.all - config.stats.bad, '</span> tests of <span class="total">', config.stats.all, '</span> passed, <span class="failed">', config.stats.bad,'</span> failed.'].join('');
+
+ if ( banner ) {
+ banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
+ }
+
+ if ( tests ) {
+ var result = id("qunit-testresult");
+
+ if ( !result ) {
+ result = document.createElement("p");
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore( result, tests.nextSibling );
+ }
+
+ result.innerHTML = html;
+ }
+
+ QUnit.done( config.stats.bad, config.stats.all );
+}
+
+function validTest( name ) {
+ var i = config.filters.length,
+ run = false;
+
+ if ( !i ) {
+ return true;
+ }
+
+ while ( i-- ) {
+ var filter = config.filters[i],
+ not = filter.charAt(0) == '!';
+
+ if ( not ) {
+ filter = filter.slice(1);
+ }
+
+ if ( name.indexOf(filter) !== -1 ) {
+ return !not;
+ }
+
+ if ( not ) {
+ run = true;
+ }
+ }
+
+ return run;
+}
+
+function push(result, actual, expected, message) {
+ message = message || (result ? "okay" : "failed");
+ QUnit.ok( result, result ? message + ": " + QUnit.jsDump.parse(expected) : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
+}
+
+function synchronize( callback ) {
+ config.queue.push( callback );
+
+ if ( config.autorun && !config.blocking ) {
+ process();
+ }
+}
+
+function process() {
+ var start = (new Date()).getTime();
+
+ while ( config.queue.length && !config.blocking ) {
+ if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
+ config.queue.shift()();
+
+ } else {
+ setTimeout( process, 13 );
+ break;
+ }
+ }
+}
+
+function saveGlobal() {
+ config.pollution = [];
+
+ if ( config.noglobals ) {
+ for ( var key in window ) {
+ config.pollution.push( key );
+ }
+ }
+}
+
+function checkPollution( name ) {
+ var old = config.pollution;
+ saveGlobal();
+
+ var newGlobals = diff( old, config.pollution );
+ if ( newGlobals.length > 0 ) {
+ ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
+ config.expected++;
+ }
+
+ var deletedGlobals = diff( config.pollution, old );
+ if ( deletedGlobals.length > 0 ) {
+ ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
+ config.expected++;
+ }
+}
+
+// returns a new Array with the elements that are in a but not in b
+function diff( a, b ) {
+ var result = a.slice();
+ for ( var i = 0; i < result.length; i++ ) {
+ for ( var j = 0; j < b.length; j++ ) {
+ if ( result[i] === b[j] ) {
+ result.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+function fail(message, exception, callback) {
+ if ( typeof console !== "undefined" && console.error && console.warn ) {
+ console.error(message);
+ console.error(exception);
+ console.warn(callback.toString());
+
+ } else if ( window.opera && opera.postError ) {
+ opera.postError(message, exception, callback.toString);
+ }
+}
+
+function extend(a, b) {
+ for ( var prop in b ) {
+ a[prop] = b[prop];
+ }
+
+ return a;
+}
+
+function addEvent(elem, type, fn) {
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, fn, false );
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, fn );
+ } else {
+ fn();
+ }
+}
+
+function id(name) {
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
+ document.getElementById( name );
+}
+
+// Test for equality any JavaScript type.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+QUnit.equiv = function () {
+
+ var innerEquiv; // the real equiv function
+ var callers = []; // stack to decide between skip/abort functions
+ var parents = []; // stack to avoiding loops from circular referencing
+
+
+ // Determine what is o.
+ function hoozit(o) {
+ if (QUnit.is("String", o)) {
+ return "string";
+
+ } else if (QUnit.is("Boolean", o)) {
+ return "boolean";
+
+ } else if (QUnit.is("Number", o)) {
+
+ if (isNaN(o)) {
+ return "nan";
+ } else {
+ return "number";
+ }
+
+ } else if (typeof o === "undefined") {
+ return "undefined";
+
+ // consider: typeof null === object
+ } else if (o === null) {
+ return "null";
+
+ // consider: typeof [] === object
+ } else if (QUnit.is( "Array", o)) {
+ return "array";
+
+ // consider: typeof new Date() === object
+ } else if (QUnit.is( "Date", o)) {
+ return "date";
+
+ // consider: /./ instanceof Object;
+ // /./ instanceof RegExp;
+ // typeof /./ === "function"; // => false in IE and Opera,
+ // true in FF and Safari
+ } else if (QUnit.is( "RegExp", o)) {
+ return "regexp";
+
+ } else if (typeof o === "object") {
+ return "object";
+
+ } else if (QUnit.is( "Function", o)) {
+ return "function";
+ } else {
+ return undefined;
+ }
+ }
+
+ // Call the o related callback with the given arguments.
+ function bindCallbacks(o, callbacks, args) {
+ var prop = hoozit(o);
+ if (prop) {
+ if (hoozit(callbacks[prop]) === "function") {
+ return callbacks[prop].apply(callbacks, args);
+ } else {
+ return callbacks[prop]; // or undefined
+ }
+ }
+ }
+
+ var callbacks = function () {
+
+ // for string, boolean, number and null
+ function useStrictEquality(b, a) {
+ if (b instanceof a.constructor || a instanceof b.constructor) {
+ // to catch short annotaion VS 'new' annotation of a declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+
+ "nan": function (b) {
+ return isNaN(b);
+ },
+
+ "date": function (b, a) {
+ return hoozit(b) === "date" && a.valueOf() === b.valueOf();
+ },
+
+ "regexp": function (b, a) {
+ return hoozit(b) === "regexp" &&
+ a.source === b.source && // the regex itself
+ a.global === b.global && // and its modifers (gmi) ...
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function": function () {
+ var caller = callers[callers.length - 1];
+ return caller !== Object &&
+ typeof caller !== "undefined";
+ },
+
+ "array": function (b, a) {
+ var i, j, loop;
+ var len;
+
+ // b could be an object literal here
+ if ( ! (hoozit(b) === "array")) {
+ return false;
+ }
+
+ len = a.length;
+ if (len !== b.length) { // safe and faster
+ return false;
+ }
+
+ //track reference to avoid circular references
+ parents.push(a);
+ for (i = 0; i < len; i++) {
+ loop = false;
+ for(j=0;j<parents.length;j++){
+ if(parents[j] === a[i]){
+ loop = true;//dont rewalk array
+ }
+ }
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ parents.pop();
+ return false;
+ }
+ }
+ parents.pop();
+ return true;
+ },
+
+ "object": function (b, a) {
+ var i, j, loop;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of strings
+
+ // comparing constructors is more strict than using instanceof
+ if ( a.constructor !== b.constructor) {
+ return false;
+ }
+
+ // stack constructor before traversing properties
+ callers.push(a.constructor);
+ //track reference to avoid circular references
+ parents.push(a);
+
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
+ loop = false;
+ for(j=0;j<parents.length;j++){
+ if(parents[j] === a[i])
+ loop = true; //don't go down the same path twice
+ }
+ aProperties.push(i); // collect a's properties
+
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ eq = false;
+ break;
+ }
+ }
+
+ callers.pop(); // unstack, we are done
+ parents.pop();
+
+ for (i in b) {
+ bProperties.push(i); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
+ }
+ };
+ }();
+
+ innerEquiv = function () { // can take multiple arguments
+ var args = Array.prototype.slice.apply(arguments);
+ if (args.length < 2) {
+ return true; // end transition
+ }
+
+ return (function (a, b) {
+ if (a === b) {
+ return true; // catch the most you can
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
+ return false; // don't lose time with error prone cases
+ } else {
+ return bindCallbacks(a, callbacks, [b, a]);
+ }
+
+ // apply transition with (1..n) arguments
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
+ };
+
+ return innerEquiv;
+
+}();
+
+/**
+ * jsDump
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
+ * Date: 5/15/2008
+ * @projectDescription Advanced and extensible data dumping for Javascript.
+ * @version 1.0.0
+ * @author Ariel Flesler
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
+ */
+QUnit.jsDump = (function() {
+ function quote( str ) {
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
+ };
+ function literal( o ) {
+ return o + '';
+ };
+ function join( pre, arr, post ) {
+ var s = jsDump.separator(),
+ base = jsDump.indent(),
+ inner = jsDump.indent(1);
+ if ( arr.join )
+ arr = arr.join( ',' + s + inner );
+ if ( !arr )
+ return pre + post;
+ return [ pre, inner + arr, base + post ].join(s);
+ };
+ function array( arr ) {
+ var i = arr.length, ret = Array(i);
+ this.up();
+ while ( i-- )
+ ret[i] = this.parse( arr[i] );
+ this.down();
+ return join( '[', ret, ']' );
+ };
+
+ var reName = /^function (\w+)/;
+
+ var jsDump = {
+ parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
+ var parser = this.parsers[ type || this.typeOf(obj) ];
+ type = typeof parser;
+
+ return type == 'function' ? parser.call( this, obj ) :
+ type == 'string' ? parser :
+ this.parsers.error;
+ },
+ typeOf:function( obj ) {
+ var type;
+ if ( obj === null ) {
+ type = "null";
+ } else if (typeof obj === "undefined") {
+ type = "undefined";
+ } else if (QUnit.is("RegExp", obj)) {
+ type = "regexp";
+ } else if (QUnit.is("Date", obj)) {
+ type = "date";
+ } else if (QUnit.is("Function", obj)) {
+ type = "function";
+ } else if (obj.setInterval && obj.document && !obj.nodeType) {
+ type = "window";
+ } else if (obj.nodeType === 9) {
+ type = "document";
+ } else if (obj.nodeType) {
+ type = "node";
+ } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
+ type = "array";
+ } else {
+ type = typeof obj;
+ }
+ return type;
+ },
+ separator:function() {
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? ' ' : ' ';
+ },
+ indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
+ if ( !this.multiline )
+ return '';
+ var chr = this.indentChar;
+ if ( this.HTML )
+ chr = chr.replace(/\t/g,' ').replace(/ /g,' ');
+ return Array( this._depth_ + (extra||0) ).join(chr);
+ },
+ up:function( a ) {
+ this._depth_ += a || 1;
+ },
+ down:function( a ) {
+ this._depth_ -= a || 1;
+ },
+ setParser:function( name, parser ) {
+ this.parsers[name] = parser;
+ },
+ // The next 3 are exposed so you can use them
+ quote:quote,
+ literal:literal,
+ join:join,
+ //
+ _depth_: 1,
+ // This is the list of parsers, to modify them, use jsDump.setParser
+ parsers:{
+ window: '[Window]',
+ document: '[Document]',
+ error:'[ERROR]', //when no parser is found, shouldn't happen
+ unknown: '[Unknown]',
+ 'null':'null',
+ undefined:'undefined',
+ 'function':function( fn ) {
+ var ret = 'function',
+ name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
+ if ( name )
+ ret += ' ' + name;
+ ret += '(';
+
+ ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
+ return join( ret, this.parse(fn,'functionCode'), '}' );
+ },
+ array: array,
+ nodelist: array,
+ arguments: array,
+ object:function( map ) {
+ var ret = [ ];
+ this.up();
+ for ( var key in map )
+ ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
+ this.down();
+ return join( '{', ret, '}' );
+ },
+ node:function( node ) {
+ var open = this.HTML ? '<' : '<',
+ close = this.HTML ? '>' : '>';
+
+ var tag = node.nodeName.toLowerCase(),
+ ret = open + tag;
+
+ for ( var a in this.DOMAttrs ) {
+ var val = node[this.DOMAttrs[a]];
+ if ( val )
+ ret += ' ' + a + '=' + this.parse( val, 'attribute' );
+ }
+ return ret + close + open + '/' + tag + close;
+ },
+ functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
+ var l = fn.length;
+ if ( !l ) return '';
+
+ var args = Array(l);
+ while ( l-- )
+ args[l] = String.fromCharCode(97+l);//97 is 'a'
+ return ' ' + args.join(', ') + ' ';
+ },
+ key:quote, //object calls it internally, the key part of an item in a map
+ functionCode:'[code]', //function calls it internally, it's the content of the function
+ attribute:quote, //node calls it internally, it's an html attribute value
+ string:quote,
+ date:quote,
+ regexp:literal, //regex
+ number:literal,
+ 'boolean':literal
+ },
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
+ id:'id',
+ name:'name',
+ 'class':'className'
+ },
+ HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
+ indentChar:' ',//indentation unit
+ multiline:false //if true, items in a collection, are separated by a \n, else just a space.
+ };
+
+ return jsDump;
+})();
+
+})(this);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/test_ajax.html Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <!-- dependencies -->
+ <script type="text/javascript" src="../../data/jquery.js"></script>
+ <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.dom.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.ajax.js" type="text/javascript"></script>
+ <!-- qunit files -->
+ <script type="text/javascript" src="qunit.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+ <!-- test suite -->
+ <script src="test_ajax.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="main"> </div>
+ <h1 id="qunit-header">CubicWeb Ajax Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <ol id="qunit-tests">
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/test_ajax.js Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,222 @@
+$(document).ready(function() {
+
+ function jsSources() {
+ return $.map($('head script[src]'), function(script) {
+ return script.getAttribute('src');
+ });
+ }
+
+ test('test simple h1 inclusion (ajax_url0.html)', function() {
+ expect(3);
+ equals(jQuery('#main').children().length, 0);
+ stop();
+ jQuery('#main').loadxhtml('/../ajax_url0.html', {
+ callback: function() {
+ equals(jQuery('#main').children().length, 1);
+ equals(jQuery('#main h1').html(), 'Hello');
+ start();
+ }
+ });
+ });
+
+ test('test simple html head inclusion (ajax_url1.html)', function() {
+ expect(6);
+ var scriptsIncluded = jsSources();
+ equals(jQuery.inArray('http://foo.js', scriptsIncluded), - 1);
+ stop();
+ jQuery('#main').loadxhtml('/../ajax_url1.html', {
+ callback: function() {
+ var origLength = scriptsIncluded.length;
+ scriptsIncluded = jsSources();
+ // check that foo.js has been inserted in <head>
+ equals(scriptsIncluded.length, origLength + 1);
+ equals(scriptsIncluded[origLength].indexOf('http://foo.js'), 0);
+ // check that <div class="ajaxHtmlHead"> has been removed
+ equals(jQuery('#main').children().length, 1);
+ equals(jQuery('div.ajaxHtmlHead').length, 0);
+ equals(jQuery('#main h1').html(), 'Hello');
+ start();
+ }
+ });
+ });
+
+ test('test addCallback', function() {
+ expect(3);
+ equals(jQuery('#main').children().length, 0);
+ stop();
+ var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
+ d.addCallback(function() {
+ equals(jQuery('#main').children().length, 1);
+ equals(jQuery('#main h1').html(), 'Hello');
+ start();
+ });
+ });
+
+ test('test callback after synchronous request', function() {
+ expect(1);
+ var deferred = new Deferred();
+ var result = jQuery.ajax({
+ url: './ajax_url0.html',
+ async: false,
+ beforeSend: function(xhr) {
+ deferred._req = xhr;
+ },
+ success: function(data, status) {
+ deferred.success(data);
+ }
+ });
+ stop();
+ deferred.addCallback(function() {
+ // add an assertion to ensure the callback is executed
+ ok(true, "callback is executed");
+ start();
+ });
+ });
+
+ test('test addCallback with parameters', function() {
+ expect(3);
+ equals(jQuery('#main').children().length, 0);
+ stop();
+ var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
+ d.addCallback(function(data, req, arg1, arg2) {
+ equals(arg1, 'Hello');
+ equals(arg2, 'world');
+ start();
+ },
+ 'Hello', 'world');
+ });
+
+ test('test callback after synchronous request with parameters', function() {
+ var deferred = new Deferred();
+ var result = jQuery.ajax({
+ url: './ajax_url0.html',
+ async: false,
+ beforeSend: function(xhr) {
+ deferred._req = xhr;
+ },
+ success: function(data, status) {
+ deferred.success(data);
+ }
+ });
+ deferred.addCallback(function(data, req, arg1, arg2) {
+ // add an assertion to ensure the callback is executed
+ ok(true, "callback is executed");
+ equals(arg1, 'Hello');
+ equals(arg2, 'world');
+ },
+ 'Hello', 'world');
+ });
+
+ test('test addErrback', function() {
+ expect(1);
+ stop();
+ var d = jQuery('#main').loadxhtml('/../ajax_url0.html');
+ d.addCallback(function() {
+ // throw an exception to start errback chain
+ throw new Error();
+ });
+ d.addErrback(function() {
+ ok(true, "errback is executed");
+ start();
+ });
+ });
+
+ test('test callback / errback execution order', function() {
+ expect(4);
+ var counter = 0;
+ stop();
+ var d = jQuery('#main').loadxhtml('/../ajax_url0.html', {
+ callback: function() {
+ equals(++counter, 1); // should be executed first
+ start();
+ }
+ });
+ d.addCallback(function() {
+ equals(++counter, 2); // should be executed and break callback chain
+ throw new Error();
+ });
+ d.addCallback(function() {
+ // should not be executed since second callback raised an error
+ ok(false, "callback is executed");
+ });
+ d.addErrback(function() {
+ // should be executed after the second callback
+ equals(++counter, 3);
+ });
+ d.addErrback(function() {
+ // should be executed after the first errback
+ equals(++counter, 4);
+ });
+ });
+
+ test('test already included resources are ignored (ajax_url2.html)', function() {
+ expect(10);
+ var scriptsIncluded = jsSources();
+ equals(jQuery.inArray('http://foo.js', scriptsIncluded), - 1);
+ equals(jQuery('head link').length, 1);
+ equals(jQuery('head link').attr('href'), 'qunit.css');
+ stop();
+ jQuery('#main').loadxhtml('/../ajax_url1.html', {
+ callback: function() {
+ var origLength = scriptsIncluded.length;
+ scriptsIncluded = jsSources();
+ // check that foo.js has been inserted in <head>
+ equals(scriptsIncluded.length, origLength + 1);
+ equals(scriptsIncluded[origLength].indexOf('http://foo.js'), 0);
+ // check that <div class="ajaxHtmlHead"> has been removed
+ equals(jQuery('#main').children().length, 1);
+ equals(jQuery('div.ajaxHtmlHead').length, 0);
+ equals(jQuery('#main h1').html(), 'Hello');
+ // qunit.css is not added twice
+ equals(jQuery('head link').length, 1);
+ equals(jQuery('head link').attr('href'), 'qunit.css');
+ start();
+ }
+ });
+ });
+
+ test('test synchronous request loadRemote', function() {
+ var res = loadRemote('/../ajaxresult.json', {},
+ 'GET', true);
+ same(res, ['foo', 'bar']);
+ });
+
+ test('test event on CubicWeb', function() {
+ expect(1);
+ stop();
+ var events = null;
+ jQuery(CubicWeb).bind('server-response', function() {
+ // check that server-response event on CubicWeb is triggered
+ events = 'CubicWeb';
+ });
+ jQuery('#main').loadxhtml('/../ajax_url0.html', {
+ callback: function() {
+ equals(events, 'CubicWeb');
+ start();
+ }
+ });
+ });
+
+ test('test event on node', function() {
+ expect(3);
+ stop();
+ var nodes = [];
+ jQuery('#main').bind('server-response', function() {
+ nodes.push('node');
+ });
+ jQuery(CubicWeb).bind('server-response', function() {
+ nodes.push('CubicWeb');
+ });
+ jQuery('#main').loadxhtml('/../ajax_url0.html', {
+ callback: function() {
+ equals(nodes.length, 2);
+ // check that server-response event on CubicWeb is triggered
+ // only once and event server-response on node is triggered
+ equals(nodes[0], 'CubicWeb');
+ equals(nodes[1], 'node');
+ start();
+ }
+ });
+ });
+});
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/test_datetime.html Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <script type="text/javascript" src="../../data/jquery.js"></script>
+ <script src="../../data/cubicweb.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+ <script type="text/javascript" src="qunit.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+ <script src="test_datetime.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="main">
+ </div>
+ <h1 id="qunit-header">QUnit example</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests">
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/test_datetime.js Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,20 @@
+$(document).ready(function() {
+
+ module("datetime tests");
+
+ test("test full datetime", function() {
+ equals(cw.utils.toISOTimestamp(new Date(1986, 3, 18, 10, 30, 0, 0)),
+ '1986-04-18 10:30:00');
+ });
+
+ test("test only date", function() {
+ equals(cw.utils.toISOTimestamp(new Date(1986, 3, 18)), '1986-04-18 00:00:00');
+ });
+
+ test("test null", function() {
+ equals(cw.utils.toISOTimestamp(null), null);
+ });
+
+
+});
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/test_htmlhelpers.html Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,20 @@
+<html>
+ <head>
+ <script type="text/javascript" src="../../data/jquery.js"></script>
+ <script src="../../data/cubicweb.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
+ <script type="text/javascript" src="qunit.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
+ <script src="test_htmlhelpers.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="main">
+ </div>
+ <h1 id="qunit-header">QUnit example</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests">
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/jstests/test_htmlhelpers.js Thu Jun 03 14:51:42 2010 +0200
@@ -0,0 +1,36 @@
+$(document).ready(function() {
+
+ module("module2", {
+ setup: function() {
+ $('#main').append('<select id="theselect" multiple="multiple" size="2">' +
+ '</select>');
+ }
+ });
+
+ test("test first selected", function() {
+ $('#theselect').append('<option value="foo">foo</option>' +
+ '<option selected="selected" value="bar">bar</option>' +
+ '<option value="baz">baz</option>' +
+ '<option selected="selecetd"value="spam">spam</option>');
+ var selected = firstSelected(document.getElementById("theselect"));
+ equals(selected.value, 'bar');
+ });
+
+ test("test first selected 2", function() {
+ $('#theselect').append('<option value="foo">foo</option>' +
+ '<option value="bar">bar</option>' +
+ '<option value="baz">baz</option>' +
+ '<option value="spam">spam</option>');
+ var selected = firstSelected(document.getElementById("theselect"));
+ equals(selected, null);
+ });
+
+ module("visibilty");
+ test('toggleVisibility', function() {
+ $('#main').append('<div id="foo"></div>');
+ toggleVisibility('foo');
+ ok($('#foo').hasClass('hidden'), 'check hidden class is set');
+ });
+
+});
+
--- a/web/views/basecontrollers.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/views/basecontrollers.py Thu Jun 03 14:51:42 2010 +0200
@@ -262,6 +262,12 @@
self._cw.encoding)
return self.response(domid, status, args, entity)
+def optional_kwargs(extraargs):
+ if extraargs is None:
+ return {}
+ else: # we receive unicode keys which is not supported by the **syntax
+ return dict((str(key), value)
+ for key, value in extraargs.items())
class JSonController(Controller):
__regid__ = 'json'
@@ -421,6 +427,18 @@
# raise RemoteCallFailed('unselectable')
return self._call_view(comp, **extraargs)
+ @xhtmlize
+ def js_render(self, registry, oid, eid=None, selectargs=None, renderargs=None):
+ if eid is not None:
+ rset = self._cw.eid_rset(eid)
+ elif 'rql' in self._cw.form:
+ rset = self._cw.execute(self._cw.form['rql'])
+ else:
+ rset = None
+ selectargs = optional_kwargs(selectargs)
+ view = self._cw.vreg[registry].select(oid, self._cw, rset=rset, **selectargs)
+ return self._call_view(view, **optional_kwargs(renderargs))
+
@check_pageid
@xhtmlize
def js_inline_creation_form(self, peid, petype, ttype, rtype, role, i18nctx):
@@ -440,13 +458,13 @@
@xhtmlize
def js_reledit_form(self):
req = self._cw
- args = dict((x, self._cw.form[x])
+ args = dict((x, req.form[x])
for x in frozenset(('rtype', 'role', 'reload', 'landing_zone')))
- entity = self._cw.entity_from_eid(int(self._cw.form['eid']))
+ entity = req.entity_from_eid(typed_eid(req.form['eid']))
# note: default is reserved in js land
- args['default'] = self._cw.form['default_value']
+ args['default'] = req.form['default_value']
args['reload'] = json.loads(args['reload'])
- rset = req.eid_rset(int(self._cw.form['eid']))
+ rset = req.eid_rset(typed_eid(req.form['eid']))
view = req.vreg['views'].select('doreledit', req, rset=rset, rtype=args['rtype'])
return self._call_view(view, **args)
--- a/web/views/bookmark.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/views/bookmark.py Thu Jun 03 14:51:42 2010 +0200
@@ -96,7 +96,7 @@
eschema = self._cw.vreg.schema.eschema(self.etype)
candelete = rschema.has_perm(req, 'delete', toeid=ueid)
if candelete:
- req.add_js( ('cubicweb.ajax.js', 'cubicweb.bookmarks.js') )
+ req.add_js('cubicweb.ajax.js')
else:
dlink = None
for bookmark in rset.entities():
--- a/web/views/editforms.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/views/editforms.py Thu Jun 03 14:51:42 2010 +0200
@@ -283,8 +283,8 @@
# FIXME editableField class could be toggleable from userprefs
_onclick = u"showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')"
- _onsubmit = ("return inlineValidateRelationForm('%(rtype)s', '%(role)s', '%(eid)s', "
- "'%(divid)s', %(reload)s, '%(vid)s', '%(default)s', '%(lzone)s');")
+ _onsubmit = ("return inlineValidateRelationFormOptions('%(rtype)s', '%(eid)s', "
+ "'%(divid)s', %(options)s);")
_cancelclick = "hideInlineEdit(%s,\'%s\',\'%s\')"
_defaultlandingzone = (u'<img title="%(msg)s" src="data/pen_icon.png" '
'alt="%(msg)s"/>')
@@ -406,9 +406,11 @@
def _build_args(self, entity, rtype, role, formid, default, reload, lzone,
extradata=None):
divid = '%s-%s-%s' % (rtype, role, entity.eid)
+ options = {'reload' : reload, 'default_value' : default,
+ 'role' : role, 'vid' : '',
+ 'lzone' : lzone}
event_args = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype,
- 'reload' : dumps(reload), 'default' : default, 'role' : role, 'vid' : u'',
- 'lzone' : lzone}
+ 'options' : dumps(options)}
if extradata:
event_args.update(extradata)
return divid, event_args
@@ -416,7 +418,7 @@
def _build_form(self, entity, rtype, role, formid, default, reload, lzone,
extradata=None, **formargs):
divid, event_args = self._build_args(entity, rtype, role, formid, default,
- reload, lzone, extradata)
+ reload, lzone, extradata)
onsubmit = self._onsubmit % event_args
cancelclick = self._cancelclick % (entity.eid, rtype, divid)
form = self._cw.vreg['forms'].select(
@@ -434,8 +436,8 @@
by checking uicfg configuration and composite relation property.
"""
__regid__ = 'reledit'
- _onclick = (u"loadInlineEditionForm(%(eid)s, '%(rtype)s', '%(role)s', "
- "'%(divid)s', %(reload)s, '%(vid)s', '%(default)s', '%(lzone)s');")
+ _onclick = (u"loadInlineEditionFormOptions(%(eid)s, '%(rtype)s', "
+ "'%(divid)s', %(options)s);")
def should_edit_relation(self, entity, rschema, role, rvid):
eschema = entity.e_schema
--- a/web/views/formrenderers.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/views/formrenderers.py Thu Jun 03 14:51:42 2010 +0200
@@ -342,7 +342,7 @@
w(u'<th align="left">%s</th>' %
tags.input(type='checkbox',
title=self._cw._('toggle check boxes'),
- onclick="setCheckboxesState('eid', this.checked)"))
+ onclick="setCheckboxesState('eid', null, this.checked)"))
for field in subfields:
w(u'<th>%s</th>' % field_label(form, field))
w(u'</tr>')
@@ -358,7 +358,7 @@
entity = form.edited_entity
values = form.form_previous_values
qeid = eid_param('eid', entity.eid)
- cbsetstate = "setCheckboxesState2('eid', %s, 'checked')" % \
+ cbsetstate = "setCheckboxesState('eid', %s, 'checked')" % \
xml_escape(dumps(entity.eid))
w(u'<tr class="%s">' % (entity.cw_row % 2 and u'even' or u'odd'))
# XXX turn this into a widget used on the eid field
--- a/web/views/massmailing.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/views/massmailing.py Thu Jun 03 14:51:42 2010 +0200
@@ -57,7 +57,7 @@
class MassMailingForm(forms.FieldsForm):
__regid__ = 'massmailing'
- needs_js = ('cubicweb.widgets.js', 'cubicweb.massmailing.js')
+ needs_js = ('cubicweb.widgets.js',)
needs_css = ('cubicweb.mailform.css')
domid = 'sendmail'
action = 'sendmail'
@@ -94,7 +94,7 @@
return sorted(reduce(operator.and_, attrs))
def build_substitutions_help(self):
- insertLink = u'<a href="javascript: insertText(\'%%(%s)s\', \'emailarea\');">%%(%s)s</a>'
+ insertLink = u'<a href="javascript: cw.widgets.insertText(\'%%(%s)s\', \'emailarea\');">%%(%s)s</a>'
substs = (u'<div class="substitution">%s</div>' % (insertLink % (subst, subst))
for subst in self.get_allowed_substitutions())
helpmsg = self._cw._('You can use any of the following substitutions in your text')
--- a/web/webconfig.py Thu Jun 03 10:17:44 2010 +0200
+++ b/web/webconfig.py Thu Jun 03 14:51:42 2010 +0200
@@ -346,14 +346,17 @@
for path in reversed([self.apphome] + self.cubes_path()):
self._load_ui_properties_file(uiprops, path)
self._load_ui_properties_file(uiprops, self.apphome)
+ datadir_url = uiprops.context['datadir_url']
# XXX pre 3.9 css compat
if self['use-old-css']:
- datadir_url = uiprops.context['datadir_url']
if (datadir_url+'/cubicweb.css') in uiprops['STYLESHEETS']:
idx = uiprops['STYLESHEETS'].index(datadir_url+'/cubicweb.css')
uiprops['STYLESHEETS'][idx] = datadir_url+'/cubicweb.old.css'
if datadir_url+'/cubicweb.reset.css' in uiprops['STYLESHEETS']:
uiprops['STYLESHEETS'].remove(datadir_url+'/cubicweb.reset.css')
+ cubicweb_js_url = datadir_url + '/cubicweb.js'
+ if cubicweb_js_url not in uiprops['JAVASCRIPTS']:
+ uiprops['JAVASCRIPTS'].insert(0, cubicweb_js_url)
def _load_ui_properties_file(self, uiprops, path):
resourcesfile = join(path, 'data', 'external_resources')