Java
JavascriptExecutor js = (JavascriptExecutor) driver;
Boolean ready = (Boolean)js.executeScript("the below JavaScript");
JavaScript
var ready = false;
window.onload = function() {
ready = true;
}
window.sleep = function() {
return new Promise(resolve => setTimeout(resolve, 2000));
}
for(var i = 0; i < 30; i++) {
if(ready) {
return true;
}
await sleep();
}
return false;
UPDATE: Sorry about the previous syntax error "funtion" in my post. That was a typo not in my actual code. All syntax errors should be gone, but I still get "SyntaxError: Unexpected identifier".
What this code is trying to do is wait for a maximum amount of time for the page to be loaded. I typically return document.readyState to check for that condition but in unique circumstances Chrome will suddenly stop loading the page and document.readyState hangs for 5+ minutes. This is killing my code so I am attempting to develop single-threaded code to kind of mimic a typically multi-threaded process.
Since JavaScript is single threaded (such a disappointing feature for a cool language like JavaScript), we have to be creative.
This code works in the browser console if you replace return true; with console.log('true'); and return false; with console.log('false'); so I don't see what the problem is.
Indeed there are some mistakes in your JavaScript code.
The first mistake is, in third line
window.sleep = funtion() { return new Promise(resolve => setTimeout(resolve, 2000)); }, the function spelling is wrong.
The second mistake is you should not use await when there is no async in your function definition. Here is the thing, async ensures that the function returns a promise, and wraps non-promises in it. The keyword await makes JavaScript wait until that promise settles and returns its result. await works only inside async functions. So you can avoid using these completely or you need to format it accordingly.
The third mistake is, you are trying to do return true; from the for loop of the if condition which is not allowed basically because it is not wrapped inside the function.
The fourth mistake is, you are not calling the window.onload function - as the result, it is always returns false even though the page is loaded.
The fifth thing is, I don't know what incomplete resolve is doing in window.sleep function.
The sixth thing is, you are returning return false; at the end without any reference which is completely meaningless.
I have modified the code and avoided the above mistakes, please look into it.
Below is the modified JavaScript code:
var status = false;
window.sleep = function() {
return setTimeout(() => {
console.log("=> Waited for 2 seconds...");
}, 2000);
}
var getStatus = function() {
for(var i = 0; i < 30; i++) {
if(window.onload = function() {
return true;
}) {
status = true;
console.log(i+"). Loaded ? "+status);
break;
} else {
console.log(i+"). Loaded ? "+status);
sleep();
}
}
return status;
}
getStatus();
Try the below Java code which prints true after the page loads :
System.setProperty("webdriver.chrome.driver", "C:\\NotBackedUp\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("http://www.google.com");
JavascriptExecutor js = (JavascriptExecutor) driver;
Boolean result = (Boolean) js.executeScript("var status = false;\r\n" +
"window.sleep = function() { \r\n" +
" return setTimeout(() => {\r\n" +
" console.log(\"=> Waited for 2 seconds...\");\r\n" +
" }, 2000);\r\n" +
"}\r\n" +
"var getStatus = function() {\r\n" +
" for(var i = 0; i < 30; i++) {\r\n" +
" if(window.onload = function() {\r\n" +
" return true;\r\n" +
" }) {\r\n" +
" status = true;\r\n" +
" console.log(i+\"). Loaded ? \"+status);\r\n" +
" break;\r\n" +
" } else {\r\n" +
" console.log(i+\"). Loaded ? \"+status);\r\n" +
" sleep();\r\n" +
" }\r\n" +
" }\r\n" +
" return status;\r\n" +
"}\r\n" +
"return getStatus();");
System.out.println(result);
I hope it helps...
Related
I am writing a simple Javascript script which uses XMLHttpRequest objects to query an API. There are two main functions within the script; routeLength(startID,endID); and getSystemSecurity(systemID);
The first method returns a Promise object, within with an API call is made:
function routeLength (startID, endID) {
return new Promise((resolve, reject) => {
const url = `the request URL`;
const xml = new XMLHttpRequest();
xml.onload = function () {
var systems = this.response.split(',');
const length = systems.length - 1;
var routeSecurity = 2;
var promises = [];
systems.forEach((element) => {
if (element[0] == '[') {
promises.push(
getSystemSecurity(element.substr(1, element.length - 1))
);
}
else if (element[element.length - 1] == ']') {
promises.push(
getSystemSecurity(element.substr(0, element.length - 1))
);
}
else promises.push(getSystemSecurity(element));
});
Promise.all(promises).then((values) => {
values.forEach((v) => {
if (v < routeSecurity) routeSecurity = v;
})
resolve({"jumps":length,"security":routeSecurity});
}).catch((error) => {
reject(error)
});
};
xml.open("GET", url);
xml.send();
})
}
This method makes a GET request to the API, and performs some logic with the result. The 'systems' array contains system IDs which I have checked are all valid (once the brackets are removed if needed). The promises pushed into the promises array call the following function:
function getSystemSecurity (systemID) {
return new Promise((resolve,reject) => {
const url = `${API_URL}/universe/systems/${systemID}`;
const xml = new XMLHttpRequest();
xml.onload = function () {
if (this.response.error) reject(this.response.error);
const security = this.response["security_status"];
if (security >= 0.5) resolve(HIGH_SECURITY);
else if (security < 0.5 && security > 0) resolve(LOW_SECURITY);
else if (security < 0) resolve(NULL_SECURITY);
else reject({"error":"Invalid security value " + security});
}
xml.onerror = reject("Error executing XMLHttpRequest with ID " + systemID + xml.statusText + xml.responseText);
xml.open("GET", url);
xml.send();
});
}
When I try to run this method, I can see all of the proper requests being made, both the initial request to /route/ as well as the /universe/systems/ routes. Using the developer console I can see that none of them have failed and they all have the expected data. However, I am told that the first promise had failed:
(index):1 Uncaught (in promise) Error executing XMLHttpRequest with ID 30002659
As you can see from the error, xml.statusText and xml.responseText aren't populated, so I cannot determine the actual error that is happening.
So why is Promise.all failing despite all of the requests working with 200 response codes?
The problem is in this line:
xml.onerror = reject("Error executing XMLHttpRequest with ID " + systemID + xml.statusText + xml.responseText);
You are not assigning an event handler, but executing it on the spot!
It should be:
xml.onerror = () => reject("Error executing XMLHttpRequest with ID " + systemID + xml.statusText + xml.responseText);
A general remark: please use the fetch API, it is so much easier to use, and it returns a promise out of the box, so that you can get rid of all those new Promise constructs.
I guess this is more of a question regarding how to use Promises correctly, which i don't grok:
According to this site (https://ourcodeworld.com/articles/read/405/how-to-convert-pdf-to-text-extract-text-from-pdf-with-javascript), we extract text from a page this way:
// assume pdf file has been loaded
function getPageText(pageNum, PDFDocumentInstance) {
// Return a Promise that is solved once the text of the page is retrieven
return new Promise(function (resolve, reject) {
PDFDocumentInstance.getPage(pageNum).then(function (pdfPage) {
// The main trick to obtain the text of the PDF page, use the getTextContent method
pdfPage.getTextContent().then(function (textContent) {
var textItems = textContent.items;
var finalString = "";
// Concatenate the string of the item to the final string
for (var i = 0; i < textItems.length; i++) {
var item = textItems[i];
finalString += item.str + " ";
}
// Solve promise with the text retrieven from the page
resolve(finalString);
});
});
});
}
I want to search for a certain string through all the pages till i find the page with that string. i tried the obviously wrong way of calling the above function in a for loop, but didn't know how to end when the string was found.
Thanks for the assist!
here's a lame-ish attempt. it's recursive (wish it wasn't), and although it finds the text and gets to the resolve() call, i have no idea where execution goes from there, because it doesn't log to console as i had hoped:
function findText() {
var textToFind = document.getElementById('textToFind').value;
findIt( 1, textToFind ).then( function( pageIndex ) {
// the line below never gets called. i expected the resolve() method
// further down to come here.
console.log( 'Found ' + textToFind + ' on page ' + pageIndex );
},
function(reason) {
console.log(reason);
});
}
function findIt( pageIndex, textToFind ) {
return new Promise( function( resolve, reject ) {
if ( pageIndex > pdfObject.numPages-1 ) {
reject("Couldn't find " + textToFind);
}
getPageText( pageIndex ).then( function( pageText ) {
if ( pageText.indexOf(textToFind) === -1 ) {
findIt( pageIndex+1, textToFind );
}
else {
resolve(pageIndex); // in the debugger, i get here
}
});
});
}
I am trying to write a function which takes a list of Rich Text Content Controls and a single string as argument, and which replaces the content of all matching content controls with this string.
While this works with a smaller amount of content controls, it fails with documents with a huge amount of them. I have to work with documents with over 700 Content Controls with individual titles. In this case, the code just replaces the first 66X CCs and then aborts with a GeneralException. I assume this is just due to the huge amount of content controls. I am having similar problems, when I try to register bindings for all these CCs (GeneralException). But this is a different topic.
I tried to work around this problem, by limiting the amounts of changes per .sync() and looping through the CCs, performing as many loops as necessary. However, this is not that easy, due to the asynchronous nature of office-js. I am not very familiar with javascript-async-promise-programming so far. But this is what I have come up with:
function replaceCCtextWithSingleString (CCtitleList, string) {
var maxPerBatch = 100;
/*
* A first .then() block is executed to get proxy objects for all selected CCs
*
* Then we would replace all the text-contents in one single .then() block. BUT:
* Word throws a GeneralException if you try to replace the text in more then 6XX CCs in one .then() block.
* In consequence we only process maxPerBatch CCs per .then() block
*/
Word.run(function (context) {
var CCcList = [];
// load CCs
for(var i = 0; i < CCtitleList.length; i++) {
CCcList.push(context.document.contentControls.getByTitle(CCtitleList[i]).load('id'));
}
return context.sync().then(function () { // synchronous
var CClist = [];
// aggregate list of CCs
for(var i = 0; i < CCcList.length; i++) {
if(CCcList[i].items.length == 0) {
throw 'Could not find CC with title "'+CCtitleList[j]+'"';
}
else {
CClist = CClist.concat(CCcList[i].items);
}
}
$('#status').html('Found '+CClist.length+' CCs matching the criteria. Started replacing...');
console.log('Found '+CClist.length+' CCs matching the criteria. Started replacing...');
// start replacing
return context.sync().then((function loop (replaceCounter, CClist) {
// asynchronous recoursive loop
for(var i = 0; replaceCounter < CClist.length && i < maxPerBatch; i++) { // loop in loop (i does only appear in condition)
// do this maxPerBatch times and then .sync() as long as there are still unreplaced CCs
CClist[replaceCounter].insertText(string, 'Replace');
replaceCounter++;
}
if(replaceCounter < CClist.length) return context.sync() // continue loop
.then(function () {
$('#status').html('...replaced the content of '+replaceCounter+' CCs...');
return loop(replaceCounter, numCCs);
});
else return context.sync() // end loop
.then(function () {
$('#status').html('Replaced the content of all CCs');
});
})(0, CClist));
});
}).catch(function (error) {
$('#status').html('<pre>Error: ' + JSON.stringify(error, null, 4) + '</pre>');
console.log('Error: ' + JSON.stringify(error, null, 4));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo, null, 4));
}
throw error;
});
}
However... it is not working. It replaces the first 100 CCs and then stops. Without a failure, without an exception or anything. The return loop(replaceCounter, CClist); is just not executed and I don't know why. If I try to step into this line in the debugger it throws me somewhere in the office-js code.
Any suggestions?
Edit:
I updated my code based on the suggestions of Juan Balmori and it works as a charm:
function replaceCCtextWithSingleString_v1_1 (CCtitleList, string) {
Word.run(function (context) {
var time1 = Date.now();
// load the title of all content controls
var CCc = context.document.contentControls.load('title');
return context.sync().then(function () { // synchronous
// extract CC titles
var documentCCtitleList = [];
for(var i = 0; i < CCc.items.length; i++) { documentCCtitleList.push(CCc.items[i].title); }
// check for missing titles and replace
for(var i = 0; i < CCtitleList.length; i++) {
var index = documentCCtitleList.indexOf(CCtitleList[i]);
if(index == -1) { // title is missing
throw 'Could not find CC with title "'+CCtitleList[i]+'"';
}
else { // replace
CCc.items[index].insertText(string, 'Replace');
}
}
$('#status').html('...replacing...');
return context.sync().then(function () {
var time2 = Date.now();
var tdiff = time2-time1;
$('#status').html('Successfully replaced all selected CCs in '+tdiff+' ms');
});
});
}).catch(function (error) {
$('#status').html('<pre>Error: ' + JSON.stringify(error, null, 4) + '</pre>');
console.log('Error: ' + JSON.stringify(error, null, 4));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo, null, 4));
}
});
}
It still takes 13995 ms to complete, but at least it works :-)
Any ideas, what was provoking the GeneralException though?
I posted a new question concerning the speed issue: What is the fastest way of replacing the text of many content controls via office-js?
Good Question.. I did some perf test long time ago and I was able to change more than 10k content controls in a document. with 700 you should be ok.
Not sure why are you pre-filling a list, that is not needed, you are actually navigating 2 times the collection which is not good for perf. You can do the string comparison while traversing the collection!
Here is an example, I just did a quick test with a 700 content control document with a hypothetical tag of "test".
I was able to
1. Compare their text against whatever you want to compare it (its a string)
2. Change the value if the condition is true.
It took 5134 milliseconds to complete the operation and here is the code. which I think its quite acceptable.
Hope this helps!
function perfContentControls() {
var time1 = Date.now(); // lets see in how much time we complete the operation :)
var CCs =0
Word.run(function (context) {
var myCCs = context.document.body.contentControls.getByTag("test");
context.load(myCCs);
return context.sync()
.then(function () {
CCs = myCCs.items.length
for (var i = 0; i < CCs; i++) {
if (myCCs.items[i].text == "new text 3") // you can check the cc content and if needed replace it....
myCCs.items[i].insertText("new text 4", "replace");
}
return context.sync()
.then(function () {
var time2 = Date.now();
var diff = time2 - time1;
console.log("# of CCs:" + CCs + " time to change:" + diff + "ms");
})
})
.catch(function (er) {
console.log(er.message);
})
})
}
I need help with loop beaking.
For my check I did the simple test:
while(i < 10) {
element(by.xpath("//a[contains(#id, 'ma-apply')]")).isPresent().then(function(result) {
if(!result) {
helper.one_page_ahead();
} else {
console.log('there is on the page');
break;
}
});
i++;
};
This code leads to the error.
I tried to follow advice via StackOverflow and changed break to return.
But this leads to full loop execution (up to 10).
Here is the output:
[14:17:46] I/launcher - Running 1 instances of WebDriver Started user
skills: AJAX there is on the page there is on the page there is on the
page there is on the page there is on the page there is on the page
there is on the page there is on the page .
1 spec, 0 failures Finished in 37.93 seconds
I tried the same with for loop like
for(i = 0; i < 10; i++) {
//code
break;
}
Would be glad to find the answer.
This is some commentary about why the while statement does not work: When you call isPresent you are returned a webdriver.promise.Promise<boolean>. Since you are in the webdriver control flow, you'll need to throw an error,
browser.get('http://angularjs.org');
var i = 0;
var running = true;
while(i < 3 && running) {
console.log('while: ' + running + ' ' + i);
element(by.model('username')).isPresent().then((result) => {
console.log('element: ' + running + ' ' + i);
if (result) {
// huzzah we found it, so lets break the element after the first test
browser.get('https://docs.angularjs.org/tutorial');
} else {
running = false;
throw new Error('no username')
}
}).catch((err) => {
console.log(err);
});
i++;
}
This basically prints out:
[19:07:18] I/hosted - Using the selenium server at http://localhost:4444/wd/hub
[19:07:18] I/launcher - Running 1 instances of WebDriver
Started
while: true 0
while: true 1
while: true 2
element: true 3
[Error: no username]
element: false 3
[Error: no username]
element: false 3
[Error: no username]
So basically your while loop queues up items in the control flow to execute. These then will get executed asynchronously in order.
I like the suggestion by Sudharsan Selvaraj to do this recursively.
You need to implement a recursive method to achieve what you want, try the below piece of code,
function runTillElementFound(totalCount,currentCount){
var self = this;
var _element = element(by.xpath("//a[contains(#id, 'ma-apply')]"));
if(currentCount < totalCount){
return _element.isPresent().then(function(isElementPresent){
if(isElementPresent){
return;
}else{
helper.one_page_ahead();
self.runTillElementFound(totalCount,currentCount++);
}
})
}else{
return false; //if element not present after Max count reached.
}
}
this.runTillElementFound(10,0); //this will execute the method untill the required element found on the page.
If you want to avoid recursion you could modify the index variable inside the returned promised
while(i < 10) {
element(by.xpath("//a[contains(#id, 'ma-apply')]")).isPresent().then(function(result) {
if(!result) {
helper.one_page_ahead();
} else {
console.log('there is on the page');
i = 10;
}
});
i++;
};
And I would add a browser.sleep(x) in between each repetion to avoid the code to be run before the result from the promise is evaluated.
i = 10; is not effecting, Still loop iterating
I have a 100 or so Word Open XML (.xml, not .docx, saved as "Word XML Document")documents (components) stored on SharePoint.
I use AJAX to load these by selection, as xml, 1 to many into an array, in which I also manage the selection sequence.
Once the user has selected the "components" they can then insert them into Word, the insertion is done via an array traversal (there is probably a better way to do this - but for now it does work),
wordBuild does the loading
function writeDocSync(){
// run through nameXMLArray to find the right sequence
var x = 0;
var countXMLAdds = 0;
//debugger;
toggleWriteButton("disable");
$('.progress-button').progressInitialize("Building Word");
toggleProgressBar(true);
// only run if we have data present
if(nameXMLArray.length > 0){
// increment through sequentially until we have all values
while (countXMLAdds <= checkedList.length){
// repeatedly traverse the array to get the next in sequence
while (x < nameXMLArray.length){
if (Number(nameXMLArray[x].position) === countXMLAdds && nameXMLArray[x].useStatus === true){
progHold = countXMLAdds;
wordBuild(nameXMLArray[x].xml, nameXMLArray[x].filename, countXMLAdds);
}
x++;
}
x=0;
countXMLAdds ++;
}
document.getElementById("showCheck").className = "results";
writeSelections("<b>You just built your proposal using<br/>the following components:</b><br/>");
toggleWriteButton("enable");
}
}
xxxxxxxxx
function wordBuild(xmlBody, nameDoc, progress){
var aryLN = checkedList.length;
var progPCT = (progress/aryLN)*100;
progressMeter.progressSet(progPCT);
Word.run(function (context) {
var currentDoc = context.document;
var body = currentDoc.body;
body.insertOoxml(xmlBody, Word.InsertLocation.end);
body.insertBreak(Word.BreakType.page, Word.InsertLocation.end);
return context.sync().then(function () {
showNotification("Written " + nameDoc);
});
})
.catch(function (error) {
showNotification('Error: ' + nameDoc + ' :' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
showNotification('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
All the documents will load singly, and all will load in batches of say 10 - 30 or more.
The problem comes when I load the entire set (I have a "check all" option).
Sometimes 50 will build before I get an exception, sometimes 60, rarely more than 60, but very occasionally I get a gap where the exception doesn't occur, then it continues later.
The exception (which is repeated for each file) is:
Debug info: {}
Error: componentABC.xml :{"name":"OfficeExtension.Error","code":"GeneralException","message":"An internal error has occurred.","traceMessages":[],"debugInfo":{},"stack":"GeneralException: An internal error has occurred.\n at Anonymous function (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:150094)\n at yi (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163912)\n at st (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163999)\n at d (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163819)\n at c (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:162405)"}
Any help with what might cause this would be hugely appreciated.
Oh I should also say, the files where the exception is raised don't get inserted into Word. But in smaller batches - they work without issue.
Word.run() is an asynchronous call, and there's a limit to the number of concurrent Word.run() calls you can make. Since you're executing Word.run() inside a while loop, all of them get kicked off at the same time and run simultaneously.
There are a few ways to work around this.
Put everything inside one Word.run() call. This puts everything in one giant batch, avoiding multiple roundtrip calls to Word.
if (nameXMLArray.length > 0 {
Word.run(function(context) {
//...
while(...) {
wordBuild(context, nameXMLArray[x].xml, nameXMLArray[x].filename, countXMLAdds);
//...
}
return context.sync();
});
}
function wordBuild(context, xmlBoxy, nameDoc, progress) {
//everything as it currently is, except without the Word.run and the context.sync
}
Implement wordBuild as a promise, and use AngularJS’s $q service to chain the promises, something vaguely like this:
function wordBuild(...) {
var deferred = $q.defer();
Word.run( function(context) {
// current code
return context.sync().then(function() {
deferred.resolve();
});
});
return deferred.promise;
}
//Somewhere else
for (var x…)
{
promises.add(wordBuild);
}
$q.all(promises);
https://docs.angularjs.org/api/ng/service/$q
Angularjs $q.all
Chain the wordBuild calls yourself, as something like this:
var x = 0;
var context;
function (wordBuild() {
if (x >= nameXMLArray.length)
return;
else {
context.document.body.insertOoxml(ooxml, Word.InsertLocation.end);
x++;
return context.sync().then(wordBuild);
}
});
Word.run(function (ctx) {
context = ctx;
return wordBuild();
}
This sort of approach is difficult to maintain, but it could work.
Incidentally, the progress meter in your original code only updates when the call to Word starts, not when it actually returns. You might want to move the progress meter update code into the callback.
I ended up using jQuery deferreds, I was already using jQuery for treeview and checkboxes etc. so it made sense.
This is a mix of Geoffrey's suggestions and my own! I cannot claim it to be good code, only that is does work. (If it is good code or not will take me more time to understand!)
I run batches of 49 xml doc inserts, at 51 the Async call "Word.run" failed in tests, and inserts of 80 or so documents in one Word.run caused Word to freeze, so although not proven 49 inserts within 1 Word.run seems like a good starter for 10! 50 inserts of 49 pieces allows for 2450 inserts, which is way beyond anything I can see being needed, and would probably break Word!
To get the deferreds and sent variables to keep their values once launched as asynch deferreds I had to create a variable to transfer both new deferreds, and values, so I could use the "bind" command.
As Word async returns context.sync() I check the count of the batch, when the batch is completed, I then call the next batch - inside the context.sync()
A sort of recursive call, still a combination of Geoffrey's suggestion, and batches. This has a theoretical limit of 50 batches of 49 document sections. So far this has worked in all tests.
The progress meter exists in its own timed call, but as JavaScript prioritises code over UI it does hop. For example 120 documents it will hop just below half way fairly quickly, then a while later jump to almost complete, then complete (effectively 3 hops of a massively fast sequential percentage increases, various tricks suggested have zero effect (forceRepaint() is the latest experiment!).
function startUILock(){
// batch up in groups of 49 documents (51 and more were shown to fail, 49 gives manouvre room)
toggleProgressBar(true);
$('.progress-button').progressInitialize("Building Word");
progressMeter.progressSet(1);
$.blockUI({message: "Building word..."});
setTimeout(forceRepaint, 3000);
}
function forceRepaint(){
var el = document.getElementById('progDiv');
el.style.cssText += ';-webkit-transform:rotateZ(0deg)';
el.offsetHeight;
el.style.cssText += ';-webkit-transform:none';
}
function UIUnlock(insertedCount){
debugger;
var pct = (insertedCount/checkedList.length)*100
//showNotification('Progress percent is: ' + pct);
if (insertedCount !== checkedList.length ){
progressMeter.progressSet(pct);
forceRepaint();
} else {
$.unblockUI();
progressMeter.progressSet(100);
}
}
function writeDocDeffered(){
insertedCounter = 0;
var lastBatch = 0;
var x = 49;
var z = checkedList.length + 1;
if(x > z){
x=z;
}
deferreds = buildDeferredBatch(x, lastBatch);
$.when(deferreds).done(function () {
return;
})
.fail(function () {
//showNotification('One of our promises failed');
});
}
function buildDeferredBatch(batch, lastBatch) {
// this ensures the variables remain as issued - allows use of "bind"
var deferredsa = [];
var docSender = {
defr : $.Deferred(),
POSITION: batch,
LASTPOSITION: lastBatch,
runMe : function(){
this.defr.resolve(writeDocBatchedDeferred(this.POSITION, this.LASTPOSITION, this.defr));
}
}
// small timeout might not be required
deferredsa.push(setTimeout(docSender.runMe.bind(docSender), 10));
return deferredsa;
}
function writeDocBatchedDeferred(batch, lastBatch, defr){
// write the batches using deferred and promises
var x;
var countXMLAdds = lastBatch;
x = 0;
var fileName;
debugger;
// only run if we have data present
if(nameXMLArray.length > 0){
var aryLN = checkedList.length;
// increment through sequentially until we have all values
Word.run(function (context) {
var currentDoc = context.document;
var body = currentDoc.body;
while (countXMLAdds <= batch){
// repeatedly traverse the array to get the next in sequence
while (x < nameXMLArray.length){
if (Number(nameXMLArray[x].position) === countXMLAdds && nameXMLArray[x].useStatus === true){
fileName = nameXMLArray[x].filename;
body.insertOoxml(nameXMLArray[x].xml, Word.InsertLocation.end);
body.insertBreak(Word.BreakType.page, Word.InsertLocation.end);
insertedCounter = countXMLAdds;
var latest = insertedCounter;
var timerIt = {
LATEST: latest,
runMe : function(){
UIUnlock(this.LATEST);
}
}
setTimeout(timerIt.runMe.bind(timerIt),1000);
}
x++;
}
x=0;
countXMLAdds ++;
}
return context.sync().then(function () {
if(countXMLAdds = batch){
var lastBatch = batch + 1;
// set for next batch
var nextBatch = batch + 50;
var totalBatch = checkedList.length + 1;
// do not exceed the total batch
if(nextBatch > totalBatch){
nextBatch=totalBatch;
}
// any left to process keep going
if (nextBatch <= totalBatch && lastBatch < nextBatch){
deferreds = deferreds.concat(buildDeferredBatch(nextBatch, lastBatch));
}
// this batch done
defr.done();
}
});
})
.catch(function (error) {
showNotification('Error: ' + nameXMLArray[x].filename + " " + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
showNotification('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
document.getElementById("showCheck").className = "results";
writeSelections("<b>You just built your document using<br/>the following components:</b><br/>");
}
return defr.promise;
}