У меня есть загрузчик файлов на некоторых моих XPages.Это работает так хорошо, но есть один глубокий недостаток его использования.В некоторых случаях он создает 2, 3, 4 или n дубликатов одного и того же поля внутри документа.И это происходит только в том случае, если я пытаюсь загрузить один файл (или набор файлов) и сделать то же самое сразу после него.Иногда это происходит после того, как я удаляю один файл и загружаю больше.Поля документа выглядят так после сохранения.Я понятия не имею о причине, почему это происходит.
Сначала я думал, что это может быть, потому что я забыл поставить оператор doc_source.save();
в кнопке удаления.Но это не оказалось причиной.
Код CC приведен ниже
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:div id="${javascript:compositeData.ID+'refresh'}">
<xp:table>
<xp:this.rendered><![CDATA[#{javascript:currentDocument.isEditable() && (!context.getUserAgent().isIE(6,9))
}]]></xp:this.rendered>
<xp:tr>
<xp:td id="td1" styleClass="doc_field_select">
<xp:text escape="false" id="cf_add">
<xp:this.value><![CDATA[#{javascript:return(texticon('plus-5-icon',25,25,'Add files',false))
}]]></xp:this.value>
</xp:text>
<xp:eventHandler event="onclick" submit="false"
disableValidators="true">
<xp:this.script><![CDATA[document.getElementById("#{javascript:compositeData.ID+'_files_input'}").click();]]></xp:this.script>
</xp:eventHandler>
</xp:td>
<xp:td styleClass="doc_field_select" id="td2">
<xp:text escape="false" id="cf_deleteall">
<xp:this.value><![CDATA[#{javascript:return(texticon('x-mark-4-icon',25,25,'Delete all',false))
}]]></xp:this.value>
</xp:text>
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" disableValidators="true">
<xp:this.script><![CDATA[var id='#{javascript:
getClientId(compositeData.ID+"_files_upload")}';
var tst=document.getElementById(id);
tst.value='';]]></xp:this.script>
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
var doc:NotesDocument=doc_source.getDocument(true);
if (doc==null)
{
return(null);
}
if (!doc.hasItem(compositeData.FieldName))
{
return(null);
}
var rit1:NotesRichTextItem=doc.getFirstItem(compositeData.FieldName);
if (rit1==null)
{
return(null);
}
try
{
var arr=rit1.getEmbeddedObjects();
}
catch(e)
{
return(null);
}
for(var i = 0; i < arr.length; i++)
{
doc_source.removeAttachment(compositeData.FieldName, arr[i].getName());
}
return;
var doc:NotesDocument=doc_source.getDocument(true);
var rit:NotesRichTextItem=doc.getFirstItem(compositeData.FieldName);
if (rit==null)
{
return('');
}
var arr=rit.getEmbeddedObjects()
if (arr==null)
{
return('');
}
res=[]
for (var i = 0; i < arr.length; i++)
{
var att:NotesEmbeddedObject=arr[i];
//res.push(att.getName())
arr[i].remove();
}
//doc.save()
doc=doc_source.getDocument(true);
print('has RichText');
print(doc.hasItem(compositeData.FieldName));
return;}]]></xp:this.script>
</xp:executeScript>
<xp:saveDocument></xp:saveDocument>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
<div style="height:0px;overflow:hidden">
<input type="file"
id="${javascript:compositeData.ID+'_files_input'}"
onchange="${javascript:
var urlToUpload = '\''+database.getHttpURL()+ database.getFilePath().replace(/\\/g,'/') + view.getPageName() + '\'';
var filesInput = '\'' + compositeData.ID + '_files_input' + '\'';
var filesUpload = '\'' + compositeData.ID + '_files_upload' + '\'';
var filesButton = '\'' + compositeData.ID + '_files_button' + '\'';
var filesProgress = '\'' + compositeData.ID + '_files_progress' + '\'';
return 'files_onchange(' + urlToUpload + ',' + filesInput + ',' + filesUpload + ',' + filesButton + ',' + filesProgress + ')';
}"
multiple="true" uploadOnSelect="true" name="uploadedfile" />
<xp:fileUpload
id="${javascript:compositeData.ID+'_files_upload'}"
useUploadname="true">
<xp:this.value><![CDATA[#{doc_source[compositeData.FieldName]}]]></xp:this.value>
</xp:fileUpload>
<xp:button value="Refresh"
id="${javascript:compositeData.ID+'_files_button'}">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" disableValidators="true"
refreshId="${javascript:compositeData.ID+'refresh'}">
<xp:this.action>
<xp:actionGroup>
<xp:saveDocument></xp:saveDocument>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
if (compositeData.postUpload!=null)
{
compositeData.postUpload.getScript().invoke(facesContext, null)
}}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</div>
<xp:repeat id="${javascript:compositeData.ID+'_files_repeat'}"
rows="30" var="rowData" indexVar="rowIndex">
<xp:this.value><![CDATA[#{javascript:
try
{
var doc:NotesDocument=doc_source.getDocument(true);
}
catch(e)
{
var oss=new OsnovaSession();
}
if (doc==null)
{
return(null);
}
if (!doc.hasItem(compositeData.FieldName))
{
return(null);
}
var rit1:NotesRichTextItem=doc.getFirstItem(compositeData.FieldName);
if (rit1==null)
{
return(null);
}
try
{
var arr=rit1.getEmbeddedObjects()
}
catch(e)
{
return(null);
}
return(arr)
}]]></xp:this.value>
<xp:table>
<xp:tr>
<xp:td styleClass="doc_field_select" id="td4">
<xp:text escape="false" id="cf_file">
<xp:this.value><![CDATA[#{javascript:
if (rowData==null)
{
return('');
}
var siz=(rowData.getFileSize()/1024).toFixed(1);
siz=siz.replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
return(texticon('download-9-icon',compositeData.IconSize,compositeData.IconSize,rowData.getName()+' ('+siz+' KB) ',false));
}]]></xp:this.value>
<xp:this.style><![CDATA[#{javascript:
if(compositeData.IconColor==null)
{
return('')
}
else
{
return('fill:'+compositeData.IconColor+';')
}}]]></xp:this.style>
</xp:text>
<xp:link escape="true" text="Link"
id="link_test" target="_blank" style="display:none">
<xp:this.value><![CDATA[#{javascript:var oss=new OsnovaSession()
try
{
var db:NotesDatabase=session.getDatabase(null,null);
db.openByReplicaID(session.getCurrentDatabase().getServer(),compositeData.ReplicaID);
var doc=db.getDocumentByUNID(compositeData.DocumentUNID);
}
catch(e)
{
var doc=null;
}
if(doc==null)
{
var doc:NotesDocument=doc_source.getDocument();
var db=database;
}
if (doc==null)
{
return(null);
}
//http(s)://[yourserver]/[application.nsf]/[viewname|0]/[UNID| ViewKey]/$File/[AttachmentName]?Open
var res=oss.ServerURL()+'/';
res+=db.getFilePath().replace(/\\/g,'/');
res+='/0/'+doc.getUniversalID()+'/$File/'+rowData.getName()+'?Open';
return(res);
//Old version
var res=oss.ServerURL()+'/'
res+=db.getFilePath().replace(/\\/g,'/')
res+='/xsp/.ibmmodres/domino/OpenAttachment/'
res+=db.getFilePath().replace(/\\/g,'/')+'/'
res+=doc.getUniversalID()+'/$File/'+rowData.getName()+'?Open'
return(res)
}]]></xp:this.value>
</xp:link>
<xp:eventHandler event="onclick" submit="true"
refreshMode="norefresh" disableValidators="true">
<!-- <xp:this.action><![CDATA[#{javascript:/*
var res=oss.ServerURL()+'/'
res+=database.getFilePath().replace(/\\/g,'/')
res+='/xsp/.ibmmodres/domino/OpenAttachment/'
res+=database.getFilePath().replace(/\\/g,'/')+'/'
res+=doc.getUniversalID()+'/$File/'+rowData.getName()+'?Open'
facesContext.getExternalContext().redirect(res)
//view.postScript("window.open('" + res + "'),'_blank'")
*/}]]></xp:this.action> -->
<xp:this.script><![CDATA[
var linkID = '#{javascript:getClientId("link_test")}';
document.getElementById(linkID).click();]]>
</xp:this.script>
</xp:eventHandler>
</xp:td>
<xp:td styleClass="doc_field_select" id="td3">
<xp:text escape="false" id="cf_del">
<xp:this.value><![CDATA[#{javascript:
return(texticon('minus-5-icon',compositeData.IconSize,compositeData.IconSize,'Delete',false));
}]]>
</xp:this.value>
<xp:this.style><![CDATA[#{javascript:
if(compositeData.IconColor==null)
{
return('');
}
else
{
return('fill:'+compositeData.IconColor+';');
}}]]></xp:this.style>
</xp:text>
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" disableValidators="true">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
doc_source.removeAttachment(compositeData.FieldName, rowData.getName());
doc_source.save();
}]]>
</xp:this.script>
</xp:executeScript>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
if (compositeData.postDelete!=null)
{
compositeData.postDelete.getScript().invoke(facesContext, null);
}}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
</xp:repeat>
<span id="${javascript:compositeData.ID+'_files_progress'}">
</span>
</xp:div>
</xp:view>
И скрипт CSJS, который я использую, находится здесь:
function files_onchange(urlToUpload, filesInput, filesUpload, filesButton, filesProgress)
{
var urfiles = document.getElementById(filesInput).files;
files_upload(urlToUpload, filesInput, filesUpload, urfiles, 0, filesButton, filesProgress);
}
function files_upload(url, filesInput, uploadID, files, counter, refreshID, filesProgress)
{
//refreshID, uploadID not exact match
console.log(url);
url=""
console.log(url)
var formData = new FormData();
var file = null;
var form = XSP.findForm(filesInput);
//console.log(uploadID);
if (!files) return;
var numberOfFiles = files.length;
file = files[counter];
var max = files.length;
if (counter >= max) return;
formData.append(document.querySelector('[id$=' + uploadID + ']').id, file);
formData.append("$$viewid", dojo.query("input[name='$$viewid']")[0].value);
formData.append("$$xspsubmitid", dojo.query("input[name='$$xspsubmitid']")[0].value);
formData.append("$$xspsubmitvalue", dojo.query("input[name='$$xspsubmitvalue']")[0].value);
formData.append("$$xspsubmitscroll", dojo.query("input[name='$$xspsubmitscroll']")[0].value);
formData.append(form.id, form.id);
var xhr = new XMLHttpRequest();
/* event listners */
xhr.upload.addEventListener("progress", function(e)
{
if (e.lengthComputable)
{
var percentComplete = Math.round(e.loaded * 100 / e.total);
document.getElementById(filesProgress).innerHTML = percentComplete.toString()+'%, ( '+(counter+1).toString()+' / '+numberOfFiles.toString()+' )';
}
else
{
document.getElementById(filesProgress).innerHTML = '...';
}
}, false);
xhr.addEventListener("load", function()
{
counter++;
if (counter >= max)
{
document.getElementById(filesInput).value = "";
if (refreshID)
{
document.querySelector('[id$=' + refreshID + ']').click();
}
}
else
{
files_upload(url, filesInput, uploadID, files, counter, refreshID, filesProgress); // сам себя, ну ебаный ты в рот блять
}
}, false);
xhr.addEventListener("error", function(e)
{
document.getElementById(filesProgress).innerHTML = "Error: "+e;
}, false);
xhr.addEventListener("abort", function()
{
document.getElementById(filesProgress).innerHTML = "Upload cancelled.";
}, false);
xhr.open("POST", url);
xhr.send(formData);
document.querySelector('[id$=' + uploadID + ']').value = '';
}
Возможно, это просто функция Notes для храненияRichText элементы?Заранее спасибо.