Photoshop Scripting: How to make page numbers - javascript

Hello I was wondering if anyone can help me write a Photoshop script that will display a number and save the document incrementally?
I got to here so far:
if(app.documents.length != 0){
var doc = app.activeDocument;
for(i = 0; i < doc.artLayers.length; ++i){
var layer = doc.artLayers[i];
if(layer.kind == LayerKind.TEXT){
layer.textItem.contents = 1;
layer.textItem.size = 20;
}
}
}
But I'm having trouble writing the content with increments. I want it so that the page number on my document increases by 1.

It isn't entirely clear what you are after. This will increment the number shown, but every text layer it encounters will get numbered.
if(app.documents.length != 0){
var doc = app.activeDocument;
var j = 1;
for(i = 0; i < doc.artLayers.length; ++i){
var layer = doc.artLayers[i];
if(layer.kind == LayerKind.TEXT){
layer.textItem.contents = j;
layer.textItem.size = 20;
j++;
}
}
}

Related

createElement and loops [duplicate]

In JavaScript I am creating a grid (the type of grid you see in Photoshop) with HTML tables. The grid size is going to be variable, i.e., changeable by the user, so the size of each grid square must be calculated and divided by the number of pixels available to get an exact size grid.
I've done all this, but I have a problem adding in the necessary table elements to create the grid. My code is in full working order, except when I use the appendChild() function inside a for loop it only ever appends a single child, when it should be appending up to a couple of hundred.
My code:
grid.show = function(event)
{
var e = event;
if(grid.show_grid == false)
{
grid.show_grid = true;
parent.document.getElementById("grid_table").style.display = "block";
// Get grid (table) and create some elements.
grid.get_grid = parent.document.getElementById("grid_table");
grid.tr = parent.document.createElement("tr");
grid.td = parent.document.createElement("td");
// Clear the grid of all squares so we don't have to worry about subtracting anything.
grid.get_grid.innerHTML = "";
// Calculate the number of horizontal and vertical squares.
var horizontal = Math.ceil(grid.total_width / grid.size);
var vertical = Math.ceil(grid.total_height / grid.size);
// This was a nested loop, removed for demonstration.
// Attempting to add 10 "<tr><td></td></tr>" to the table.
for(var j = 0; j < 10; j++)
{
grid.tr.appendChild(grid.td);
}
//console.log(grid.tr);
// Add the elements to the table.
grid.get_grid.appendChild(grid.tr);
}
else
{
grid.show_grid = false;
parent.document.getElementById("grid_table").style.display = "none";
}
}
This only ever returns a single table row with single table data inside, like so:
<tr>
<td></td>
</tr>
I've already looked at this page and this page, and they sound promising but I just can't figure out how to make this work.
EDIT: Code now working, solution:
grid.show = function(event)
{
var e = event;
if(grid.show_grid == false)
{
grid.show_grid = true;
parent.document.getElementById("grid_table").style.display = "block";
grid.get_grid = parent.document.getElementById("grid_table");
grid.tr = null;
grid.td = null;
grid.get_grid.innerHTML = "";
var horizontal = Math.ceil(grid.total_width / grid.size);
var vertical = Math.ceil(grid.total_height / grid.size);
for(var i = 0; i < vertical; i++)
{
grid.tr = parent.document.createElement("tr");
for(var j = 0; j < horizontal; j++)
{
grid.td = parent.document.createElement("td");
grid.td.width = grid.size;
grid.td.height = grid.size;
grid.tr.appendChild(grid.td);
}
grid.get_grid.appendChild(grid.tr);
}
}
else
{
grid.show_grid = false;
parent.document.getElementById("grid_table").style.display = "none";
}
}
You are appending the same element over and over. You need to call document.createElement each time you wish to have a new element.
EDIT: If the element setup is really complicated and potentially includes children then you can also use Node.cloneNode
If you want to make one copy of the element, you will need to clone it. Use cloneNode()
So change
grid.tr.appendChild(grid.td);
to
grid.tr.appendChild(grid.td.cloneNode(true));
for(var j = 0; j < 10; j++)
{
grid.tr.appendChild(grid.td);
}
should be
for(var j = 0; j < 10; j++) {
var newTd = parent.document.createElement('td');
grid.tds.push(newTd); // if you need it, not sure why though
grid.tr.appendChild(newTd);
}

