Jump to content

step

Registered Users - Approved
  • Posts

    962
  • Joined

Everything posted by step

  1. Maybe it's a permissions issue with that particular PDF or something. It's really difficult to say based on a couple of screenshots. Can you collect and upload your template/data?
  2. Probably not the case, but it might be worth making sure that you don't have "Suppress static PDF background in composition" checked in your composition settings (under "graphics"). What version of FusionPro are you using? I think I recall a quirk in previous versions of FusionPro that had difficulty dealing with template file names with capital letters in them. Is your file all lower cased – as it's listed in the message log? Is that colon (:) part of the file name? It might be worth trying to rename your template something simple like "test.pdf" and trying to recompose. I also wanted to mention that you can toggle body pages by page number in FP8 and FP9 – I'm not sure about 7... for (var i=1; i<=6; i++) FusionPro.Composiiton.SetBodyPageUsage(i + !Field('ASK') * 6, true) console.log(i + !Field('Ask') * 6) Or similar: var pg = 7; while (--pg) FusionPro.Composiiton.SetBodyPageUsage(pg + !Field('ASK') * 6, true);
  3. One way to do this is to set all of your pages to "unused," create an array containing the names of the pages, and tell FusionPro to compose 1 record per page in the array but repeat that "record" by the number of pages in the data file. To get started, your OnJobStart rule would look like this: // The name of your pages pages = [ 'Card1', 'Letter', 'Cert1', 'Cert2', 'Card2' ]; FusionPro.Composition.composeAllRecords = false; FusionPro.Composition.endRecordNumber = pages.length; Which essentially tells FusionPro to only compose five records (since that is the length of the "pages" array). You can edit the names of the pages in the array there, but remember: they need to match what you've named the pages in your template. The bulk of the process happens in OnRecordStart: var ex = new ExternalDataFileEx(PrimaryInputFile(), '\t'); FusionPro.Composition.repeatRecordCount = ex.recordCount; var pg = pages[FusionPro.Composition.inputRecordNumber-1]; var output = GetFileName(PrimaryInputFile()).replace(/\..+$/,'') + '_' + pg + '.' + FusionPro.Composition.outputFormatExtension; if (FusionPro.Composition.repeatRecordNumber == 1) FusionPro.Composition.OpenNewOutputFile(output); FusionPro.Composition.SetBodyPageUsage(pg, true); for (var i in FusionPro.Fields) FusionPro.Composition.AddVariable(i, ex.GetFieldValue(FusionPro.Composition.repeatRecordNumber, i)); This code imports your linked data file as an external data file. It counts the records in the external data file and assigns the value to the "repeatRecordCount" so that each page in your template will be repeated by the number of records in your data file (46). Then the name of the page is pulled from the global "pages" array created in the OnJobStart rule. The name of the output file is also, in part, determined by the page name. The name of the output file will be {name of input file}_{name of page}.{output format}. If it is the start of a new record – meaning the start of a new page, a new output file is opened and named appropriately using the OpenNewOutputFile function. Finally, the correct page is activated and proper external data field values are assigned to the FusionPro.Fields object to allow the "Field" function to continue to return the correct values. I hope this helps get you going. Let me know if you have further questions.
  4. I don't believe Tou was suggesting a key command but rather holding the Control key while scrolling up/down using your mouse wheel. You may need to enable those settings in System Preferences > Mouse/Trackpad. If you're interested in a key command you can set that up in Yosemite by tweaking some Accessibility settings. One trick I've found useful is to select all of the text in the text editor (cmd + A) and bump the font size up to around 12pt or so. This allows me to read/edit the text pretty clearly without having to zoom in at all. Then when everything is typeset as desired, select all the text (cmd + A) and shrink the text back down to the 6pt "fine print" size it will print at. I'm pretty sure this works on Windows as well. Someone else would have to confirm though.
  5. Sure, but where's the difficulty in that? I'd say it's closer to the latter of those two options. The "magnify" tag doesn't really alter the values of any previously set tags, it just applies magnification (pardon the redundancy) of a certain type – text, textwidth, textheight, leading, or tracking. I believe it's the tag that FusionPro applies behind the scenes when a text flow is copy-fitted. More information can be found on page 66-67 of the TagsRefGuide.pdf of the FP documentation.
  6. Have you seen this post? It references a similar situation. It appears that the Copyfit function may interpret empty textflows as "unable to fit." This slight revision should work in your scenario: var cf = FusionPro.Composition.CurrentFlow; if (!cf.fits) if (+!!RawTextFromTagged(cf.content.replace(/<variable name="([^"]*)">/g, function(s,p){return RuleOrField(p);}))) cf.content = '<para><color name=Red><z newsize=36>TEXT DOES NOT FIT!</para>';
  7. Check out page 50 on the TagsRefGuide.pdf in the FusionPro documentation. Sounds like you're looking for the "setwidth" tag. It's set in points (not percentages) so if you have a 12 pt font, to get a 75% width using the setwidth tags, you'd have to specify 9 points: return 'Regular text <setwidth newsize="9">text that is 75% the width. <setwidth newsize="12">Back to regular text.'; Note that there is not a closing tag for "setwidth" so you'll need to set it back to the original width if you don't intend for everything that follows it to have a width of 9 points. You could also create a function to do this for you: function SetWidth(text, percentage, size) { var size = size || 12; var percentage = percentage || 1; var width = size*percentage; return '<setwidth newsize="' + width + '">' + text + '<setwidth newsize="' + size + '">'; } return 'some regular text' + SetWidth('some text that is 75% the width', 0.75, 12) + 'some regular text ' + SetWidth('some text 150% wider', 1.5, 12);
  8. That's probably a question that should be asked in the MarcomCentral forum. But if I had to guess, I bet you could do something to the effect of: var address = Field('Your Address Field'); FusionPro.Composition.composeThisRecord = !!address;
  9. Well, I'll admit it's kind of hacky, but you could just edit the variable stuff off of the art, add it as a resource to your template, and then overlay your variable frames. I'm not really sure what your other options are aside from re-typsetting their coupons. Example attached.sample.zip
  10. Cool, that makes it even simpler: var email = Field("Individual Email"); // If email is empty, return nothing if (!email) return ''; // Else: add the domain email += '@MyDomain.com'; // Replace . and @ return email.replace(/([\.@])/g,'<span font="Gotham Medium" pointsize="7">$1</span>'); That's because when you set the size with "z" tags – there is no closing z tag. Meaning you'll have to set the font back to whatever it originally was instead of just closing the tag. From the looks of the code you've posted, that's what you've done. It really doesn't have anything to do with setting the font as well: One of the advantages to using the span tag is that it allows you to set attributes within one tag and close them without having to reset prior attributes. Again, that's because there is no closing z tag. You'd have to write it like this: return[color="red"] '<f name="Telegrafico">' +[/color] Field("Address").replace(/(\d+)/g,'<f name="Gotham Medium"><z newsize="7">$1</f>[color="red"]<z newsize="9">[/color]'); Or, you know, with a span tag: return Field("Address").replace(/(\d+)/g, '<span font="Gotham Medium" pointsize="7">$1</span>'); Is it correct to assume that Rule1 feeds to Rule2 and Rule 2 feeds to Rule 3? Is the domain name ("@SIMPSONHOUSING.COM") supposed to be all caps regardless of the "CaseSelection" applied in Rule 1? Also note that "pointsize" is not a tag. So you'd need to re-write that to use z tags or span tags – both topics which I've beaten to death already in this post. Have you given the code I posted a try? It seems like it would have solved a lot of your problems. But just to clarify, I'm suggesting that you condense your 3 rules into one: var email = Field("Individual Email"); // If email is empty, return nothing if (!email) return ''; var CaseSelection = 'allcaps'; switch(CaseSelection){ case 'allcaps': email = ToUpper(email); break; case 'smallcaps': email = '<smallcaps>' + email + '</smallcaps>'; break; case 'lowercase': email = ToLower(email); break; default: email = email; } // Else: add the domain email += '@SIMPSONHOUSING.COM'; // Replace . and @ return email.replace(/([\.@])/g,'<span font="Gotham Medium" pointsize="7">$1</span>'); Or if you want the domain of the email address to be affected by the CaseSelection: var email = Field("Individual Email"); // If email is empty, return nothing if (!email) return ''; email += '@SIMPSONHOUSING.COM'; var CaseSelection = 'allcaps'; switch(CaseSelection){ case 'allcaps': email = ToUpper(email); break; case 'smallcaps': email = '<smallcaps>' + email + '</smallcaps>'; break; case 'lowercase': email = ToLower(email); break; default: email = email; } // Replace . and @ return email.replace(/([\.@])/g,'<span font="Gotham Medium" pointsize="7">$1</span>'); Or if you'd rather keep all of your rules as is, you could create a global function that replaces everything that isn't a letter or space (essentially replacing only special characters) and call it from your respective rules: JavaScript Globals function ReplaceSpecial(text, font, size) { var font = font || 'Gotham Medium'; var size = size || '7'; return text.replace(/([^a-z|<>|\s]+)(?!([^<]+)?>)/gi, '<span font="' + font + '" pointsize="' + size + '">$1</span>'); } return (Rule("RuleEmailCase")) ? ReplaceSpecial(Rule("RuleEmailCase")+"@SIMPSONHOUSING.COM") : ''; You could optionally specify a different font and pointsize for special use cases: var twitter = '<span font="Telefico" pointsize="9">' + '@twitter'; return ReplaceSpecial(twitter, 'Arial Bold', 9); /* Returns: <span font="Telefico" pointsize="9"><span font="Arial Bold" pointsize="9">@</span>twitter Note that numbers and special characters within tags are not replaced. The @ sign (originally set to Telegrafico) is overridden by the function and changed to Arial Bold */
  11. I agree with Dan that setting the leading on individual characters that (I'd imagine) you'd want to stay on the same line, is kind of pointless – so I excluded it from my code. Aside from that, you certainly don't need two JavaScript rules to handle your scenario. In fact, you can do it all at once like this: var email = Field("Individual Email"); // If email is empty, return nothing if (!email) return ''; // Else: add the domain email += '@MyDomain.com'; // Replace . and @ return email.replace(/[\.@]/g, function(s) { var size = s == '.' ? 4.5 : 7; return '<span font="Gotham Medium" pointsize="' + size + '">' + s + '</span>'; });
  12. Right now, you're capturing all numbers and assigning them to the '$1' variable which you then wrap in your font tag. If you want to expand that regexp to include parentheses and hyphens, I think this would work for you: return Field("Address").replace(/([\(\)\-\d]+)/g, '<span font="Gotham Medium">$1</span>'); Here's a more in depth break-down of how it works: var find = new RegExp( '(' + // Parenthesis CAPTURE matched patterns and assign them to $1 '[' + // Square brackets denote a character set that the RegExp should match '\\(' + // First character to match: ( <-- Open parenthesis // Note that we escape so we don't start another capture group '\\)' + // Second character to match: ) <-- Close parenthesis '\\-' + // Third character to match: - <-- hyphen '\\d' + // All digits 0-9 ']' + // Close the square brackets because we only want to match what's inside '+' + // Plus sign means we want to match 1 or more of the characters in the [] ')' // Close parenthesis to end capturing ,'g'); // g means "Match globally" // Each captured match is assigned to $1 so we can wrap it in font tags var replace = '<span font="Gotham Medium">$1</span>'; return Field("Address").replace(find,replace);
  13. Note that as the name suggests: those changes will affect the superscript ratio of everything that's superscripted within your template as it is a global edit. You may be fine with this but it's also worth pointing out that you can also set the offset and ratio of the superscript tags within the paragraph tags themselves: var str = '<p superoffset=90>ENERGY STAR<superscript>®</superscript>'; str += '<p superoffset=30>ENERGY STAR<superscript>®</superscript>'; return str;
  14. You can do this with the code that I posted http://forums.pti.com/showpost.php?p=18408&postcount=4 in the thread that has basically the same topic.
  15. This will keep the regexp from matching the first word of a sentence: var wordsToItalicize = ["of", "the"]; for (var w in wordsToItalicize) cod = cod.replace(new RegExp("[color="Red"].[/color]\\b(" + wordsToItalicize[w] + ")\\s\\b", "gi"), "<i>$1</i> "); return cod;
  16. You can link text frames but you'll get the same result by using a three column text frame and the second block of code from my post above. I'm unsure of what you're getting at here. Obviously you can have multiple rows in a table but you can also have multiple lines in one cell. So I think you'll be fine with which avenue you chose in that regard. Yes, you can put multiple fields in a cell. But again, I think a table is overkill for what you are trying to do. After seeing your screenshot, it doesn't look like you want to align each address differently – it looks like you want 3 different addresses centered across 3 columns: return [ 'Addr1, Suite 1<br>City, ST 11111', 'Addr2, Suite 2<br>City, ST 222222', 'Longer Address3<br>Some City, ST 33333' ].join('<p verticalstart=topofcolumn>');
  17. Check out the "Tags Reference Guide." There's some good information about the "paragraph" tag in there (starting on page 41) that I think is what you're looking for. You can set a "quad" attribute that will specify a paragraphs alignment. Here's an example: var addressBlock = "123 Sample Dr. <br> City, ST 12345"; var result = ''; for (var i=0; i<3; i++) result += '<p quad=' + ['L', 'C', 'R'][i] + '>' + addressBlock; return result; If you want them aligned vertically, create a 3 column text frame and add the "verticalstart" attribute: var addressBlock = "123 Sample Dr. <br> City, ST 12345"; var result = ''; for (var i=0; i<3; i++) result += '<p quad=' + ['L', 'C', 'R'][i] + (i? ' verticalstart=topofcolumn>' : ' br=false>') + addressBlock; return result; If you have a field that returns which alignment to use (Left, Right, Center) you could something like this: var addressBlock = "123 Sample Dr. <br> City, ST 12345"; var alignment = "Center"; return '<p br=false quad=' + Left(alignment,1) + '>' + addressBlock;
  18. Come on! No love for the oxford comma? Either way, I think something like this would work for you: var a = [Field('desc1'), Field('desc2'), Field('desc3'), Field('desc4')].filter(String); var b = a.pop(); return [a.join(', '),b].filter(String).join(' and '); I'm confused. That seems totally unrelated to this topic. But here's how I would handle that scenario: return [Field("Savings"), Field("Qty-2for")] .map(function(s,p,a) { if (p) // If this is the quantity field, return s ? 'on ' + s : ''; // prepend it with 'on ' if it's not empty. // Remove anything that isn't a decimal or a digit from the 'Savings' field // and format it to two decimal places so that it's easy to work with s = FormatNumber('0.00', StringToNumber(s.replace(/[^\d\.]/g,''))); return s*1 ? // Make sure the savings amount isn't 0.00 'Save ' + // If it is, prepend 'Save ' to the return string (Math.floor(s) ? // Is the savings greater than or equal to $1? '$' + Math.floor(s) // Prepend it with a dolla bill : s * 100 + '¢') // If it's less append a cent sign : ''; // Return nothing if it's 0.00 (or empty) }) .filter(String) // Remove the empty strings .join('<br>') // join the remaining positions with a break tag .replace(/^o.*/,''); // return nothing if the string starts with 'o' And if you felt like it, you could make it a one-liner, though I feel like it loses a little bit of its readability that way: return [Field("Savings"), Field("Qty-2for")].map(function(s,p,a){ if (p) return s ? 'on ' + s : ''; s = FormatNumber('0.00', StringToNumber(s.replace(/[^\d\.]/g,''))); return s*1 ? 'Save ' + (Math.floor(s) ? '$' + Math.floor(s): s * 100 + '¢') : '';}).filter(String).join('<br>').replace(/^o.*/,'');
  19. Yeah I think you would still be able to pull this off but it would be easier to answer if I knew a little bit more about how the two codes were concatenated. I'm assuming that the "specific code number" is a sequence number? Is that number formatted to two digits and or is the job number always 4 digits? If the first 4 digits of the "CODE" field is what you based the names of your body pages on, you can use the "Left" function to only capture the first 4 characters on the left: var pg = Left(Field("CODE"), 4); FusionPro.Composition.SetBodyPageUsage(pg + " front", true); FusionPro.Composition.SetBodyPageUsage(pg + " back", true); Or you could use a RexExp to try and match any of your pages at the beginning of the "CODE" field: var pgs = ['GY3A','AN07','H3r','c0d3']; // Your Page Codes var pg = Field("CODE").match(new RegExp('^' + pgs.join('|'), 'i' )); FusionPro.Composition.SetBodyPageUsage(pg + " front", true); FusionPro.Composition.SetBodyPageUsage(pg + " back", true); But again, I could probably offer a more helpful solution if I had a little bit more information about those codes and how they relate to your template. But generally speaking, if there is something unique about that string that allows you to determine which version to use, there's typically a way to write some code to parse that information out.
  20. Woah, apparently I am too slow. Good thing repetition is the mother of learning, right? I will say, though, I had originally written my code to be exactly like that but FP barked at me when I tried to validate. It seemed to me like you have to explicitly check whether a variable is defined. Cool! I did not know that!
  21. I'm pretty sure that's because the field values aren't accessible from OnJobStart. The "Field" function returns the value of a specified field for the current record but when OnJobStart is called, there is no current record. You could get around this by putting this in your OnRecordStart rule. It will only define the 'XDF' variable when it hasn't previously been defined. The result being that 'XDF' is only defined once much like if you were to call it from OnJobStart: var filename = Field("ER.Name").replace(/ /g, '') + '.txt'; if (typeof XDF == 'undefined') XDF = new ExternalDataFileEx("C:\\Shared\\130515_IdealSoluti ons\\" + filename, "\t");
  22. Can you elaborate on what you mean by "I tried to apply a Callback Rule but that didn't work?" Which Callback rule did you write code for? And what was the result that you got from the code you wrote that didn't work? I think dreimer's suggestion is probably the easiest to maintain. You can duplicate the body pages for each version, go to FusionPro > Manage Pages > Page Usage, and edit each page to have a unique name and set it to unused. For example: "Background A" "Background A-back" "Background B" "Background B-back" "Background C" "Background C-back" "Background D" "Background D-back" Then, you can delete the B, C, and D frames from the A postcard and so forth. That way, you don't have to both with toggling individual text frames for every record, instead you just turn "on" the appropriate body page for that record (and all of its text frames). You'd put this in an OnRecordStart callback: var trigger = Field("Postcard"); // Field used to determine which postcard to use FusionPro.Composition.SetBodyPageUsage(trigger, true); FusionPro.Composition.SetBodyPageUsage(trigger + '-back', true); If all four versions have a common back, you could set up your pages as: "Background A" Unused "Background B" Unused "Background C" Unused "Background D" Unused "back" Used And then you'd only have to determine which front to use from your OnRecordStart rule: FusionPro.Composition.SetBodyPageUsage(Field("postcard"), true); And while I feel like that may be the easier way to handle this scenario, I realize it doesn't exactly answer your question. So, if you still want to have the text frames of all four versions on one page, here's how you'd do that: In an OnRecordStart callback rule, you can define the frames associated with each postcard and then suppress the ones that don't match the current version: var trigger = Field("Postcard"); // Field used to determine which postcard to use var frames = []; // Frame names when 'Background A' is used frames['Background A'] = [ 'Frame 1', 'Frame 2', 'Frame 3', 'Frame 4' ]; // Frame names when 'Background B' is used frames['Background B'] = [ 'Frame 5', 'Frame 6', 'Frame 7' ]; // etc for (var i in frames) frames[i].forEach(function(s){FindTextFrame(s).suppress = i != trigger }); Or you could name your text frames like so and simplify the OnRecordStart code: "Background A_1" "Background A_2" "Background A_3" "Background A_4" "Background B_1" "Background B_2" "Background B_3" "Background C_1" "Background C_2" "Background C_3" "Background D_1" "Background D_2" "Background D_3" "Background D_4" "Background D_5" "Background D_6" var trigger = Field("Postcard"); var versions = ['Background A', 'Background B', 'Background C', 'Background D']; var maxFrames = 6; // Most frames any version has while (maxFrames--) versions.forEach(function(s){ try { FindTextFrame(s + '_' + maxFrames).suppress = s != trigger; } catch(e){}});
  23. The problem is that you've defined 'accentColor' outside the scope of the 'Header' function. That if statement needs to be within the function: function Header(str) { if (Field("Color") == "Plum") var accentColor = '<color name="PANTONE 5195 C">'; else if (Field("Color") == "Orange") var accentColor = '<color name="PANTONE 153 C">'; else if (Field("Color") == "Red") var accentColor = '<color name="PANTONE 704 C">'; else if (Field("Color") == "Green") var accentColor = '<color name="PANTONE 361 C">'; else var accentColor = '<color name="PANTONE 5425 C">'; return '<p style="CV Section" leading=40 leadafter=200>' + accentColor + str + '</color></p>'; } Or if you'd like to shorten things up a little bit: function Header(str) { var color = { 'Plum' : '5195', 'Orange': '153', 'Red' : '704', 'Green' : '361' }[Field('Color')] || '5425'; return '<p style="CV Section" leading=40 leadafter=200><color name="PANTONE ' + color + ' C">' + str + '</color></p>'; }
  24. What did you have in mind? You could definitely create a global variable to hold inline paragraph styles that you could then call from other rules: heading = '<p style="Header" br=false leading=140 quad="C">'; body = '<p style="Body" leading=120 quad="L">'; Then your text rules would look like: return heading + 'This is a Centered Header' + body + 'This is left justified body text'; Then you'll be able to adjust the values of those tags by editing the variables in the "JavaScript Globals" rather than modifying them in each of your text rules. For that matter, you could create functions that formatted your text with font styles and sizes if you wanted to: function Header(str) { return '<p style="Header" br=false leading=140 quad="C"><span font="Arial" pointsize="12">' + str + '</span>'; } Then just call it from your text rules: return Header('This is a Centered Header in Arial 12pt');
×
×
  • Create New...