Reordering/move pages using Indesign script - javascript

I have a nearly 400 page document that I need to [randomly] reorder the pages. (If you need to know, this is a book of single page stories that need to be randomly distributed. I created a random list of pages to input into the script.)
I've been working with a modified script I found elsewhere on the internet that creates an array and moves the pages around:
var order="...list of new page numbers...";
// Create an array out of the list:
ranges = toSeparate (order);
if (ranges.length != app.activeDocument.pages.length)
{
alert ("Page number mismatch -- "+ranges.length+" given, "+app.activeDocument.pages.length+" in document");
exit(0);
}
// Consistency check:
sorted = ranges.slice().sort(numericSort);
for (a=0; a<sorted.length-1; a++)
{
if (sorted[a] < sorted[a+1]-1 ||
sorted[a] == sorted[a+1])
alert ("Mismatch from "+sorted[a]+" to "+sorted[a+1]);
}
// alert ("New order for "+order+"\nis "+ranges.join(", "));
// Convert from 1..x to 0..x-1:
for (moveThis=0; moveThis<ranges.length; moveThis++)
ranges[moveThis]--;
for (moveThis=0; moveThis<ranges.length; moveThis++)
{
if (moveThis != ranges[moveThis])
{
try{
app.activeDocument.pages[ranges[moveThis]].move (LocationOptions.BEFORE, app.activeDocument.pages[moveThis]);
} catch(_) { alert ("problem with page "+moveThis+"/index "+ranges[moveThis]); }
}
for (updateRest=moveThis+1; updateRest<ranges.length; updateRest++)
if (ranges[updateRest] < ranges[moveThis])
ranges[updateRest]++;
}
function toSeparate (list)
{
s = list.split(",");
for (l=0; l<s.length; l++)
{
try {
if (s[l].indexOf("-") > -1)
{
indexes = s[l].split("-");
from = Number(indexes[0]);
to = Number(indexes[indexes.length-1]);
if (from >= to)
{
alert ("Cannot create a range from "+from+" to "+to+"!");
exit(0);
}
s[l] = from;
while (from < to)
s.splice (++l,0,++from);
}} catch(_){}
}
// s.sort (numericSort);
return s;
}
function numericSort(a,b)
{
return Number(a) - Number(b);
}
This code worked, except that it was consistently rearranging them into the wrong random order, which, at the end of the day, is workable, but it'll just be a bigger pain in the ass to index the stories.
I suspected the problem might be caused by starting at the begginning of the document rather than the end, so I modified the script to start at the end, but then app.activeDocument.pages[ranges[moveThis]] kept coming up as undefined.
So I gave up and tried this:
app.activeDocument.pages[298].move (LocationOptions.BEFORE, app.activeDocument.pages[366]);
app.activeDocument.pages[33].move (LocationOptions.BEFORE, app.activeDocument.pages[365]);
app.activeDocument.pages[292].move (LocationOptions.BEFORE, app.activeDocument.pages[364]);
And so on for every page. (This reminds me of my time in junior high using sendKeys to create programs in Visual Basic. Had I bothered to seriously learn JavaScript instead of creating shitty AOL chatroom scrollers, I probably wouldn't be on here today.)
Nevertheless, I received the following error:
Error Number: 30477
Error String: Invalid value for parameter 'reference' of method 'move'. Expected Page or Spread, but received nothing.
I'm trying to avoid having to manually move the pages, especially considering the amount of time I've already been working on this. Any suggestions on what I need to change? Thank you!

The issue might be that you are using more than one page per spread and then trying to shuffle them across spread. The better way is to use single page per spread.
Here is a small snippet that works on my machine
var doc = app.activeDocument;
doc.documentPreferences.facingPages = false;
for (var i =0; i < 100; i++){
var index = parseInt((Math.random() * doc.spreads.length) % doc.spreads.length + '' , 10);
doc.spreads[index].move();
}
What this does is
Disables the facing pages options and makes one page per spread. A desirable condition as you mentioned that your stories are one page each(I am assuming that your stories will not violate this assumption).
Takes a random spread from the doc and sends it to the end of the spreads in the doc. It does so 100 times.
The result is what you wanted. A script to shuffle the current SPREADS randomly.

Related

How do i fix the wrong integration of an automatic transfer of rows between sheets?

What I'm trying to accomplish is:
have a data input sheet called 'data' (its data is fed by a form)
script moves the information from data to sheet1/sheet2/.../sheetn (according to a string that is to be found in column 3)
script also deletes moved rows
I think the deleteRow command works fine, i suspect the culprit being the detection of the string in the array.
I've already used the search a lot, tried a few codes and I've identified this as the most probable candidate (its by cooper), as it's almost doing what i need it to do.
I tried logging a bit, but unfortunately i dont know too much about coding yet. Currently im learning by trial and error.
If i log for vals[i][2] i only get 1 string, instead of a few from my example input.
When i set only one targetsheet (sh1) and target-term it works. but when i extend it it doesnt work anymore.
{
var ss=SpreadsheetApp.getActive();
var sh0=ss.getSheetByName('Data');
var rg0=sh0.getDataRange();
var sh1=ss.getSheetByName('Applesheet');
var sh2=ss.getSheetByName('Banana');
var sh3=ss.getSheetByName('Cherry');
var vals=rg0.getValues();
Logger.log(vals)
for(var i=vals.length-1;i>0;i--)
{
if(vals[i][2]=='Apple')
Logger.log("PV Abfrage -", vals[i][2])
{
sh1.appendRow(vals[i]);
sh0.deleteRow(i+1);
}
if(vals[i][2]=='Banana') //also tried with else if here
{
sh2.appendRow(vals[i]);
sh0.deleteRow(i+1);
}
if(vals[i][2]=='Cherry')
{
sh3.appendRow(vals[i]);
sh0.deleteRow(i+1);
}
}
}
My code moves rows that dont contain any of the terms.
It's also supposed to only move rows that contain this term, but its doing so super unrealiably.
I think all rows get appended to Applesheet, rows that contain banana are moved to banana but the ones with cherry wont.
Im definitely not experienced enough to judge, but this code seems a bit unreliable, because even my test version with just one if fails to perform the way i want it to.
Issue:
Your first if statement is forced to return true by the Logger.log() you've included between if and {. As soon as you remove it, your code functions exactly as you're expecting.
Example:
If we run the following script:
var check = ['Apple', 'Pear', 'Fruit'];
for (i = 0; i < check.length; i++) {
if (check[i] === 'Apple') {
console.log('Found!');
}
}
We're looping through an array, and logging "Found!" for every time the item in the array is found. This is the same way your script works. It works as expected, "Apple" is only found once in the array, so the log looks like this:
Found!
As soon as we put a log between the if and the {, like so:
var check = ['Apple', 'Pear', 'Fruit'];
for (i = 0; i < check.length; i++) {
if (check[i] === 'Apple')
console.log("Oops!")
{
console.log('Found!');
}
}
We get the following:
Oops!
Found!
Found!
Found!
Summary:
Make sure to only include your conditions for the if statement between your if and {, adding anything else can return false positives like you've experienced today.
Reference:
JavaScript if Statements

Copying & Modifying specific values from each Form submit when copying to another sheet

I got a situation where 2 independent parties need access to the same data, but their back-end that uses the data needs a different format, e.g. one party needs to see "Soccer", the other needs to see "1".
This input comes from various users through a Google Form.
I previously ran a time interval script that would copy over all data from sheet 1, then copy it to sheet 2, then a double loop would kick (using var i) in to search all columns and replace specific strings on sheet 2 with a numeric value.
This script worked, but due to it's inefficiency it started to crash once I started to have more data.
So I am trying to reduce the dataset by just handling the data that comes from each individual Form Submit.
I tried 2 different approaches:
1) Grab values to copy, modify values, then copy to new sheet
2) Grab values to copy, copy to new sheet, then modify these new values (lastrow)
I know the copy bit works in both scripts I wrote but my modification does not, when using the debugger it shows me the modified data is same as the original and this is in fact what happens the copy is identical.
I realize I am probably making a very basic mistake, but I am blind as to what it is. Searching for similar threads on Stackoverflow and other sites I did not come to a resolution.
Current code:
function onFormSubmit(e){
var responses = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var projects = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var row = responses.getLastRow();
var col = responses.getLastColumn();
var copy = responses.getRange(row, 1, 1, col)
var modify = copy.getValues();
for (var i=0; i < modify.length; i++){
if (modify [i] == "SearchString1"){
modify [i] = "1";
}
else if (modify [i] == "SearchString2"){
modify [i] = "0";
}
else if (modify [i] == "SearchString3"){
modify [i] = "1";
}
projects.appendRow(modify);
}
}
This code will copy the data, but not modify it.
I had a variation where i used .setvalues but that resulted in the same end result.
Solved, it was all about location identifiers.
The getvalues created a double array and the append was in the loop instead of outside of it. I had to specify the append and modification better.
Fixed code:
for (var i=0; i < modify[0].length; i++){
if (modify[0][i] == "SearchString1"){
modify[0][i] = "1";
}
else if (modify[0][i] == "SearchString2"){
modify[0][i] = "0";
}
else if (modify[0][i] == "SearchString3"){
modify[0][i] = "1";
}
}
projects.appendRow(modify[0]);
}

