Jump to content

Dan Korn

Members
  • Posts

    4,884
  • Joined

  • Days Won

    17

Everything posted by Dan Korn

  1. Yes, absolutely. I don't understand what you mean by "a path source". Who is asking for that? You can create a Graphic rule with exactly the same code as in your Text rule, and assign the rule to a Graphic frame. From the New Rule dialog, select the Graphic radio button at the top, then select Empty Rule and click Next. You can literally copy the content from your Text rule into the Graphic rule. Thanks. I've attached a modified version with a Graphic rule and a Graphic frame, which I think does basically what you want. I did make a few changes to your rule to clean up some unnecessary code. I also changed it to first look for "png". The first record doesn't find the graphic without this change. The reason is that, when it looks for the URL with a "tif" extension, the web server returns an XML document with an error instead of the graphic, but because it's returning the XML, FusionPro thinks that it did successfully download the file, but it errors when trying to handle that XML as a graphic. (At least it works this way on Mac; it might still find the right graphic when composed on Windows, such as when you submit it to Producer.) The moral of the story here is, you shouldn't really "test" for files downloaded from the Internet by extension, the way you can for local files. Your data should include the fully-resolved URL for each graphic, with the filename extension. Then your Graphic rule can be just the one-liner I mentioned in the previous thread: return CreateResource(Field("URL")); Also, in FusionPro 11 and later, you can accomplish this without any rule at all, by simply changing the field type to Graphic. From the menu in Acrobat, select FusionPro -> Data Definition -> Input Options, click Edit Fields, select the field and click Edit, then set the type to Graphic and the Subtype to File name. Then you can insert assign that field directly as the variable for a graphic frame, again, without any rule at all. 20302_Shift_Mailer-graphic-rule.pdf
  2. You don't do the scaling in the rule. You do the scaling in the graphic frame, using the controls on the Graphic Frame palette. You probably want the Scaling set to Best Fit. Once again, I would need to look at your template and your data to be able to make more specific suggestions.
  3. Well, without knowing what's in the data, it's impossible to say what's wrong. But usually a URL is fully resolved, and doesn't need any extensions or anything appended to it. So I think that what I wrote in the other thread should probably work: return CreateResource(Field("URL2")); But again, without seeing your job, or at the very least an example of what's in your data, I have no way to analyze what's not working. FWIW, this works for me: return CreateResource("https://fusionpro-marcomcentral.netdna-ssl.com/wp-content/uploads/2019/06/fusionpro-icon.png");
  4. It's hard to say exactly what to do without more information about your job and the data file, but you can just make a Graphic rule like so: return CreateResource(Field("YourFieldName")); If the data field value is the fully resolved URL to the graphic, this should work.
  5. FusionPro should already be optimizing the PDF to include the graphic only once. It's hard to say exactly why that's not working without more information, including, at the very least, the version of FusionPro you're using, and the Composition Settings for the job.
  6. Or: Left(Field("PFNAME"), 1) Or just: Field("PFNAME")[0]
  7. You were very close. Each rule can just call CopyfitLineWithMagnifyTag to fit itself independently. I tweaked the code just a bit, putting this into the JavaScript Globals: function CopyfitLineWithMagnifyTag(line, width, AllowToExpand) { var tm = new FusionProTextMeasure; tm.CalculateTextExtent(line); if (tm.messages) ReportError("CopyfitMagnifyLine: " + tm.messages); if (tm.textWidth < width && !AllowToExpand) return line; var factor = Round(width / tm.textWidth * 100, 0) - 10; return "<magnify type=text factor=" + factor + ">" + line + "</magnify>"; } function FitInfoLine(fieldName) { var lineText = TaggedDataField(fieldName); var font = Field("Font"); switch (font) { case "Gotham": font = "Gotham Medium"; break; case "Goudy": font = "GoudyOldStyExtBol"; break; } //font = "Arial"; // I used this since I don't have your fonts. var pointSize = 14; var content = '<f name="' + font + '"><z newsize="' + pointSize + '">' + lineText; var frameWidth = FindTextFrame(FusionPro.Composition.CurrentFlow.name || "info").GetSettableTextWidth(); return CopyfitLineWithMagnifyTag(content, frameWidth); } Then each of the four rules become one-liners, like so: return FitInfoLine("Name"); return FitInfoLine("Title"); return FitInfoLine("Department"); return FitInfoLine("SC"); Finally, and this is very important, you need to turn OFF copyfitting for the frame, in the Overflow Options dialog.
  8. You could also make sure that "Preserve Annotations" is unchecked, on Graphics tab of the Composition Settings dialog. Beyond that, it's very hard to say what the slowdown in a job might be without looking at the files.
  9. In JavaScript, the property is FusionPro.Composition.currentPageNumber. You'll need to check the "Re-evaluate this rule for every text flow" box. The other thing you can do is name the frame with the $pagenum variable, and do something like this in OnRecordStart: FindTextFrame("YourFrameName").suppress = ToUpper(Field("ShowPageNumbers"))[0] == "Y";
  10. Hmm, it works for me. Though I don't have your job files, so I had to change the field names and use a different test job. Are you sure you have the exact code I posted? Anyway, there's nothing I can do to diagnose what's happening in your specific job without the files.
  11. Sure, a minor change: function format_phone(prefix, phone_num) { if (!Field(phone_num)) return ""; var endsWithDot = prefix.match(/\.$/); var result = '<span'; if (!endsWithDot) result += ' bold=true color="PANTONE BLUE 072 U"'; result +='>' + prefix; if (!endsWithDot) result += ":"; result += " " + '</span>' + Field(phone_num); return result; } var numbers = { Office: "Office", "ext.": "Ext", Direct: "Direct", Cell: "Cell" }; var result = []; for (var label in numbers) result.push(format_phone(label, numbers[label])); return result.filter(String).join(" \n");
  12. This should work: function format_phone(prefix, phone_num) { if (!Field(phone_num)) return ""; var endsWithDot = prefix.match(/\.$/); var result = '<span bold=true'; if (!endsWithDot) result += ' color="PANTONE BLUE 072 U"'; result +='>' + prefix; if (!endsWithDot) result += ":"; result += " " + '</span>' + Field(phone_num); return result; } var numbers = { Office: "Office", "ext.": "Ext", Direct: "Direct", Cell: "Cell" }; var result = []; for (var label in numbers) result.push(format_phone(label, numbers[label])); return result.filter(String).join(" \n"); I've reduced the code a bit by having just the minimal data in the numbers object (which is now an object with a map of properties and values instead of an array), and calling the format_phone function in a loop, which includes the calls to Field. There's a little bit of Regular Expression magic to detect whether the prefix (label) ends with a dot, which is what we use to determine whether to change the color and append the colon. I also put the bold change into the span tag, and removed the code to set the color to Black, which is not needed if the variable for this rule is inserted in Black in the Text Editor, since the ending </span> tag restores the original color.
  13. If you check the "Preserve Annotations" box on the Graphics tab of the Composition Settings, the form fields will be present in PDF output.
  14. Please contact Support with ALL of this information: The exact version of FusionPro. The exact version of Acrobat. The exact version of your operating system.
  15. Sorry, I can see how that documentation is misleading. You can use variable data in the slug text, to an extent. You could have the rule insert, say, the current date, or a record range (FusionPro.Composition.startRecordNumber et al), or any other job setting (including one from FusionPro.Composition.JobOptions). But you can't use a field value from your primary data. Also, the slug line appears on every imposed sheet, so you can't have it just appear on the first one. A custom imposition background might be your best bet. You could have a text frame on it, and a rule that returns an empty string unless FusionPro.Composition.impositionSheetNumber == 1.
  16. You're not in the context of a data record in OnJobStart. In other words, the Field function can be called only when a record is being composed, but in OnJobStart, you haven't started composing any records yet. (The OnJobStart rule is called before any data is processed, because you can change which records are composed there.) More specifically, the slug line text is not meant to change from sheet to sheet. (It's not record-specific.) It's just a per-job setting, and using the FusionPro.Composition.impositionSheetSlugText property in OnJobStart merely overrides the per-job setting for the slug text specified in the FPI file (in FP Imposer). You could always open up your data file (or another file) as an XDF, with "new ExternalDataFileEx", in the OnJobStart rule, and grab the store ID from there for your slug line. If you really do want record-specific information to appear on the imposed sheet, you can set up a custom imposition background page, and any data fields you call out on text frames there will be from the first record composed on the sheet.
  17. Well, there are a few problems here. For one, you're not referencing the "Account ID" fields in either the primary or the secondary (XDF) data correctly in your rules. In OnRecordStart, you call it "Acct": DetailCursor = DetailFile.SortBy("Acct", "Type"); Obviously it should be "Account ID" instead. But you don't need the call to SortBy or the cursor object at all here; you can just use the DetailFile XDF object directly. So we can get rid of that line and then just use the XDF object in the Purchases rule: recs = DetailFile.FindRecords(Field("Account ID"), "Account ID"); Though that's not quite right either. The first parameter should be the name of the XDF field, which is just "Account ID", and the second parameter should be the value you're trying to match, which is the value of that field from the primary data, or Field("Account ID"). So that line should be: recs = DetailFile.FindRecords("Account ID", Field("Account ID")); However, even with those changes, at least with the data file you provided, this still doesn't work. That's because there are no mathing "Account ID" values between the two tabs in the Excel file. For instance, the first record in the primary data has Account ID 2934, but the secondary data doesn't have any records with that Account ID. You need to make sure your data is valid and actually has some matching records. I can't really help with that; you just have to start with the right data. Note that, once you have some matching records between your two data files, you can accomplish this without writing any JavaScript at all. You can click on the Secondary Data button from the Data Source Definition dialog, map the fields from the XDF there, then use the "Table - from data source" form rule to define the table.
  18. Thanks for posting the job. The line of code you posted is fine. But this error message appears in the log file: The problem is further up in the OnRecordStart rule: if (((((Field("PCOMP") == "6") || (Field("PCOMP") == "2")) || (Field("PCOMP") == "D")) || (Field("PCOMP") == "4")) && (Field("PINSC") == "Y")) { FusionPro.Composition.SetBodyPageUsage("TM",true); } if ((Field("PINSC") == "Y") && (Field("PCOMP") == "Y")) { FusionPro.Composition.SetBodyPageUsage("TM",true); } [color="DarkRed"]if ((Field("HOST") == "Y")) { FusionPro.Composition.SetBodyPageUsage("TH",true); }[/color] if ((Field("SCC") == "1")) { FusionPro.Composition.SetBodyPageUsage("BC",true); } if ((Field("DATE01") != "")) { FusionPro.Composition.SetBodyPageUsage("Itinerary",true); Print("Itinerary page activated."); } The rule throws an exception when the call to set the usage of a non-existent page "TH" fails, and therefore the rest of the rule does not get run. This is why I asked: Almost always, there's something in there that's at least a hint as to what the problem is. It's also why it's often difficult, if not impossible, to figure out what the problem is from just a snippet of code. The short answer to how to fix this is: remove the code that's calling out a page that doesn't exist (or add a page with that name). The longer answer is, if you might have callouts for pages that don't exist, then you can put each call into its own try/catch block, so that, even if an exception is thrown, the rest of the rule still runs, like so: if (((((Field("PCOMP") == "6") || (Field("PCOMP") == "2")) || (Field("PCOMP") == "D")) || (Field("PCOMP") == "4")) && (Field("PINSC") == "Y")) { try { FusionPro.Composition.SetBodyPageUsage("TM",true); } catch (ex) { Print(ex); } } if ((Field("PINSC") == "Y") && (Field("PCOMP") == "Y")) { try { FusionPro.Composition.SetBodyPageUsage("TM",true); } catch (ex) { Print(ex); } } if ((Field("HOST") == "Y")) { try { FusionPro.Composition.SetBodyPageUsage("TH",true); } catch (ex) { Print(ex); } } if ((Field("SCC") == "1")) { try { FusionPro.Composition.SetBodyPageUsage("BC",true); } catch (ex) { Print(ex); } } if ((Field("DATE01") != "")) { try { FusionPro.Composition.SetBodyPageUsage("Itinerary",true); } catch (ex) { Print(ex); } } I also see quite a bit of repetition in your job, with all of those rules like Format Date Itin 01, Format Date Itin 02, Format Date Itin 03, etc. A lot of that could be greatly reduced with a rule with a for loop starting with something like "for (var i = 1; i <= 20; i++)", but I'll leave that for another thread.
  19. That seems right, though I can't say for sure without the job. Is it not working for you? Are there any messages in the log file? Is the page marked as Unused initially? It won't matter if you do this instead: FusionPro.Composition.SetBodyPageUsage("Itinerary", Field("DATE01") != ""); The only other thing I can think of is that your data field might not actually be empty, if there are spaces. So you could try: FusionPro.Composition.SetBodyPageUsage("Itinerary", Trim(Field("DATE01")) != "");
  20. It's hard to say exactly what you need to do without the collected job files, as well as information about the versions of FusionPro, Acrobat, and your operating system. I'm also a bit confused as to whether you're using the Excel file directly as the input to FusionPro or exporting it to a text file which you then use as the input. If it's the latter, you're probably better off importing the Excel directly and reducing the number of conversions. Also, what exactly do you mean by "not displaying correctly?" What exactly are you seeing? A picture might be worth a thousand words here. Collecting up the job, and posting it here would be better. Collecting and posting a minimal sample which demonstrates the problem would be best. A few general things to keep in mind: * Always do a full composition (not just a preview) and look at the log file. It likely contains some clues as to what's going wrong and how to fix it. * You need to use a font that supports whatever characters you're trying to output. Not every font supports every Unicode character, though there are some "Pan-Unicode" fonts which try to handle a lot of them, such as Microsoft's Arial Unicode MS and Google's Noto. * If you're using a text file as input, you may need to specify its encoding in the Define Data Source dialog. * Depending on the Unicode characters you're outputting, you may need to UN-check the "Limit processing to Latin-1 / Mac Roman" box on the Advanced tab of the Composition Settings dialog.
  21. Sorry about that. The feedback is appreciated. The older version was a Carbon app, which isn't supported anymore. (Apple keeps changing up their UI technologies.) What would you suggest to make it better? Is it just the appearance, or is it that you have to scroll around more? If you're on Windows, you can still use the older FP Imposer. On Mac, there's no going back, though if you open up the FPI file in a text editor it's not too hard to figure out.
  22. This is a bug, specific to stacked imposition. If you're using imposition without stacking, or no imposition at all, then the graphic resource will work in the output. I did make a fix for this (FP-550), which will be included in a future release. (Unfortunately we just missed getting this into the most recent 12.1.2 release.) The ability to use a resource directly in a graphic frame like this was a new feature in FP 11. As lasdoog points out, the workaround is to create a Graphic rule to return the resource, as in previous versions of FusionPro. Sorry for the trouble.
  23. The issue is that the XDF is present on your local Designer machine, but is not found when you do the full composition on the remote FP Server machine. As others have noted, this has been an issue for users of FusionPro VDP Producer as well. But that was the past. A lot of things changed in FP 11. We added a feature in FusionPro VDP 11.2 to make this all much easier. Instead of putting the XDF file on the network, or adding it as a plain text resource, you can now manage XDF files, which we now call Secondary Data Sources, in the same way you define your primary data source. From the Define Data Source dialog, you can click on the Secondary Sources button. Or, from the menu in Acrobat, you can select FusionPro -> Data Definition -> Secondary Data Sources. This brings up the new Data Sources dialog, where you can define all of your data sources the same way as your primary source. So, instead of defining your XDF in JavaScript, you can now add the data source, of any format (including ODBC on Windows), using the Data Sources dialog. When you click Add, you'll be taken through the same set of Wizard dialogs as with your primary data source, where you can select all of the options relevant to the data, such as the delimiter, the encoding, and even the sheet for Excel. Also, on the Collect dialog, there's now a check box for Secondary data sources (which is checked by default). So the data source will automatically be collected up with the other job files, including the primary data source, and will always be found, even in a remote composition with FP VDP Producer or Server. Also, the data source will be accessible by its source name in your rules. So instead of this: externalDF = new ExternalDataFileEx('196176_IDM_22NB JAN NEWSLETTER FINAL DATA.txt', '\t'); You can simply access the source by whatever name you gave it on the Data Sources dialog, such as: externalDF = FusionPro.GetDataSource("My Secondary Data"); (TV voice) But wait, there's more! With the new Secondary Data Sources functionality, in most cases, you don't need any JavaScript at all to access the XDF data. You can set up a mapping from your primary data to the secondary data records, and use the secondary data fields directly in the Text Editor, just like your primary data fields. Or, if each record in your primary data maps to multiple records in the secondary data (such as an account number mapping to multiple transactions), you can use the new Form rules for tables in FP 11 to create a table from the matching data, again with no JavaScript at all! If you're willing to post the job, I can show you how you can set it up to access the XDF without any JavaScript rules at all. Or, you can take a look at the Statement-MultiFile.pdf job in the Statement folder under the FusionPro Tutorials (from the Acrobat menu, FusionPro -> Documentation -> Tutorials). This is also all documented in the FusionPro VDP User Guide, in the sections about Secondary Data Sources and Tutorials.
  24. Yes, sorry, this deserves some explanation. The JavaScript String.replace() function uses a shorthand called Regular Expressions. Regular Expressions are a big topic, so I won't try to fully explain them here, but I can break down the call here: var ttnum = StringToNumber(Field("amnt").replace(/[^\d\.]/g, '')); So we're calling the String.replace function, on the String object returned by the Field function for the field "amnt". This gives us a string with a value such as "$1,234.56". The String.replace() function takes two parameters, which, in this case, are a RegExp literal and a replacement string (which is '', or an empty string). The RegExp literal /[^\d\.]/g breaks down like so: / - starts the RegExp literal [ - starts a range/group (see Groups and Ranges) ^ - denotes that the range is a "negated" group \d - denotes "any digit" (0-9) (see Character Classes) \. - denotes a literal period/dot (decimal place) character ] - ends the range/group / - ends the RegExp literal g - "global" flag, denoting to act on all matching instances So [^\d\.] means "a group of characters including any digit and a period", negated with the caret ^, turning it into "any character that's NOT a digit or period." And the g flag says "ALL matches (instances) of any character that's not a digit or period." So what this means is "match all instances of a character that is NOT a digit or a period/dot," and replace it with the replacement, which is '', i.e. an empty string, so it's replacing it with nothing, i.e. removing it. Effectively, we're stripping out anything that's not a digit or a dot, including the dollar sign, any commas, and anything else, leaving just the digits and the decimal dot. Therefore, a string such as "$1,234.56" gets turned into "1234.56", which can be parsed to the number 1234.56, which can then be used in mathematical calculations, such as multiplying it by two. Now, sure, instead of using Regular Expressions, we could have written something like this: var ttstr = Field("amnt"); var ttnumstr = ""; for (var i in ttstr) { var c = ttstr[i]; if ("1234567890.".indexOf(c) >= 0) ttnumstr += c; } var ttnum = StringToNumber(ttnumstr); But this is much more succinct: var ttnum = StringToNumber(Field("amnt").replace(/[^\d\.]/g, '')); And, once you get the hang of Regular Expressions, you'll find them to be an extremely powerful tool.
  25. Yes, it's always better to deal with raw, unformatted data, such as pure numbers, rather than pre-formatted data, such as with dollar signs and comma separators. But I understand that you just have what you have. So you're stripping off the dollar sign to get a number, but not the commas that divide thousands (and millions). There are lots of ways to "clean" or "unformat" such strings in JavaScript, which can be found via a search like this, but I think this is the simplest: var ttnum = StringToNumber(Field("amnt").replace(/[^\d\.]/g, '')); return FormatNumber("$#,###.00", ttnum * 2);
×
×
  • Create New...