Hide/Show div p5.js

I am using the p5.js library, and I am working on a speech recognition - text to speech project. Kind of a chatbot.
Input is voice input which becomes a string.
I am outputting the result from a txt file, using a markov chain. Output is a string contained in a div.
My question is:
Is there a way to hide/show the div containing my input/output (.myMessage and .robotMessage) in intervals?
I want the whole screen first showing only the input when I am talking, then input disappears and only output showing, then when the computer voice finishes speaking my input is shown in the screen and so on...
Here some parts of the code, let me know if it is clear enough.
//bot
function setup() {
noCanvas();
//reads and checks into the text file
for (var j = 0; j < names.length; j++) {
var txt = names[j];
for (var i = 0; i <= txt.length - order; i++) {
var gram = txt.substring(i, i + order);
if (i == 0) {
beginnings.push(gram);
}
if (!ngrams[gram]) {
ngrams[gram] = [];
}
ngrams[gram].push(txt.charAt(i + order));
}
}
//voice recognition
let lang = 'en-US';
let speechRec = new p5.SpeechRec(lang, gotSpeech);
let continuous = true;
let interim = false;
speechRec.start(continuous, interim);
//text-to-speach
speech = new p5.Speech();
speech.onLoad = voiceReady;
function voiceReady() {
console.log('voice ready');
}
//input-ouput
function gotSpeech() {
if (speechRec.resultValue) {
var p = createP(speechRec.resultString);
p.class('myMessage');
}
markovIt();
chooseVoice();
speech.speak(answer);
}
}
and
function markovIt() {
var currentGram = random(beginnings);
var result = currentGram;
for (var i = 0; i < 100; i++) {
var possibilities = ngrams[currentGram];
if (!possibilities) {
break;
}
var next = random(possibilities);
result += next;
var len = result.length;
currentGram = result.substring(len - order, len);
}
var answer = result;
window.answer = answer;
var p2 = createP(answer);
p2.class('robotMessage');
}
how the HTML looks
<div class="container">
<div class="myMessage"></div>
<div class="robotMessage"></div>
</div>
Use select() to get a document element by its id, class, or tag name. e.g:
let my_div = select("myMessage");
Change the style of an element by style().
e.g hide:
my_div.style("display", "none");
e.g. show:
my_div.style("display", "block");
See also Toggle Hide and Show

Create a random array to compare between the users array and flashes on a simon says game