Javascript runs out of memory major browsers due to array size

I am trying to create an array, that will be MAASSSIVVEE...i read somewhere that javascript can create an array of up to 4.xx Billion or so. The array i am trying to create will likely be in the quadrillions or higher. I don't even know where to go from here. I am going to assume that JS is not the proper solution for this, but i'd like to give it a try...it is for client side, and i would prefer not to bog down my server with this if there are multiple people using it at once. Also, not looking to learn a new language as i am just getting into JS, and code in general.
could i possibly use setTimeout(),0 breaks in the totalcombos function? Time is not really an issue, i wouldn't mind if it took a few minutes to calculate, but right now it just crashes.
i have tried this using a dedicated worker, but it still crashes the host. the worker code is what i am posting, as the host code is irrelevant to this question (it only compiles the original objects and posts them, then receives the messages back).
The code: (sorry for the mess...im coding noob and just an enthusiast)
onmessage = function(event){
//this has been tested on the very small sample size below, and still runs out of memory
//all the objects in these first arrays are formatted as follows.
// {"pid":"21939","name":"John Smith","position":"QB","salary":"9700","fppg":"23"}
// "PID" is unique to each object, everything else could appear in another object.
// There are no repeated objects.
var qbs = **group of 10 objects like above**
var rbs = **group of 10 objects like above**
var wrs = **group of 10 objects like above**
var tes = **group of 10 objects like above**
var ks = **group of 10 objects like above**
var ds = **group of 10 objects like above**
//This code works great and fast with small sets. ie (qbs, rbs, wrs)
function totalcombos() {
var r = [], arg = arguments, max = arg.length-1;
function helper(arr, i) {
for (var j=0; j<arg[i].length; j++) {
var a = arr.slice(0); // clone arr
if(a.indexOf(arg[i][j]) != -1){
j++;
} else
a.push(arg[i][j]);
if (i==max) {
r.push(a);
} else
helper(a, i+1);
}
}
helper([], 0);
return r;
};
//WAY TOO BIG...commented out so as not to crash when run
//var tCom = totalcombos(qbs, rbs, wrs, tes, ks, ds);
//postMessage(tCom.length);
}
When the sets get to be larger like 50 objects in each, it just crashes as it is out of memory. I reduce the set with other code but it will still be very large. How would i fix it?
I am trying to create all the possible combinations and then go through and reduce from there based on total salary of each group.
When working with data, regardless of language or platform, its usually best practice to only load the data that's otherwise you encounter errors or bottlenecks etc. as you are finding.
If your data is being stored somewhere like a Database, a JSON file, or a Web Service or an API etc. (anything basically), you'd be better of searching that set of data to retrieve only that which you need, or to at least reduce the size of the Array data your're trying to traverse.
As an analogy, if you're trying to load the whole internet into memory on a PC with only 2GB of RAM, you're going to have a really bad time. :)

