/* * :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: * - 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,role){jQuery('div.inline-'+rtype+'-'+role+'-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 petype : the parent entity type * @param ttype : the target (inlined) entity type * @param rtype : the relation type between both entities */functionaddInlineCreationForm(peid,petype,ttype,rtype,role,i18nctx,insertBefore){insertBefore=insertBefore||getNode('add'+rtype+':'+peid+'link').parentNode;vard=asyncRemoteExec('inline_creation_form',peid,petype,ttype,rtype,role,i18nctx);d.addCallback(function(response){vardom=getDomFromResponse(response);preprocessAjaxLoad(null,dom);varform=jQuery(dom);form.css('display','none');form.insertBefore(insertBefore).slideDown('fast');updateInlinedEntitiesCounters(rtype,role);reorderTabindex();jQuery(CubicWeb).trigger('inlinedform-added',form);// if the inlined form contains a file input, we must force// the form enctype to multipart/form-dataif(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');}postAjaxLoad(dom);});d.addErrback(function(xxx){log('xxx =',xxx);});}/* * removes the part of the form used to edit an inlined entity */functionremoveInlineForm(peid,rtype,role,eid,showaddnewlink){jqNode(['div',peid,rtype,eid].join('-')).slideUp('fast',function(){$(this).remove();updateInlinedEntitiesCounters(rtype,role);});if(showaddnewlink){toggleVisibility(showaddnewlink);}}/* * 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){// XXX work around the eid_param thing (eid + ':' + eid) for #471746varnodeid=['rel',peid,rtype,eid+':'+eid].join('-');varnode=jqNode(nodeid);if(!node.attr('cubicweb:type')){node.attr('cubicweb:type',node.val());node.val('');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){// XXX work around the eid_param thing (eid + ':' + eid) for #471746varnodeid=['rel',peid,rtype,eid+':'+eid].join('-');varnode=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);vardivid=['div',peid,rtype,eid].join('-');jqNode(divid).fadeTo('fast',1);varnoticeid=['notice',peid,rtype,eid].join('-');jqNode(noticeid).hide();}}function_clearPreviousErrors(formid){jQuery('#'+formid+'ErrorMessage').remove();jQuery('#'+formid+' span.error').remove();jQuery('#'+formid+' .error').removeClass('error');}function_displayValidationerrors(formid,eid,errors){varglobalerrors=[];varfirsterrfield=null;for(fieldnameinerrors){varerrmsg=errors[fieldname];varfieldid=fieldname+':'+eid;varsuffixes=['','-subject','-object'];varfound=false;for(vari=0,length=suffixes.length;i<length;i++){varfield=jqNode(fieldname+suffixes[i]+':'+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);found=true;break;}}if(!found){firsterrfield=formid;globalerrors.push(_(fieldname)+' : '+errmsg);}}if(globalerrors.length){if(globalerrors.length==1){varinnernode=SPAN(null,globalerrors[0]);}else{varinnernode=UL(null,map(partial(LI,null),globalerrors));}// insert DIV and innernode before the formvardiv=DIV({'class':"errorMessage",'id':formid+'ErrorMessage'});div.appendChild(innernode);jQuery('#'+formid).before(div);}returnfirsterrfield||formid;}functionhandleFormValidationResponse(formid,onsuccess,onfailure,result,cbargs){// Successif(result[0]){if(onsuccess){onsuccess(result,formid,cbargs);}else{document.location.href=result[1];}returntrue;}if(onfailure&&!onfailure(result,formid,cbargs)){returnfalse;}unfreezeFormButtons(formid);// Failures_clearPreviousErrors(formid);vardescr=result[1];// Unknown structureif(!isArrayLike(descr)||descr.length!=2){log('got strange error :',descr);updateMessage(descr);returnfalse;}_displayValidationerrors(formid,descr[0],descr[1]);updateMessage(_('please correct errors below'));document.location.hash='#header';returnfalse;}/* unfreeze form buttons when the validation process is over*/functionunfreezeFormButtons(formid){jQuery('#progress').hide();jQuery('#'+formid+' .validateButton').removeAttr('disabled');returntrue;}/* disable form buttons while the validation is being done */functionfreezeFormButtons(formid){jQuery('#progress').show();jQuery('#'+formid+' .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){varchild=form.appendChild(INPUT({type:'hidden',name:bname,value:bvalue}));}varonsubmit=form.onsubmit;if(!onsubmit||(onsubmit&&onsubmit())){form.submit();}if(bname){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 */functionsetFormsTarget(node){var$node=jQuery(node||document.body);$node.find('form').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'}));}});}jQuery(document).ready(function(){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) * @param default_value : value if the field is empty * @param lzone : html fragment (string) for a clic-zone triggering actual edition */functioninlineValidateRelationForm(rtype,role,eid,divid,reload,vid,default_value,lzone){try{varform=getNode(divid+'-form');varrelname=rtype+':'+eid;varnewtarget=jQuery('[name='+relname+']').val();varzipped=formContents(form);vard=asyncRemoteExec('validate_form','apply',zipped[0],zipped[1]);}catch(ex){returnfalse;}d.addCallback(function(result,req){if(handleFormValidationResponse(divid+'-form',noop,noop,result)){if(reload){document.location.reload();}else{varargs={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');}}returnfalse;});returnfalse;}/**** inline edition ****/functionloadInlineEditionForm(eid,rtype,role,divid,reload,vid,default_value,lzone){varargs={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');}functionshowInlineEditionForm(eid,rtype,divid){jQuery('#'+divid).hide();jQuery('#'+divid+'-value').hide();jQuery('#'+divid+'-form').show();}functionhideInlineEdit(eid,rtype,divid){jQuery('#appMsg').hide();jQuery('div.errorMessage').remove();jQuery('#'+divid).show();jQuery('#'+divid+'-value').show();jQuery('#'+divid+'-form').hide();}CubicWeb.provide('edition.js');