# HG changeset patch # User Adrien Di Mascio # Date 1275569502 -7200 # Node ID 7b9553a9db6543c6db35ec4168d6bc38b88c3a3a # Parent ef903fff826d9160f7fb4fb57760026cd7ee2dee [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) diff -r ef903fff826d -r 7b9553a9db65 web/data/cubicweb.ajax.js --- 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 . */ 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
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'; + 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 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; + } +); + diff -r ef903fff826d -r 7b9553a9db65 web/data/cubicweb.bookmarks.js --- 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")); - }); -} diff -r ef903fff826d -r 7b9553a9db65 web/data/cubicweb.calendar.js --- 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>")))), - 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'); + diff -r ef903fff826d -r 7b9553a9db65 web/data/cubicweb.compat.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>> 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>> 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('