MongoDB: cannot iterate through all data with cursor (because data is corrupted)

Update:
The story is off-topic and the title misleading. The problem is caused by corrupted data set, not cursors, or MongoDB itself. But I would rather like to leave this thread here than to delete it, for that it might help other desperate people.
=== Original story starts here ===
It all starts here: MongoDB: cannot use a cursor to iterate through all the data
I was trying to iterate through a cursor in Java, and it fails because my collection has too many records(~250M). I tried to allocate a new cursor and use cursor.skip to jump back in when the cursor gets timed out but cursor.skip itself times out.
#mnemosyn pointed out the right way for me: break the job into two stages: In the first stage, use a projected cursor to pull only the monotonic _id's of the records. Record the _id's, and then store it somewhere else as "checkpoints". During the second stage, I can then access any chunk of records as a checkpoint recorded.
So I wrote a javascript like this:
db=connect("localhost/twitter");
db.jobScheduler.drop();
for(var i = 0;i<16;++i)
{
db.jobScheduler.save({_id:"s"+i,jobs:[]});
}
var c = db.tweets.find({},{_id:1}).sort({_id:1});
var totalCount = c.count();
var currentBatchSize = 0;
var currentNum = 0;
var currentShard = 0;
var startTid = 0;
var endTid = 0;
var currentTid = 0;
while(true)
{
while(c.hasNext())
{
var doc = c.next()
currentTid = doc._id;
if(currentBatchSize == 0)
{
startTid = doc._id;
}
++currentNum;
++currentBatchSize;
if(currentBatchSize == 50000)
{
currentBatchSize = 0;
endTid = doc._id;
db.jobScheduler.update(
{_id:"s"+currentShard},
{$push:{jobs:[startTid,endTid]}});
currentShard = (currentShard+1)%16;
print(currentNum+"/"+totalCount+"("+currentNum*100/totalCount+"%)");
print("["+startTid+","+endTid+"]");
}
}
if(currentNum != totalCount){
var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
print("Cursor resetted....");
}else
break;
}
if(currentBatchSize != 0)
{
currentBatchSize = 0;
endTid = doc._id;
db.jobScheduler.update(
{_id:"s"+currentShard},
{$push:{jobs:[startTid,endTid]}});
currentShard = (currentShard+1)%16;
}
Considering that simply pulling _id only would still result in timeout, I added a guard like this:
if(currentNum != totalCount){
var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
print("Cursor resetted....");
}else
break;
because when the cursor times out, I don't get an exception but a false cursor.hasNext().
Since I already recorded currentTid when iterating through them, using the range query var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1}); will put me back in position, theoretically. However the poor little program end up like this:
[337242463750201340,345999466677010400]
21800000/253531208(8.598546968624076%)
[345999469818544100,346244305876295700]
Cursor resetted....
Cursor resetted....
Cursor resetted....
It seems to be stuck at the first occurrence of cursor timeout, forever. And the range query is not bringing me back.
Now I'm really confused. Iteration doesn't work. cursor.skip() doesn't work. Range query doesn't work. And what really works with MongoDB? Or is there something I'm doing really wrong?
Any help would be much appreciated!
Update:
I had some discussion with #AsyaKamsky, he helped me to discover the following things:
setting cursor.batchSize() to 10 doesn't work.
The behaviour is not caused by an idle cursor waiting for 10 minutes. The cursor is pulling data rapidly from server, but still gets invalidated.
The real problem is that after it gets invalid in this way, I could never reallocate any usable cursors anymore. All the new cursors refuse to give me data. There is one possible workaround: close the cursor before this happens, and re-allocate one and use range query to jump back.
Experiments ongoing. Updating this thread in real-time :-)
Update: Failed! I tried renewing cursor after reading 50k records every time. It also gets trapped at this magical index 21800000! That's very close to my cursor.skip() failure offset!
Update:
Confirmed the guessing:
c = db.tweets.find().skip(21800000); //works
c = db.tweets.find().skip(21850000); //doesn't work
I'll try binary search on this range to find the magic number.
Update:
Ok... Magic number found.
db.tweets.find().itcount()
->21837006
db.tweets.find().count()
->253531208
Now what? This is really bad.