i'm bulding a simon game as a student work project in school. i bulit the "card game "Dynamically by entering cell's to a table in pure js now i would want to make the "card game " to flash in a Random Sequence so i had created a random var and add a classList to evry random but here is the problem
1) i would want to creat a random array to compare between the users array when playing and it seems that i cant do a classLiss.add() to it
2)i would want to "flash" the "cards game" that evry time it will flash once and NOT at the same time (and also at the first turn it will flashh once and at the second turn it will flash Twice {not on the same time.exc}) i did use a setTimeout function to remove classList
Here is the code for "card display" and random function:
function cards(user) {
userchioce = parseInt(user.value);
if (userchioce == 4) {
var table = document.getElementById("mytable");
document.getElementById("mytable").innerHTML = "";
for (var i = 0; i < 2; i++) {
var row = table.insertRow(0);
for (var j = 0; j < 2; j++) {
var cell = row.insertCell(-1);
}
}
var t = document.getElementById("mytable");
var idnum = 0;
counter = 0;
for (var r = 0; r < t.rows.length; r++) { //luop at length of rows
for (var c = 0; c < t.rows[r].cells.length; c++) { //luop at length of rows and cells
t.rows[r].cells[c].style.backgroundColor = colorarry[counter];
t.rows[r].cells[c].innerHTML = colorarry1[counter];
t.rows[r].cells[c].setAttribute("class", "td1");
t.rows[r].cells[c].setAttribute("id", "tdd" + idnum++);
counter++;
}
}
}
counter = 0;//end of if 4
function getrandom(rnd) {
rnd = Math.floor(Math.random() * userchioce);
var id = "tdd";
var fullid = id + rnd;
var dispaly = document.getElementById(fullid);
dispaly.classList.add("flash");
{
setTimeout(function () {
dispaly.classList.remove("flash");
}, 850);
}
}
Alright, let's clean up a little first. You are creating looping to create the cells, then looping again to modify them, you should just modify them right away.
if (userchioce == 4) {
var table = document.getElementById("mytable");
document.getElementById("mytable").innerHTML = "";
var idnum = 0;
for (var i = 0; i < 2; i++) {
var row = table.insertRow(0);
for (var j = 0; j < 2; j++) {
var cell = row.insertCell(-1);
cell.style.backgroundColor = colorarry[idnum];
cell.innerHTML = colorarry1[idnum];
cell.setAttribute("class", "td1");
cell.setAttribute("id", "tdd" + idnum++);
}
}
}
I've also removed the counter variable in favour to the idnum variable. They were both defined at 0 at the same place, and also incremented at the same pace...
You do not get to display the lights one after the other because you only do it once. There should be a place where you keep track of the previous randoms.
var moves = [];
function newTurn() {
var rnd = Math.floor(Math.random() * userchioce);
// Add the new random to the moves history.
moves.push(rnd);
//create a copy, we'll be playing with it.
var movesToShow = moves.slice();
showMove();
}
function showMove(moveList){
//Remove first value of the list of moves and use it to show.
var move = moveList.shift();
var id = "tdd";
var fullid = id + move;
var display= document.getElementById(fullid);
display.classList.add("flash");
//Wait a little before removing the hightlight.
setTimeout(function () {
display.classList.remove("flash");
if(moveList.length>0){
//There are more moves, wait just a little
setTimeout(function(){
//Display a new move.
showMove(moveList);
},100);
}
}, 850);
}
// call this to start a new turn.
newTurn();
Also, I would like to urge you to correct all the typos in your script. "dispaly","userchioce" this will make things very hard for you to follow.

PDF content logic manipulation

Pdf content should always have two div on one page. Only if the content of div is to long, then there can be one div per page, but on next page, it should again be two, again, if the content allows. But that is the rule, show two content, one if content is to long. So I started to work with the javascript, to check the elements height.
let attributeDivs = document.getElementsByClassName("attributeDiv");
for(var i = 0; i < attributeDivs.length; i++) {
var twoElementsOffsetHeight = attributeDivs[i].offsetHeight + attributeDivs[i + 1].offsetHeight;
if (twoElementsOffsetHeight > 550) {
attributeDivs[i].style.pageBreakAfter = "always";
}
}
What this does is check if the two contents are to long, then it will do the page break on the first content.
But the problem is that content can be so small, that 4 of them are smaller then 550. So this is not good. Then I tried to break every second content to see can I work something with that:
for(var i = 0; i < attributeDivs.length; i++) {
var twoElementsOffsetHeight = attributeDivs[i].offsetHeight + attributeDivs[i + 1].offsetHeight;
if (i % 2) {
attributeDivs[i].style.pageBreakAfter = "always";
}
}
But then is the problem if the first is to long, it will break the content on the second page, even if it is small one.
Also, I noticed now that javascript does not calculate the hole element if the content goes on the second page. Only the content on the one page get offsetHeight.
How to approach this task?
just use a counter like this:
let attributeDivs = document.getElementsByClassName("attributeDiv");
var counter = 0; // <--- this is new
for(var i = 0; i < attributeDivs.length; i++) {
var twoElementsOffsetHeight = attributeDivs[i].offsetHeight + attributeDivs[i + 1].offsetHeight;
counter += 1; // <--- this is new
if (twoElementsOffsetHeight > 550) {
attributeDivs[i].style.pageBreakAfter = "always";
counter = 0; // <--- this is new
}else if(counter == 2) // <--- this is new
{
attributeDivs[i].style.pageBreakAfter = "always";
counter = 0;
}
}

How can I get the text to which a Nested Style is applied in InDesign

I am trying to write a script that will convert all characters to lowercase if a particular nested style is applied. I can't seem to figure out the correct syntax to get the text.
I originally tried the following, which worked to an extend, but lowercased the entire paragraph rather than only the text that has the character style applied:
function lowerCaseNest(myPStyle, myCStyle){
var myDocument = app.documents.item(0);
//Clear the find/change preferences.
app.findTextPreferences = NothingEnum.nothing;
app.changeTextPreferences = NothingEnum.nothing;
//Set the find options.
app.findChangeTextOptions.caseSensitive = false;
app.findChangeTextOptions.includeFootnotes = false;
app.findChangeTextOptions.includeHiddenLayers = false;
app.findChangeTextOptions.includeLockedLayersForFind = false;
app.findChangeTextOptions.includeLockedStoriesForFind = false;
app.findChangeTextOptions.includeMasterPages = false;
app.findChangeTextOptions.wholeWord = false;
app.findTextPreferences.appliedParagraphStyle = myPStyle;
var missingFind = app.activeDocument.findText();
var myDoc = app.documents[0];
for ( var listIndex = 0 ; listIndex < missingFind.length; listIndex++ ) {
for (i = missingFind[listIndex].nestedStyles.length-1;i>=0; i--) {
for (j = missingFind[listIndex].nestedStyles[i].parent.characters.length-1;j>=0; j--) {
if (missingFind[listIndex].nestedStyles[i].parent.characters[j].contents.appliedCharacterStyle(myCStyle)) {
var myString = missingFind[listIndex].nestedStyles[i].parent.characters[j].contents;
if (typeof(myString) == "string"){
var myNewString = myString.toLowerCase();
missingFind[listIndex].nestedStyles[i].parent.characters[j].contents = myNewString;
}
}
}
}
app.findTextPreferences = NothingEnum.nothing;
app.changeTextPreferences = NothingEnum.nothing;
}
I then tried playing around with appliedNestedStyles, but can't seem to figure out how to retrieve the text that the nested style is applied to.
Could anyone help with this?
Thanks!
John
Unless I am wrong the appliedNestedStyle can be looked after in the F/C dialog by targeting the applied characterStyle:
GREP
Find : .+
Format : character style => myCharStyle
then
var found = doc.findGrep();
…
I actually took a different tack, and figured out something that works:
function lowerCaseNest(myPStyle, myCStyle){
for (var i = 0; i < app.activeDocument.stories.length; i++){
for (var j = 0; j < app.activeDocument.stories[i].paragraphs.length; j++){
var myP = app.activeDocument.stories[i].paragraphs[j];
if (myP.appliedParagraphStyle.name==myPStyle) {
for (k=0; k<myP.characters.length; k++) {
if(typeof(myP.characters[k].appliedNestedStyles[0]) != 'undefined'){
if(myP.characters[k].appliedNestedStyles[0].name == myCStyle) {
var myC = myP.characters[k].contents;
if (typeof(myC)=='string'){
var myNewString = myC.toLowerCase();
myP.characters[k].contents = myNewString;
}
}
}
}
}
}
}
}
Still would be interested in knowing if there's an easier way to handle this, as I'm afraid this may take longer to run on long documents, since it's dealing with every paragraph individually.

Categories

Resources