InDesign Server CS6 Scripting - Get TextFrame containing DataMergeField - javascript

I am unable to determine if a DataMergeField is contained within a TextFrame.
var document = app.open('template.indd');
var dataMerge = document.dataMergeProperties;
var field;
for (field in document.dataMergeTextPlaceholders) {
var story = field.parentStory;
var content = story.contents;
var textFrame = story.textFrames.item(0);
//textFrame is null
}
//....
I am attempting to provide wrap, fit, fill options for the textual contents of any DataMergeFields, adjusting them based on the TextFrame dimensions. Without knowing any of the DataMergeFields or TextFrames properties used in the document.

Something like this should work in JS:
var document = app.open('template.indd');
var hs = document.dataMergeTextPlaceholders;
var n = hs.length, h, tf;
while (n--) {
h = hs[n];
if ( h.storyOffset.parentTextFrames.length ) {
tf = h.storyOffset.parentTextFrames[0];
//do something with tf
}
}

I was able to get this to work with the following. I am guessing that using document as opposed to app.documents.item(0) was the issue.
app.open('template.indd');
var phs = app.documents.item(0).dataMergeTextPlaceholders;
var i, textFrame, ph, story;
for (i = 0; i < phs.length; i++) {
ph = phs.item(i);
if (ph instanceof DataMergeTextPlaceholder) {
story = ph.parentStory;
if (story.textFrames.length > 0) {
textFrame = story.textFrames.item(0);
//...
}
}
}

Related

TypeError: Cannot read property "length" from undefined variables

I have worked with code that pulls table information off a site and then places into Google Sheets. While this had worked great for months, it has come to my attention that is has randomly stopped working.
I am getting the message "TypeError: Cannot read property "length" from undefined." From code:
for (var c=0; c<current_adds_array.length; c++) {
I have done extensive searching but cannot come to conclusion as to what is wrong.
Full code seen here:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Get Data')
.addItem('Add new dispatch items','addNewThings')
.addToUi();
}
function addNewThings() {
// get page
var html = UrlFetchApp.fetch("#").getContentText();
// bypass google's new XmlService because html isn't well-formed
var doc = Xml.parse(html, true);
var bodyHtml = doc.html.body.toXmlString();
// but still use XmlService so we can use getDescendants() and getChild(), etc.
// see: https://developers.google.com/apps-script/reference/xml-service/
doc = XmlService.parse(bodyHtml);
var html = doc.getRootElement();
// a way to dig around
// Logger.log(doc.getRootElement().getChild('form').getChildren('table'));
// find and dig into table using getElementById and getElementsByTagName (by class fails)
var tablecontents = getElementById(html, 'formId:tableExUpdateId');
// we could dig deeper by tag name (next two lines)
// var tbodycontents = getElementsByTagName(tablecontents, 'tbody');
// var trcontents = getElementsByTagName(tbodycontents, 'tr');
// or just get it directly, since we know it's immediate children
var trcontents = tablecontents.getChild('tbody').getChildren('tr');
// create a nice little array to pass
var current_adds_array = Array();
// now let's iterate through them
for (var i=0; i<trcontents.length; i++) {
//Logger.log(trcontents[i].getDescendants());
// and grab all the spans
var trcontentsspan = getElementsByTagName(trcontents[i], 'span');
// if there's as many as expected, let's get values
if (trcontentsspan.length > 5) {
var call_num = trcontentsspan[0].getValue();
var call_time = trcontentsspan[1].getValue();
var rptd_location = trcontentsspan[2].getValue();
var rptd_district = trcontentsspan[3].getValue();
var call_nature = trcontentsspan[4].getValue();
var call_status = trcontentsspan[5].getValue();
//saveRow(call_num, call_time, rptd_location, rptd_district, call_nature, call_status);
current_adds_array.push(Array(call_num, call_time, rptd_location, rptd_district, call_nature, call_status));
}
}
saveRow(current_adds_array);
}
//doGet();
function saveRow(current_adds_array) {
// load in sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// find the current last row to make data range
var current_last_row = sheet.getLastRow();
var current_last_row_begin = current_last_row - 50;
if (current_last_row_begin < 1) current_last_row_begin = 1;
if (current_last_row < 1) current_last_row = 1;
//Logger.log("A"+current_last_row_begin+":F"+current_last_row);
var last_x_rows = sheet.getRange("A"+current_last_row_begin+":F"+current_last_row).getValues();
var call_num, call_time, rptd_location, rptd_district, call_nature, call_status;
// iterate through the current adds array
for (var c=0; c<current_adds_array.length; c++) {
call_num = current_adds_array[c][0];
call_time = current_adds_array[c][1];
rptd_location = current_adds_array[c][2];
rptd_district = current_adds_array[c][3];
call_nature = current_adds_array[c][4];
call_status = current_adds_array[c][5];
// find out if the ID is already there
var is_in_spreadsheet = false;
for (var i=0; i<last_x_rows.length; i++) {
//Logger.log(call_num+" == "+last_15_rows[i][0]);
if (call_num == last_x_rows[i][0] && call_time != last_x_rows[i][1]) is_in_spreadsheet = true;
}
Logger.log(is_in_spreadsheet);
//Logger.log(last_15_rows.length);
if (!is_in_spreadsheet) {
Logger.log("Adding "+call_num);
sheet.appendRow([call_num,call_time,rptd_location,rptd_district,call_nature,call_status]);
}
}
}
function getElementById(element, idToFind) {
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null) {
var id = elt.getAttribute('id');
if( id !=null && id.getValue()== idToFind) return elt;
}
}
}
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
sheet.getRange('A2:F').clearContent();}
function getElementsByTagName(element, tagName) {
var data = [];
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null && elt.getName()== tagName) data.push(elt);
}
return data;
}
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("C:C");
range.setValues(range.getValues().map(function(row) {
return [row[0].replace(/MKE$/, " Milwaukee, Wisconsin")];
}));
Please be careful when instantiating a new array. You are currently using var current_adds_array = Array(). You're not only missing the new keyword, but also, this constructor is intended to instantiate an Array with an Array-like object.
Try changing this to var current_adds_array = []

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.