JavaScript logic - Parsing a textarea

I need to take a textbox that is full of formatted info about accounts and then sort it somehow. I would like to know if it would be ideal (I'm trying to make this as efficient as possible) to parse the info into a two dimensional array, or if I should make account objects that will hold info in fields.
The program is simply meant to format the data so that it can be printed out without having to copy/paste.
So far I have...
function generateOutputfvoc()
{
var accountLines = document.getElementById('accountLines').value;
var accountLinesTemp = accountLines.split(/[\s]/);
for(var i = 0; i < accountLinesTemp.length; i++)
{
if(accountLinesTemp[i].match(/
Edit (1-18-13): Here is an example input. It is basically text copied from a web CRM tool. Note, this example input is something I typed up randomly.
P8B000001234567 stackoverflow Thing 12522225555 444 Active 2005-02-26 CO1000123456
P8B000001234568 stackoverflow Another Thing 444 Active 2005-02-26 CO1000123456
P8B000001234569 stackoverflow Another Thing 556 Active 2005-02-26 CO1000123456
I would like my program to take the text and simply output the text like this:
P8B000001234567 stackoverflow Thing 12522225555 444 Active 2005-02-26 CO1000123456
P8B000001234568 stackoverflow Another Thing 444 Active 2005-02-26 CO1000123456
P8B000001234569 stackoverflow Another Thing 556 Active 2005-02-26 CO1000123456
Also, I would like to know if I should use jQuery variables. I asked this because I have been looking online a lot and I found examples that use code that looks like this:
$check=fcompcheck();
if($check)
{
$output=document.frm1.type.value+" / ";
$output=$output+"Something - "+document.frm1.disco.value+" / ";
Note the: $output variable. The dollar sign indicates a jQuery variable, right?
Thank you for any help you might be able to offer me.
Update (1-19-13): I've taken a shot at it, but I'm making slow progress. I'm used to programming Java and my JavaScript looks too similar, I can tell I'm makings errors.
I'm taking it one step at a time. Here is the logic I'm using now.
Person pastes text into text box and pushes the generate button
Program takes the contents of the text box and parses it into a large array, removing only whitespace
Program then searches for patterns in the text and begins passing values into variables
I am trying to get the program to simply identify the pattern "Summary section collapse Name" because these four words should always be in this sequence. Once it identifies this it will pass the next two array values into first and last name variables. Here's some of the code:
var contactNameFirst, contactNameLast;
// Parse the input box into an array
var inputArr = document.getElementById('inputBox').value.split(/[\s]/);
for(var i = 0; i < inputArr.length; i++)
{
if(inputArr[i] == "Summary" && inputArr[i - 1] == "section" && inputArr[i - 2] == "Collapse" && inputArr[i + 1] == "Name")
{
if(inputArr[i + 2] != "Details")
{
contactNameFirst = inputArr[i + 2];
}
else
{
contactNameFirst = "";
}
if(inputArr[i + 3] != "Details")
{
contactNameLast = inputArr[i + 3];
}
else
{
contactNameLast = "";
}
}
}
document.getElementById('contactNameOutput').innerHTML = contactNameFirst + " " + contactNameLast;
Also, should I create a new post for this now, or keep editing this one?
Your accountLinesTemp is an Array of String, you could use the Array.sort function to sort your array as expected, and then use Array.join to get the full String if necessary.
See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort on MDN for more information.

Categories

Resources