diff -r 00b1b6b906cf -r 97c55baefa0c web/data/cubicweb.edition.js --- a/web/data/cubicweb.edition.js Thu Jul 15 12:03:13 2010 +0200 +++ b/web/data/cubicweb.edition.js Mon Jul 19 15:37:02 2010 +0200 @@ -1,255 +1,317 @@ -/* +/** + * 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([key, varname, tabindex], jQuery.toJSON) + }; + cw.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 form = cw.getNode(formid || 'entityForm'); var inputTypes = ['INPUT', 'SELECT', 'TEXTAREA']; - var tabindex = (start==null)?15:start; - nodeWalkDepthFirst(form, function(elem) { + var tabindex = (start == null) ? 15: start; + cw.utils.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 ($.inArray(tagName, inputTypes)) { + 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 = cw.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'); var oid = optionNode.id.substring(2); // option id is prefixed by "id" - remoteExec('add_pending_inserts', [oid.split(':')]); + loadRemote('json', ajaxFuncArgs('add_pending_inserts', null, + [oid.split(':')]), 'GET', true); var selectNode = optionNode.parentNode; // remove option node 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 = cw.getNode('relationSelector_' + eid); + var relationSelected = relationSelector.options[relationSelector.selectedIndex]; + // new relation as a line in simple edit + buildEntityLine(relationSelected.text, optionNode, selectNode.id, eid); } } function cancelPendingInsert(elementId, element_name, comboId, eid) { // remove matching insert element - var entityView = jqNode('a' + elementId).text(); - jqNode(element_name + elementId).remove(); + var entityView = cw.jqNode('a' + elementId).text(); + cw.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 = cw.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(':')); + loadRemote('json', ajaxFuncArgs('remove_pending_inserts', null, + elementId.split(':')), 'GET', true); } -// 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 + cw.jqNode('span' + nodeId).addClass('pendingDelete'); + // replace handle text + cw.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 + cw.jqNode('span' + nodeId).removeClass('pendingDelete'); + // replace handle text + cw.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(cw.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(tripletIdsString.split('-'), + function(x) { return [x.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) { + insertBefore = insertBefore || cw.getNode('add' + rtype + ':' + peid + 'link').parentNode; + 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); + loadAjaxHtmlHead(dom); var form = jQuery(dom); form.css('display', 'none'); form.insertBefore(insertBefore).slideDown('fast'); @@ -259,76 +321,81 @@ // 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); + _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); + cw.jqNode(['div', peid, rtype, eid].join('-')).slideUp('fast', function() { + $(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')) { + var node = cw.jqNode(nodeid); + 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('-'); + cw.jqNode(divid).fadeTo('fast', 0.5); + var noticeid = ['notice', peid, rtype, eid].join('-'); + cw.jqNode(noticeid).fadeIn('fast'); } } function restoreInlinedEntity(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); + var node = cw.jqNode(nodeid); if (node.attr('cubicweb:type')) { node.val(node.attr('cubicweb:type')); node.attr('cubicweb:type', ''); - jqNode(['fs', peid, rtype, eid].join('-')).append(node); + cw.jqNode(['fs', peid, rtype, eid].join('-')).append(node); var divid = ['div', peid, rtype, eid].join('-'); - jqNode(divid).fadeTo('fast', 1); + cw.jqNode(divid).fadeTo('fast', 1); var noticeid = ['notice', peid, rtype, eid].join('-'); - jqNode(noticeid).hide(); + cw.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,60 +403,66 @@ 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