Currently working a script to make ALL the texts of a document with some specifics. Glad to say it's already functioning but not completely because it's just working on some of the textframes and not all of them.
The intention is to make the changes on every texts on the active document (point, area, frames, etc) and unfortunately, even when it works on some text frame, not all characters are affected because some special ones like - or + don't get the properties of the other normal characters.
Made some research and do believe I should be working with parentStory maybe? But I didn't figure out how to implement.
Here is my code:
var document = app.activeDocument;
var allTexts = document.textFrames[0];
for (i=0; i<allTexts.words.length; i++) {
allTexts.words[i].characterAttributes.autoLeading = true;
allTexts.words[i].characterAttributes.tracking = 250;
allTexts.words[i].characterAttributes.kerningMethod = AutoKernType.AUTO;
allTexts.words[i].characterAttributes.underline = false;
allTexts.words[i].characterAttributes.strikeThrough = false;
allTexts.words[i].characterAttributes.capitalization = FontCapsOption.NORMALCAPS;
allTexts.words[i].characterAttributes.language = LanguageType.UKENGLISH;
allTexts.words[i].characterAttributes.horizontalScale = 100;
allTexts.words[i].characterAttributes.verticalScale = 100;
allTexts.words[i].characterAttributes.baselineShift = 0;
allTexts.words[i].characterAttributes.rotation = 0;
allTexts.words[i].characterAttributes.baselinePosition = FontBaselineOption.NORMALBASELINE;
allTexts.words[i].characterAttributes.baselineDirection = BaselineDirectionType.Standard;
allTexts.words[i].characterAttributes.alternateGlyphs = AlternateGlyphsForm.DEFAULTFORM;
allTexts.words[i].characterAttributes.antialias = TextAntialias.SHARP;
}
already got helped in a different source by adding textRange to it.
var thisTextFrame;
for(var i = 0; i < app.activeDocument.textFrames.length; i++){
thisTextFrame = app.activeDocument.textFrames[i]
thisTextFrame.textRange.characterAttributes.tracking = 250;
// ...
}
Related
I'm trying to write some code in apps script to pull text from a text box in google slides and split it by paragraphs into new text boxes and I'm hitting a snag when I get to preserving lists. I haven't been successful in finding a simple way to get the listPreset from the paragraphs in the original text box to the paragraphs in their own text boxes.
I was able to use ListStyle() methods getGlyph() and isInList() successfully but unless I make a dictionary of which listPreset each glyph is in, I don't seem to able to retrieve the listPreset with any of the listed methods which I would need in order to fill into applyListPreset().
I'd love a getListPreset() function so I could just nab that from the original list. Is there something like that I'm missing?
Here is an example "before" condition.
Here is an example of the expected "after" condition.
Here is an example of what the "after" condition is when I am unable to duplicate the listStyle from the original text box into the new text boxes.
In the following example I copy the text from the original textbox and gather various attributes from it. I attempt to input the listStyle() information into the applyListPreset() method even though I know that's wrong. I just don't know how else to get the List Preset from the original text box.
FYI I've already had a bit of help with this already so it's not all my work.
function myFunction() { // get slides in the presentation
var slides = SlidesApp.getActivePresentation().getSlides();
var numberOfLogs = 5;
for (let slide of slides) { // get the objects on each slide
splitParagraphs(slide);
}
}
function splitParagraphs(slide){
slideShapes = slide.getShapes();
for(let shape of slideShapes){
var shapetype = shape.getShapeType();
if (shapetype == "TEXT_BOX"){ // checks to see if the object is a text box
createSplitShapes(shape, slide);
shape.remove();
}
}
}
function createSplitShapes(shape, slide){
var paragraphs = shape.getText().getParagraphs();
var oldHeight = shape.getHeight();
var width = shape.getWidth();
var newShapeHeight = oldHeight / paragraphs.length;
for (let [index, paragraph] of paragraphs.entries() ){ // make a textbox for each paragraph distributed vertically over the original textbox
createParagraphShapes(shape, index, paragraph, newShapeHeight, width, slide);
}
}
function createParagraphShapes(shape, index, paragraph, shapeheight, width, slide){
var text = paragraph.getRange();
var list = text.getListStyle().isInList();
var style = text.getListStyle();
var glyph = text.getListStyle().getGlyph();
var rawText = text.asString();
var textStyle = text.getTextStyle();
var fontsize = textStyle.getFontSize();
var fontfamily = textStyle.getFontFamily();
var fontweight = textStyle.getFontWeight();
var paragraphStyle = text.getParagraphStyle();
var alignment = paragraphStyle.getParagraphAlignment();
var lineSpacing = paragraphStyle.getLineSpacing();
var indent = paragraphStyle.getIndentStart();
var shapetop = shapeheight * index + shape.getTop();
if ( ! isBlank(rawText) ) {
var t = slide.insertTextBox(rawText);
t.setLeft(shape.getLeft());
t.setTop(shapetop);
t.setWidth(width);
var newTextStyle = t.getText().getTextStyle();
newTextStyle.setFontSize(fontsize);
newTextStyle.setFontFamilyAndWeight(fontfamily, fontweight);
var newParagraphStyle = t.getText().getParagraphStyle();
newParagraphStyle.setParagraphAlignment(alignment);
newParagraphStyle.setLineSpacing(lineSpacing);
newParagraphStyle.setIndentStart(indent);
if (list = true) {
t.getText().getListStyle().applyListPreset(style);
}
}
}
function paragraphLogs(paragraph, numberOfLogs){
if(numberOfLogs > 0){
console.log("\tWhat's in paragraphs?: ");
for (var k = 0; k < paragraph.length; k++){
console.log("\t\t" + ( paragraphs[k].getRange().asString() ) );
}
}
}
function isBlank(str){
return (!str || str.trim().length === 0);
}
I am creating a mock blog where I will be appending the posts via the JavaScript file. I currently have it set up so that a search button will work to only show posts with the same text in the search bar. Now, I want the posts to have the found word highlighted.
HTML:
<div id= "custom_blog_div"></div>
JS:
if (document.getElementById("custom_blog_div")) {
//Blog Post 2
var post_2_div = document.createElement("div");
post_2_div.setAttribute("id", "post_2_div");
post_2_div.setAttribute("class", "post_div");
custom_blog_div.appendChild(post_2_div);
// Header
var post_2_Header = document.createElement("h2");
var post_2_Header_Text = document.createTextNode("Welcome, and Pardon the Construction!");
post_2_Header.setAttribute("class", "blog_post_header");
post_2_Header.appendChild(post_2_Header_Text);
post_2_div.appendChild(post_2_Header);
// Date
var post_2_Date = document.createElement("p");
var post_2_Date_Text = document.createTextNode("January 2, 2018 12:00 am");
post_2_Date.setAttribute("class", "blog_post_date");
post_2_Date.appendChild(post_2_Date_Text);
post_2_div.appendChild(post_2_Date);
// Blog
var post_2_Blog = document.createElement("p");
var post_2_Blog_Text = document.createTextNode("This is a Left Image:");
var post_2_Blog_Image_1 = document.createElement("img");
post_2_Blog.setAttribute("class", "blog_post_text");
post_2_Blog_Image_1.setAttribute("class", "Left_Image");
post_2_Blog_Image_1.setAttribute("width", "100px");
post_2_Blog_Image_1.setAttribute("src", "./series images/main series/spirit legends issue 5/Spirit Legends 5 - Cover.jpg")
post_2_Blog.appendChild(post_2_Blog_Text);
post_2_Blog.appendChild(post_2_Blog_Image_1);
post_2_div.appendChild(post_2_Blog);
// Blog Post 1
var post_1_div = document.createElement("div");
post_1_div.setAttribute("id", "post_1_div");
post_1_div.setAttribute("class", "post_div");
custom_blog_div.appendChild(post_1_div);
// Header
var post_1_Header = document.createElement("h2");
var post_1_Header_Text = document.createTextNode("Welcome, and Pardon the Construction!");
post_1_Header.setAttribute("class", "blog_post_header");
post_1_Header.appendChild(post_1_Header_Text);
post_1_div.appendChild(post_1_Header);
// Date
var post_1_Date = document.createElement("p");
var post_1_Date_Text = document.createTextNode("January 2, 2018 12:00 am");
post_1_Date.setAttribute("class", "blog_post_date");
post_1_Date.appendChild(post_1_Date_Text);
post_1_div.appendChild(post_1_Date);
// Blog
var post_1_Blog = document.createElement("p");
var post_1_Blog_Text = document.createTextNode("Hi, and welcome to the official Spirit Legends website! The site is live in order to test out certain things, but as you can see, it is very much incomplete. Please look forward to the complete site in the future!");
post_1_Blog.setAttribute("class", "blog_post_text");
post_1_Blog.appendChild(post_1_Blog_Text);
post_1_div.appendChild(post_1_Blog);
}
// Search Bar button
document.getElementById("search_news_button").onclick = function() {
var all_blogs = document.getElementById("custom_blog_div").querySelectorAll(".post_div");
var text_field = document.getElementById("search_news_button_text").value.toLowerCase();
var custom_blog = document.getElementById("custom_blog_div");
// Restore all Blog Posts before searching
for (i = 0; i < all_blogs.length; i++) {
if (all_blogs[i].style.display === "none") {
all_blogs[i].style.display = "inline";
}
}
// Loop through all Blog posts
for (i = 0; i < all_blogs.length; i++) {
// Display all Blog posts containing the text in the Search Bar
if (all_blogs[i].innerText.toLowerCase().includes(text_field) === true) {
all_blogs[i].style.display = "inline";
var x = "";
for (x = 0; x < custom_blog.innerText.length; x++) {
if (custom_blog[x].innerText.toLowerCase().includes(text_field) === true) {
x = custom_blog[x].innerText.toLowerCase();
x.style.backgroundColor = "yellow";
}
}
// Highlight the found text in each blog post
var x = "";
for (x = 0; x < custom_blog.innerText.length; x++) {
if (custom_blog[x].innerText.toLowerCase().includes(text_field) === true) {
x = custom_blog[x].innerText.toLowerCase();
x.style.backgroundColor = "yellow";
}
}
// Otherwise, if no Blog posts contain the text in the Search Bar or if Search Bar is empty, display the default
} else {
all_blogs[i].style.display = "none";
}
}
}
So, like I said, the blog is working, and the search button is working, but I cannot figure out how to get the searched word highlighted. Currently, this code results in the console telling me "TypeError: custom_blog[x] is undefined".
And, if it helps, the website is http://spiritlegendsofficial.com/ but this feature hasn't been added yet. Although you can look at the rest of the site's code on there and get some context for this mock blog.
Thanks!
Assuming custom_blog is an HTMLElement type, custom_blog[0] would represent the first child node of that HTMLElement. If you check that your variable custom_blog is defined in a javascript console, but custom_blog[x] isn't defined, it basically means your <div id= "custom_blog_div"></div> has no child elements.
I think your issue is somewhere in the loop that's grabbing your text for highlighting. You're checking the length of the string, but inside the loop you're attempting to target a child node in a case where there may not be one. You might want to change the for loop's condition for continuing to be based on the number of nodes instead:
if (custom_blog.hasChildNodes()) {
var children = custom_blog.childNodes;
for (x = 0; x < children.length; x++) {
if (children[x].innerText.toLowerCase().includes(text_field) === true) {
x = children[x].innerText.toLowerCase();
x.style.backgroundColor = "yellow";
}
}
}
For more info on childNodes: https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes
As an experiment for a larger project, I am trying to make a text battle (it's in progress). What I need is when I press the button, it prints the text into a <p> tag. Also, it makes two buttons, one that says ATTACK and the other says SPARE. How would I
disable the initial onclick event from the button so I don't keep on making new buttons
add an onclick event to the new ones so I could run a different function.
This is my code:
HTML:
<button id = 'button' onclick='enemy()'>button</button>
And my JavaScript:
// PLAYER
var playerHP = 100;
var playerAt = 10;
var playerDef = 0;
//ENEMY
var enemyHP = 50;
var enemyAt = 5;
//FIGHT
function enemy() {
document.getElementById("test").innerHTML = "You encounter a wild MONSTER(AT:5 ¦ HP:50). Will you attack?";
for (var i = 0; i < 1; i++) {
var btnAt = document.createElement('BUTTON');
var t = document.createTextNode('Attack!');
btnAt.appendChild(t);
document.body.appendChild(btnAt);
var btnSp = document.createElement('BUTTON');
var d = document.createTextNode('Spare!');
btnSp.appendChild(d);
document.body.appendChild(btnSp);
}
}
Ignore some of the stuff- its for future use.
P.S. No jQuery, please, unless it is unavoidable.
something like this using .Disabled to disable the button, so you dont have to clear out the onclick for later use. and just set .onclick to whatever function you want on the button you built. I also recommend not trying to avoid jquery... Once you start using it, you can relize how much easier it can make your life. Also, why the loop?
// PLAYER
var playerHP = 100;
var playerAt = 10;
var playerDef = 0;
//ENEMY
var enemyHP = 50;
var enemyAt = 5;
//FIGHT
function enemy() {
document.getElementById("test").innerHTML = "You encounter a wild MONSTER(AT:5 ¦ HP:50). Will you attack?";
var btnAt = document.createElement('BUTTON');
//set onlick for button
btnAt.onclick = function()
{
//do stuff here
}
var t = document.createTextNode('Attack!');
btnAt.appendChild(t);
document.body.appendChild(btnAt);
var btnSp = document.createElement('BUTTON');
var d = document.createTextNode('Spare!');
btnSp.appendChild(d);
document.body.appendChild(btnSp);
//disable button
var originalbtn = document.getElementById("button").disabled = true;
}
I am trying to write a script (because I can't find one that works) that will export all my separate layers, paths, etc to transparent png files. I have seen many scripts, but all of them do not export all the layers, etc. They seem to just try and export parent layers. So if there are sub layers, these are missed.
Here is my script:
var doc = app.activeDocument;
var counter = 0;
hideOrShowItems(doc, false);
// processLayers(doc);
// displayLayer(doc, true);
function hideOrShowItems(root, show) {
for(var i = 0; i < root.layers.length; i++) {
var layer = root.layers[i];
var pathCount = layer.pathItems.length;
var layerCount = layer.layers.length;
if (pathCount > 0) {
hideOrShowPaths(layer, show);
}
if (layerCount > 0) {
hideOrShowItems(layer, show);
}
layer.visible = show;
}
}
function hideOrShowPaths(root, show) {
for(var i = 0; i < root.pathItems.length; i++) {
root.pathItems[i].visible = show;
}
}
// -- Removed for brievety
When I run the script, the only thing that gets hidden is the top layer
All of the rest are untouched.
I put a counter in and did counter++ in the for loop of hideOrShowPaths and it counts 246, so I know it can see the paths and is actually trying to hide them, but they stay visible.
Has anyone done this before? Can I hide paths, groups, clips and export them all as pngs? or will I have to do this manually?
Looks like the flag you are looking for is hidden not visible.
var doc = app.activeDocument;
var root = doc.layers[0];
// just for testing purpose. Change the color
var newRGBColor = new RGBColor();
newRGBColor.red = 255;
newRGBColor.green = 255;
newRGBColor.blue = 255;
// make all items hidden
for (var i = 0; i < root.pathItems.length; i++) {
var item = root.pathItems[i];
item.hidden = true;
item.fillColor = newRGBColor; // just for testing
}
// now loop all pathItems
for (var i = 0; i < root.pathItems.length; i++) {
var item = root.pathItems[i];
item.hidden = !item.hidden; //make one visible
// export visible part
redraw();
item.hidden = !item.hidden; // hide it again
}
In your script you will need to hide every item first, then unhide one, export and hide it again.
I Hope that snippet helps with your problem
I've written a fairly simple script that will take elements (in this case, <p> elements are the main concern) and type their contents out like a typewriter, one by one.
The problem is that as it types, when it reaches the edge of the container mid-word, it reflows the text and jumps to the next line (like word wrap in any text editor).
This is, of course, expected behavior; however, I would like to pre-format the text so that this does not happen.
I figure that inserting <br> before the word that will wrap would be the best solution, but I'm not quite sure what the best way to go about doing that is that supports all font sizes and container widths, while also keeping any HTML tags intact.
I figure something involving a hidden <span> element, adding text to it gradually and checking its width against the container width might be on the right track, but I'm not quite sure how to actually put this together. Any help or suggestions on better methods would be appreciated.
Edit:
I've managed to write something that sort of works using jQuery, although it's very sloppy, and more importantly, sometimes it seems to skip words, and I can't figure out why. #content is the name of the container, and #ruler is the name of the hidden <span>. I'm sure there's a much better way to do this.
function formatText(html) {
var textArray = html.split(" ");
var assembledLine = "";
var finalArray = new Array();
var lastI = 0;
var firstLine = true;
for(i = 0; i <= textArray.length; i++) {
assembledLine = assembledLine + " " + textArray[i];
$('#ruler').html(assembledLine);
var lineWidth = $('#ruler').width();
if ((lineWidth >= $('#content').width()) || (i == textArray.length)) {
if (firstLine) { var tempArray = textArray.slice(lastI, i); }
else { var tempArray = textArray.slice(lastI+1, i); }
var finalLine = tempArray.join(" ");
finalArray.push(finalLine);
assembledLine = "";
if (lineWidth > $('#content').width()) { i = i-1; }
lastI = i;
firstLine = false;
}
}
return finalArray.join("<br>");
}
You could use the pre tag: Which displays pre-formatted text, or you could put the content into a div tag, set a fixed width, and script based upon that.
The best way (IMO) would be to add the whole word, but have the un-"typed" letters invisible. E.g:
H<span style="visibility: hidden;">ello</span>
He<span style="visibility: hidden;">llo</span>
Hel<span style="visibility: hidden;">lo</span>
Hell<span style="visibility: hidden;">o</span>
Hello
To make it easier, give the span a name, and delete it from the DOM each time.
A possible approach is to set p display inline (because default display-block will make p to consume all width even if it has just 1 character) and then as you 'type' check the element width.
Set a tolerance in px (25px for example) and once p's width reaches total available width minus width tolerance you insert <br />
I think this should work...
After playing with the code I edited into the question, I managed to get it working decently.
Code:
function formatText(html) {
var textArray = html.split(" ");
var assembledLine = "";
var finalArray = new Array();
var lastI = 0;
var firstLine = true;
for(i = 0; i <= textArray.length; i++) {
assembledLine = assembledLine + " " + textArray[i];
$('#ruler').html(assembledLine);
var lineWidth = $('#ruler').width();
if ((lineWidth >= $('#content').width()) || (i == textArray.length)) {
if (firstLine) { var tempArray = textArray.slice(lastI, i); }
else { var tempArray = textArray.slice(lastI+1, i); }
var finalLine = tempArray.join(" ");
finalArray.push(finalLine);
assembledLine = "";
if (lineWidth >= $('#content').width()) { i = i-1; }
lastI = i;
firstLine = false;
}
}
return finalArray.join("<br>");
}
Not perfect, but it'll do. Thanks, everyone.