/* * :organization: Logilab * :copyright: 2003-2009 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: * - 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 */functionsetPropValueWidget(varname,tabindex){varkey=firstSelected(document.getElementById('pkey:'+varname));if(key){varargs={fname:'prop_widget',pageid:pageid,arg:map(jQuery.toJSON,[key,varname,tabindex])};jqNode('div:value:'+varname).loadxhtml(JSON_BASE_URL,args,'post');}}// *** EDITION FUNCTIONS ****************************************** ///* * this function is called when an AJAX form was generated to * make sure tabindex remains consistent */functionreorderTabindex(start){varform=getNode('entityForm');varinputTypes=['INPUT','SELECT','TEXTAREA'];vartabindex=(start==null)?15:start;nodeWalkDepthFirst(form,function(elem){vartagName=elem.tagName.toUpperCase();if(inputTypes.contains(tagName)){if(getNodeAttribute(elem,'tabindex')!=null){tabindex+=1;elem.setAttribute('tabindex',tabindex);}returnnull;}returnfilter(isElementNode,elem.childNodes);});}functionshowMatchingSelect(selectedValue,eid){if(selectedValue){divId='div'+selectedValue+'_'+eid;vardivNode=jQuery('#'+divId);if(!divNode.length){varargs={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);}}// @param divNode is a jQuery selectionfunction_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();}}// this function builds a Handle to cancel pending insertionfunctionbuildPendingInsertHandle(elementId,element_name,selectNodeId,eid){jscall="javascript: cancelPendingInsert('"+[elementId,element_name,selectNodeId,eid].join("', '")+"')";returnA({'class':'handle','href':jscall,'title':_("cancel this insert")},'[x]');}functionbuildEntityLine(relationName,selectedOptionNode,comboId,eid){// textContent doesn't seem to work on selectedOptionNodevarcontent=selectedOptionNode.firstChild.nodeValue;varhandle=buildPendingInsertHandle(selectedOptionNode.id,'tr',comboId,eid);varlink=A({'href':'view?rql='+selectedOptionNode.value,'class':'editionPending','id':'a'+selectedOptionNode.id},content);vartr=TR({'id':'tr'+selectedOptionNode.id},[TH(null,relationName),TD(null,[handle,link])]);try{varseparator=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)vartableBody=separator.parentNode;tableBody.insertBefore(tr,separator);}catch(ex){log("got exception(2)!"+ex);}}functionbuildEntityCell(relationName,selectedOptionNode,comboId,eid){varhandle=buildPendingInsertHandle(selectedOptionNode.id,'div_insert_',comboId,eid);varlink=A({'href':'view?rql='+selectedOptionNode.value,'class':'editionPending','id':'a'+selectedOptionNode.id},content);vardiv=DIV({'id':'div_insert_'+selectedOptionNode.id},[handle,link]);try{vartd=jQuery('#cell'+relationName+'_'+eid);td.appendChild(div);}catch(ex){alert("got exception(3)!"+ex);}}functionaddPendingInsert(optionNode,eid,cell,relname){varvalue=getNodeAttribute(optionNode,'value');if(!value){// occurs when the first element in the box is selected (which is not// an entity but the combobox title)return;}// 2nd special caseif(value.indexOf('http')==0){document.location=value;return;}// add hidden parametervarentityForm=jQuery('#entityForm');varoid=optionNode.id.substring(2);// option id is prefixed by "id"remoteExec('add_pending_inserts',[oid.split(':')]);varselectNode=optionNode.parentNode;// remove option nodeselectNode.removeChild(optionNode);// add line in tableif(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);}else{varrelationSelector=getNode('relationSelector_'+eid);varrelationSelected=relationSelector.options[relationSelector.selectedIndex];// new relation as a line in simple editbuildEntityLine(relationSelected.text,optionNode,selectNode.id,eid);}}functioncancelPendingInsert(elementId,element_name,comboId,eid){// remove matching insert elementvarentityView=jqNode('a'+elementId).text();jqNode(element_name+elementId).remove();if(comboId){// re-insert option in combobox if it was taken from therevarselectNode=getNode(comboId);// XXX what on object relationif(selectNode){varoptions=selectNode.options;varnode_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 insertionfunctionbuildPendingDeleteHandle(elementId,eid){varjscall="javascript: addPendingDelete('"+elementId+', '+eid+"');";returnA({'href':jscall,'class':'pendingDeleteHandle','title':_("delete this relation")},'[x]');}// @param nodeId eid_from:r_type:eid_tofunctionaddPendingDelete(nodeId,eid){vard=asyncRemoteExec('add_pending_delete',nodeId.split(':'));d.addCallback(function(){// and strike entity viewjqNode('span'+nodeId).addClass('pendingDelete');// replace handle textjqNode('handle'+nodeId).text('+');});}// @param nodeId eid_from:r_type:eid_tofunctioncancelPendingDelete(nodeId,eid){vard=asyncRemoteExec('remove_pending_delete',nodeId.split(':'));d.addCallback(function(){// reset link's CSS classjqNode('span'+nodeId).removeClass('pendingDelete');// replace handle textjqNode('handle'+nodeId).text('x');});}// @param nodeId eid_from:r_type:eid_tofunctiontogglePendingDelete(nodeId,eid){// node found means we should cancel deletionif(hasElementClass(getNode('span'+nodeId),'pendingDelete')){cancelPendingDelete(nodeId,eid);}else{addPendingDelete(nodeId,eid);}}functionselectForAssociation(tripletIdsString,originalEid){vartripletlist=map(function(x){returnx.split(':');},tripletIdsString.split('-'));vard=asyncRemoteExec('add_pending_inserts',tripletlist);d.addCallback(function(){varargs={vid:'edition',__mode:'normal',rql:rql_for_eid(originalEid)};document.location='view?'+asURL(args);});}functionupdateInlinedEntitiesCounters(rtype){jQuery('#inline'+rtype+'slot span.icounter').each(function(i){this.innerHTML=i+1;});}/* * makes an AJAX request to get an inline-creation view's content * @param peid : the parent entity eid * @param ttype : the target (inlined) entity type * @param rtype : the relation type between both entities */functionaddInlineCreationForm(peid,ttype,rtype,role){vard=asyncRemoteExec('inline_creation_form',peid,ttype,rtype,role);d.addCallback(function(response){varlinknode=getNode('add'+rtype+':'+peid+'link');vardom=getDomFromResponse(response);varform=jQuery(dom);form.css('display','none');form.insertBefore(linknode.parentNode).slideDown('fast');updateInlinedEntitiesCounters(rtype);reorderTabindex();form.trigger('inlinedform-added');postAjaxLoad(dom);});d.addErrback(function(xxx){log('xxx =',xxx);});}/* * removes the part of the form used to edit an inlined entity */functionremoveInlineForm(peid,rtype,eid){jqNode(['div',peid,rtype,eid].join('-')).slideUp('fast',function(){$(this).remove();updateInlinedEntitiesCounters(rtype);});}/* * 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 */functionremoveInlinedEntity(peid,rtype,eid){varnodeid=['rel',peid,rtype,eid].join('-');varnode=jqNode(nodeid);if(node&&node.length){node.remove();vardivid=['div',peid,rtype,eid].join('-');jqNode(divid).fadeTo('fast',0.5);varnoticeid=['notice',peid,rtype,eid].join('-');jqNode(noticeid).fadeIn('fast');}}functionrestoreInlinedEntity(peid,rtype,eid){varnodeid=['rel',peid,rtype,eid].join('-');vardivid=['div',peid,rtype,eid].join('-');varnoticeid=['notice',peid,rtype,eid].join('-');varnode=jqNode(nodeid);if(!(node&&node.length)){node=INPUT({type:'hidden',id:nodeid,name:rtype+':'+peid,value:eid});jqNode(['fs',peid,rtype,eid].join('-')).append(node);jqNode(divid).fadeTo('fast',1);jqNode(noticeid).hide();}}function_clearPreviousErrors(formid){jQuery('#'+formid+' span.error').remove();}function_displayValidationerrors(formid,eid,errors){varglobalerrors=[];varfirsterrfield=null;for(fieldnameinerrors){varerrmsg=errors[fieldname];varfieldid=fieldname+':'+eid;varfield=jqNode(fieldname+':'+eid);if(field&&getNodeAttribute(field,'type')!='hidden'){if(!firsterrfield){firsterrfield='err-'+fieldid;}addElementClass(field,'error');varspan=SPAN({'id':'err-'+fieldid,'class':"error"},errmsg);field.before(span);}else{firsterrfield=formid;globalerrors.push(fieldname+': '+errmsg);}}if(globalerrors.length){if(globalerrors.length==1){varinnernode=SPAN(null,globalerrors[0]);}else{varinnernode=UL(null,map(LI,globalerrors));}// insert DIV and innernode before the formvardiv=DIV({'class':"errorMessage"});div.appendChild(innernode);jQuery('#'+formid).before(div);}returnfirsterrfield||formid;}functionhandleFormValidationResponse(formid,onsuccess,onfailure,result){// Successif(result[0]){if(onsuccess){returnonsuccess(result[1],formid);}else{document.location.href=result[1];return;}}unfreezeFormButtons(formid);// Failures_clearPreviousErrors(formid);vardescr=result[1];// Unknown structureif(!isArrayLike(descr)||descr.length!=2){log('got strange error :',descr);updateMessage(descr);return;}_displayValidationerrors(formid,descr[0],descr[1]);updateMessage(_("please correct errors below"));document.location.hash='#header';if(onfailure){onfailure(formid);}returnfalse;}/* unfreeze form buttons when the validation process is over*/functionunfreezeFormButtons(formid){jQuery('#progress').hide();jQuery('#'+formid+' input.validateButton').removeAttr('disabled');returntrue;}/* disable form buttons while the validation is being done */functionfreezeFormButtons(formid){jQuery('#progress').show();jQuery('#'+formid+' input.validateButton').attr('disabled','disabled');returntrue;}/* used by additional submit buttons to remember which button was clicked */functionpostForm(bname,bvalue,formid){varform=getNode(formid);if(bname){form.appendChild(INPUT({type:'hidden',name:bname,value:bvalue}));}varonsubmit=form.onsubmit;if(!onsubmit||(onsubmit&&onsubmit())){form.submit();}}/* 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 */functionsetFormsTarget(){jQuery('form.entityForm').each(function(){varform=jQuery(this);vartarget=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'}));}});}$(document).ready(setFormsTarget);/* * 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 * around the corresponding input fields. */functionvalidateForm(formid,action,onsuccess,onfailure){try{varzipped=formContents(formid);vard=asyncRemoteExec('validate_form',action,zipped[0],zipped[1]);}catch(ex){log('got exception',ex);returnfalse;}function_callback(result,req){handleFormValidationResponse(formid,onsuccess,onfailure,result);}d.addCallback(_callback);returnfalse;}/* * 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) */functioninlineValidateAttributeForm(formid,rtype,eid,divid,reload,default_value){try{varform=getNode(formid);if(typeofFCKeditorAPI!="undefined"){for(varnameinFCKeditorAPI.__Instances){varoEditor=FCKeditorAPI.__Instances[name];if(oEditor.GetParentForm()==form){oEditor.UpdateLinkedField();}}}varzipped=formContents(form);vard=asyncRemoteExec('edit_field','apply',zipped[0],zipped[1],rtype,eid,default_value);}catch(ex){log('got exception',ex);returnfalse;}d.addCallback(function(result,req){handleFormValidationResponse(formid,noop,noop,result);if(reload){document.location.href=result[1];}else{varfieldview=getNode(divid);// XXX using innerHTML is very fragile and won't work if// we mix XHTML and HTMLfieldview.innerHTML=result[2];// switch inline form off only if no errorif(result[0]){// hide global error messagesjQuery('div.errorMessage').remove();jQuery('#appMsg').hide();cancelInlineEdit(eid,rtype,divid);}}returnfalse;});returnfalse;}functioninlineValidateRelationForm(formid,rtype,role,eid,divid,vid,default_value){try{varform=getNode(formid);varrelname=rtype+':'+eid;varnewtarget=jQuery('[name='+relname+']').val();varzipped=formContents(form);vard=asyncRemoteExec('edit_relation','apply',zipped[0],zipped[1],rtype,role,eid,vid,default_value);}catch(ex){log('got exception',ex);returnfalse;}d.addCallback(function(result,req){handleFormValidationResponse(formid,noop,noop,result);varfieldview=getNode(divid);fieldview.innerHTML=result[2];// switch inline form off only if no errorif(result[0]){// hide global error messagesjQuery('div.errorMessage').remove();jQuery('#appMsg').hide();varinputname='edit'+role[0]+'-'+relname;jQuery('input[name='+inputname+']').val(newtarget);cancelInlineEdit(eid,rtype,divid);}returnfalse;});returnfalse;}/**** inline edition ****/functionshowInlineEditionForm(eid,rtype,divid){jQuery('#'+divid).hide();jQuery('#'+divid+'-form').show();}functioncancelInlineEdit(eid,rtype,divid){jQuery('#'+divid).show();jQuery('#'+divid+'-form').hide();}CubicWeb.provide('edition.js');