Accessing Stored Object

I have an object "Driver" defined at the beginning of my script as such:
function Driver(draw, name) {
this.draw = draw;
this.name = name;
}
I'm using this bit of JQuery to create new drivers:
var main = function () {
// add driver to table
$('#button').click(function ( ) {
var name = $('input[name=name]').val();
var draw = $('input[name=draw]').val();
var draw2 = "#"+draw;
var name2 = "driver"+draw
console.log(draw2);
console.log(name2);
if($(name2).text().length > 0){
alert("That number has already been selected");}
else{$(name2).text(name);
var name2 = new Driver(draw, name);}
});
That part is working great. However, when I try later on to access those drivers, the console returns that it is undefined:
$('.print').click(function ( ) {
for(var i=1; i<60; i++){
var driverList = "driver"+i;
if($(driverList.draw>0)){
console.log(driverList);
console.log(driverList.name);
}
If you're interested, I've uploaded the entire project I'm working on to this site:
http://precisioncomputerservices.com/slideways/index.html
Basically, the bottom bit of code is just to try to see if I'm accessing the drivers in the correct manner (which, I'm obviously not). Once I know how to access them, I'm going to save them to a file to be used on a different page.
Also a problem is the If Statement in the last bit of code. I'm trying to get it to print only drivers that have actually been inputed into the form. I have a space for 60 drivers, but not all of them will be used, and the ones that are used won't be consecutive.
Thanks for helping out the new guy.
You can't use a variable to refer to a variable as you have done.
In your case one option is to use an key/value based object like
var drivers = {};
var main = function () {
// add driver to table
$('#button').click(function () {
var name = $('input[name=name]').val();
var draw = $('input[name=draw]').val();
var draw2 = "#" + draw;
var name2 = "driver" + draw
console.log(draw2);
console.log(name2);
if ($(name2).text().length > 0) {
alert("That number has already been selected");
} else {
$(name2).text(name);
drivers[name2] = new Driver(draw, name);
}
});
$('.print').click(function () {
for (var i = 1; i < 60; i++) {
var name2 = "driver" + i;
var driver = drivers[name2];
if (driver.draw > 0) {
console.log(driver);
console.log(driver.name);
}

How do I empty global arrays used in a pop up slideshow?

I've created a program where you can choose a set of images by checking checkboxes. The image URL's and the alt-texts are stored in two arrays. When clicking av button on the HTML-page you open a new window that calls on the arrays with window.opener.
When closing the new window I would like to empty the arrays. Otherwise the pictures chosen in the first round are displayed in the slideshow when opening it the second time. I understand you can empty arrays by this method: array.length= 0;
But where do I add the code? I'm quite lost. I'm pasting the code, perhaps someone can give me a hand.
var imgUrlList = [], imgTextList = [], //These arrays need to be emptied
windVar = null;
function init() {
var tags, i, openWindow;
tags = document.getElementsByClassName("unmarkedImg");
openWindow = document.getElementById("slideShowBtn");
openWindow.onclick = savePicsForSlideshow;
for (i = 0; i < tags.length; i++) {
tags[i].parentNode.onmouseover = showLargePict;
tags[i].parentNode.onmouseout = hideLargePict;
}
}
window.onload = init;
function showLargePict() {
var largePictTagDiv = this.getElementsByClassName("innerBox")[0];
var largePictTagParentDiv = largePictTagDiv.parentNode;
var imgTag = largePictTagParentDiv.getElementsByTagName('img')[0];
var checkBoxlargePict = largePictTagDiv.getElementsByTagName('input')[0];
if (checkBoxlargePict.checked)
imgTag.className = "markedImg";
else imgTag.className = "unmarkedImg";
largePictTagDiv.style.visibility = "visible";
} // End showLargePict
function hideLargePict() {
var largePictTag;
largePictTag = this.getElementsByClassName("innerBox")[0];
largePictTag.style.visibility = "hidden";
}
function savePicsForSlideshow() {
var innerBoxes = document.getElementsByClassName("innerBox");
for (i = 0; i < innerBoxes.length; i++) {
checkBoxlargePict = innerBoxes[i].getElementsByTagName('input')[0];
if (checkBoxlargePict.checked) {
var imgTagSrc = innerBoxes[i].getElementsByTagName('img')[0].src;
imgUrlList.push(imgTagSrc);
var spanTagText = innerBoxes[i].getElementsByTagName('span')[0].innerHTML;
imgTextList.push(spanTagText);
}
}
if (imgTextList.length > 0) {
newWindow(500, 600, "slideshow.htm");
}
}
function newWindow(width, height, filename) {
var windowProperties;
windowProperties = "top=100,left=100,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=" + width + ",height=" + height;
if (windVar != null) if (windVar.closed == false) windVar.close();
windVar = window.open(filename, "", windowProperties);
}
Please excuse my programming and English grammar shortcomings. I'm new to javascript.
//Henrik, Göteborg, Sweden.
At the beginning of the savePicsForSlideshow function, empty out each array.
imgUrlList.length = 0;
imgTextList.length = 0;
You can check if thw window is close with the property closed of the object window
if(window.closed)
{
array.length = 0;
}

sharepoint javascript on click shape

I need to add an onclick event to shapes from Visio in SharePoint, with JavaScript, like the vwaControl handler shapeselectionchanged but on click, is there any way I could do that?
I'm sorry about my English is not my native language.
I hope you can understand me.
I just did something similar.
You can use the shapeSelectionChangedHandler to handle clicks to. As far as I know there is no onClick functionality, but shapeSelectionChangedHandler works fine for me.
See:
Programming with Visio in SharePoint, create new Outlook meeting in ?Javascript?
See: http://msdn.microsoft.com/en-us/library/gg243427.aspx for guide to set it up with Content WebPart and so on.
Code I use, just add what you want in shapeSelectionChangedHandler = function(source, args) {}
<script language="javascript">
var app = Sys.Application;
app.add_load(onApplicationLoad);
// hold an instance of the Visio VWA control
var vwaControl;
var shapeSelectionChangedHandler = null;
function onApplicationLoad()
{
vwaControl= new Vwa.VwaControl("WebPartWPQ4");
vwaControl.addHandler("diagramcomplete", onDiagramComplete);
vwaControl.addHandler("shapeselectionchanged", shapeSelectionChangedHandler);
}
function onDiagramComplete()
{
var vwaPage = vwaControl.getActivePage();
vwaPage.setZoom(35); // force the initial zoom level
}
shapeSelectionChangedHandler = function(source, args)
{
// get the selected shape from the shapes on the page
var vwaPage = vwaControl.getActivePage();
var vwaShapes = vwaPage.getShapes();
var shape = vwaShapes.getItemById(args);
// get the data to display for the selected shape
var data = shape.getShapeData();
var strRoomName = "";
var strFloorNumber = "";
var strCapacity = "";
var strStatus = "";
for (var j = 0; j < data.length; j++)
{
if (data[j].label == "RoomName")
{
strRoomName = data[j].value;
continue;
}
if (data[j].label == "FloorNumber")
{
strFloorNumber = data[j].value;
continue;
}
if (data[j].label == "Capacity")
{
strCapacity = data[j].value;
continue;
}
if (data[j].label == "RoomStatus")
{
strStatus = data[j].value;
continue;
}
}
// get the selected state input and set its value
var inputRoomName = document.getElementById('strRoomName');
inputRoomName.value = strRoomName;
var inputFloorNumber = document.getElementById('strFloorNumber');
inputFloorNumber.value = strFloorNumber;
var inputCapacity = document.getElementById('strCapacity');
inputCapacity.value = strCapacity;
var inputStatus = document.getElementById('strStatus');
inputStatus.value = strStatus;
}

Categories

Resources