Jump to content

step

Registered Users - Approved
  • Posts

    962
  • Joined

Everything posted by step

  1. Yes, it can be done with FusionPro. In the example that you posted, you have 260 records in your data. However, since you technically only want to create 2 records from that data (one record for 10062 and one record for 10280), you're going to need your data in a format that better lends itself to the output you're trying to create. You could edit the data and assign fields that correspond to each column per record or you could link to your data as an external data file and let JavaScript handle it for you. The latter method will walk through each record of your input data file at the start of the job (in OnJobStart) and determine how many unique CenterID's there are in the data and set the number of records to compose to be equal to the number of unique CenterIDs: var recs = 0; var id = ''; var ex = new ExternalDataFileEx(FusionPro.Composition.inputFileName,'\t'); for (var i=1; i<=ex.recordCount; i++) { if (ex.GetFieldValue(i, 'CenterID') != id) { id = ex.GetFieldValue(i, 'CenterID'); recs++; } } FusionPro.Composition.composeAllRecords = false; FusionPro.Composition.endRecordNumber = recs; Of course you'll also need a way to access that data when you're composing the job. My recommendation for that would be to create a global object or array to hold those values. You can insert the values by tweaking the OnJobStart rule above (and there are plenty of examples on the forum – one of which I posted yesterday). From there it's just a matter of referencing the global object or array for each record rather than the actual fields in FusionPro. As far as the slipsheet goes, since each record will ultimately end up being a new "center," you can probably just create a "slipsheet" body page in addition to the current body page. That will make each "center" start with a slipsheet. I'm not sure what you intend to happen if the number of names and points exceeds what is able to fit on 1 sheet but my suggestion would be to duplicate your body page and use it an overflow page. Anyway, that's how I would do it but hopefully that helps point you in the right direction.
  2. No worries! I just wanted to make sure you were able to accomplish what you were trying to do. If you discover a way to rapidly learn JavaScript, please share haha. My recommendation is simply to participate in this forum. Ask questions and ask for clarification if you don't understand a solution. Of course there are video tutorials as well.
  3. Diane, I just wanted to note that your previous efforts weren't that far off. Here's why they didn't work, though: if(Field ("Name") != "" || Field("Phone") != "" || Field("Email") != "") return NullResource([color="Red"]<none>[/color]); else return Resource("YellowLine"); If you remove the "<none>" tag in the "NullResource" function, the above code will work perfectly. if (Field("Name") == "") if (Field("Phone") == "") if (Field("Email") == "") return Resource("Blank"); else return Resource("YellowLine"); There's actually nothing wrong with the above code but it's important to note that the way it's written is actually interpreted as a nested if statement. Like this: if (Field("Name") == "") { if (Field("Phone") == "") { if (Field("Email") == "") { return Resource("Blank"); } } } else { return Resource("YellowLine"); } if (Field("Name") == ""&&Field("Phone") == ""&&Field("Email") == "")[color="red"];[/color] return Resource("Blank"); else return Resource("YellowLine"); If you were to remove the semi-colon at the end of the if condition, the above code would work as well. The semi-colon is used to separate statements in JavaScript so that particular semi-colon is interrupting the if statement. Yet another way to write this is using the ternary operator: return (Field("Name") || Field("Phone") || Field("Email")) ? Resource("YellowLine") : Resource("Blank");
  4. I see. The easiest thing to do is to create a template that is just the top 1/4th of that artwork with one text frame that returns the coupon number and impose it 4up (1 column, 4 rows) when you're composing it. But I guess if you're adamant about using the 4 up template, you could create a global array that holds your coupon values and shift the first value for each text frame. Create an OnJobStart callback rule that looks like this: var field = 'Coupon'; // Name of the field holding the coupon number var ex = new ExternalDataFileEx(PrimaryInputFile(),','); coupons = []; var recs = ex.recordCount; for (var i=1; i<=recs; i++) coupons.push(ex.GetFieldValue(i, field)); FusionPro.Composition.composeAllRecords = false; FusionPro.Composition.endRecordNumber = recs/4; And the rule that each text frame would return would look like this (make sure that "Re-evaluate this rule for every text flow" is checked): return coupons.shift() || '';
  5. That works for you? As I said before, I (still) don't really understand what you're trying to do and while I'm happy if that code does what you're trying to do, I just don't understand it. You've made an array named 'r'. Within 'r' you've put 4 fields, each within their own array. So assuming you've named your frames 0,1,2, and 3, I still don't understand how that could return a unique value for each frame. If your ultimate goal is to return Field("N_VAR_1") in frame "0", Field("N_VAR_1__2") in frame "1" and so forth, you'd need to modify your code to be: var r = [ [Field("N_VAR_1")],[Field("N_VAR_1__2")],[Field("N_VAR_1__3")],[Field("N_VAR_1__4")] ]; var x = FusionPro.Composition.CurrentFlow.name return r[color="Red"][0][/color][x]; Or just get rid of the 2D array: return [ Field("N_VAR_1"), Field("N_VAR_1__2"), Field("N_VAR_1__3"), Field("N_VAR_1__4") ][FusionPro.Composition.CurrentFlow.name];
  6. I don't understand what you're trying to do. Can you post an example? Are you trying to a return a specific value for a variable, "MyVar1", depending on which coupon field's value is "C1"? If so, your current code could just be modified to look like this: if (Field("COUPON_COD") == "C1") { return Field("N_VAR_1"); } if (Field("COUPON_CO2") == "C1") { return Field("N_VAR_1__2"); } if (Field("COUPON_CO3") == "C1") { return Field("N_VAR_1__3"); } if (Field("COUPON_CO4") == "C1") { return Field("N_VAR_1__4"); } Or: var i = 5; while (--i > 2) if (Field("COUPON_CO" + i) == 'C1') return Field("N_VAR_1__" + i); return (Field("COUPON_COD") == "C1") ? Field("N_VAR_1") : ''; Assuming you've named your text frames, you can see a text frame's name by checking the "Re-evaluate this rule for every text flow" and entering this rule: return FusionPro.Composition.CurrentFlow.name;
  7. So you have 1 page with 4 text frames and each text frame should return 1-4 for the first record and 5-8 for the second record and so forth? When you say that the numbers are already supplied, can you elaborate on how they are supplied? If you are printing numbers 1-20, do you have 20 records with one field or do you have 5 records with 4 fields (one for each text frame)? If it's that latter, you could just assign each of the record's fields to its respective frame. If it's the former, is altering your template so that it only has one text frame and then imposing each record 4up an option? If not, you can still make this work with a little coding but it would be easier to help if I knew what your data/template looked like. Could you collect your template and upload it to the forum?
  8. I think the reason your template is failing is because your code is creating a variable named "Resource Page" but you aren't assigning it to the graphic frame. You either need to type "Resource Page" in the graphic frame property window where it currently says "[Field of Rule]" or change Dan's code to this: var r = Resource("Kafka on the Shore signature pages.pdf"); FusionPro.Composition.repeatRecordCount = r.countPages; r.pagenumber = FusionPro.Composition.repeatRecordNumber; [color="Red"]FindGraphicFrame("ResourcePage").SetGraphic(r);[/color] You could duplicate the first page in your template creating a second page that you toggle on/off from OnRecordStart depending on when you want to duplex. Then you'd just change the variable on the second page's frame from "Resource Page" to "Back Page" and your code would look like this: [color="red"]var duplex = true; // false for 1 sided[/color] var r = Resource("Kafka on the Shore signature pages.pdf"); FusionPro.Composition.repeatRecordCount = r.countPages; r.pagenumber = FusionPro.Composition.repeatRecordNumber; FusionPro.Composition.AddGraphicVariable("Resource Page", r); [color="red"]FusionPro.Composition.AddGraphicVariable("Back Page", Resource("dummy.pdf")); FusionPro.Composition.SetBodyPageUsage(2, duplex);[/color] Alternatively, your template could remain unchanged and you could repeat each page twice (once for the front and once for the back) pulling in the "dummy" resource for even repeats: var r = Resource("Kafka on the Shore signature pages.pdf"); FusionPro.Composition.repeatRecordCount = r.countPages * 2; var rep = FusionPro.Composition.repeatRecordNumber; if (rep % 2) r.pagenumber = Round(rep/2,0); else r = Resource("dummy.pdf"); FusionPro.Composition.AddGraphicVariable("Resource Page", r);
  9. One nice thing about the filter method is that you can pass it a callback function to determine whether to remove the element from the array or not. For example, if you wanted to include the comma as part of the first element in your array (the lastname field), you could write a function to filter the elements if they are not strings or if the string is only a comma indicating that the last name field is empty: return [ Trim(Field("Mem_Lastname"))[color="Red"] + ','[/color], Trim(Field("Mem_Firstname")), Trim(Field("Mem_MiddleInit")) ].filter([color="red"]function(s){ return s.replace(',', ''); }[/color]).join(' '); Using the .map method would allow you to perform a function on each element of the array. This is helpful in situations that you might find yourself being repetitive in your code – with the Trim function for example. You could also add the comma to the first element of your array within that function like this: return [ Field("Mem_Lastname"), Field("Mem_Firstname"), Field("Mem_MiddleInit") ][color="red"].map(function(s,p) { return Trim(s) ? Trim(s) + (!p ? ',' : '') : ''; })[/color].filter(String).join(' ');
  10. Weird. I'm running almost that exact configuration (except I'm running Acrobat X 10.1.1) without seeing this issue. I would have just assumed it was a font conflict after updating the OS that could be resolved by bombing your font cache.
  11. I still don't understand what you're trying to do. Could you upload an example of the output you're trying to produce?
  12. Are you asking how to make an 22" x 8.5" book fit on an 11"x17" sheet? I can pretty confidently say that FusionPro does not have that capability. If you impose your landscape file on a larger press sheet (a 22" x 17" sheet for example) and rotate it 90 degrees, do you get the layout you're aiming for? Did I completely misunderstand your question? It might be helpful if you show us what you want it to look like.
  13. Sorry, Lisa, I should have given that a try before I posted it as a solution. I think what's happening is that OnRecordStart is being called during pre-processing to determine the total number of records that will be generated. Since the range is set to "1" and "totalRecords" (which is unknown at the time of pre-processing), pre-processing will determine that only one record will be created thus making the total records 1. You'd have to add the following to tell pre-processing that all records should be composed when you're pre-processing the job so that the totalRecordCount is accurate: var ranges = [ 1, FusionPro.Composition.totalRecordCount ]; function CheckRanges(val) { for (var i in ranges) if (val == ranges[i] || ((ranges[i] instanceof Array) && val >= ranges[i][0] && val <= ranges[i][1])) return true; return false; } FusionPro.Composition.composeThisRecord = [color="Red"]FusionPro.Composition.inPreprocessing || [/color]CheckRanges(CurrentRecordNumber()); Alternatively, you could determine the total number of records yourself by incrementing a variable each time a record is pre-processed: [color="red"]this.total = this.total || 0; if (FusionPro.Composition.inPreprocessing) ++this.total;[/color] var ranges = [ 1, [color="Red"]this.total[/color] ]; function CheckRanges(val) { for (var i in ranges) if (val == ranges[i] || ((ranges[i] instanceof Array) && val >= ranges[i][0] && val <= ranges[i][1])) return true; return false; } FusionPro.Composition.composeThisRecord = CheckRanges(CurrentRecordNumber());
  14. Okay well now I understand. The rule in your template is not the same as the rule that you posted to the forum. The rule in your template is missing the "name" property for the "color" tag and it's looking for the HTML entity of the '@' symbol rather than the '@' symbol itself: return Field("Email").replace(/[color="red"]& # 6 4 ;[/color]/g, '[color="Red"]<color ="Black">& # 6 4 ;[/color]</color>'); Since your data isn't passing the "@" as the HTML entity, there's no reason to search for it in that field. So ironically, if I change your rule to match the code in your original post (after the forum converted the entity to the @ symbol), I get the desired result: return Field("Email").replace(/@/g, '<color name="Black">@</color>');
  15. Hilary, I think what David is saying here is that maybe you're inserting your "Email" field into your text frame as opposed to the rule you used to manipulate your "Email" field. You can change your rule to something like this to make sure your template is pulling in the correct rule: return "Yep, I'm the Email rule!"; I agree that your rule looks like it should work. We'd probably have to see your actual template to get a better idea of what's happening. That being said, another thing you could try is using span tags rather than color tags: return Field("Email").replace('@','<span color="Black">@</span>');
  16. Sure, just right-click on the column in the "layout" tab of FusionPro Imposer and click "Rotate column 180 degrees."
  17. Actually, as long as pre-processing is occurring, FusionPro already knows how many records there are. That information is accessible through "FusionPro.Composition.totalRecordCount". If your job is imposing, then pre-processing is already occurring. Otherwise, you'll need to specifically tell the job to pre-process by putting this in an OnJobStart rule: FusionPro.Composition.forcePreprocessing = true; Then it's just a matter of making the following edit to your OnRecordStart code: var ranges = [ 1, [color="Red"]FusionPro.Composition.totalRecordCount[/color] ]; function CheckRanges(val) { for (var i in ranges) if (val == ranges[i] || ((ranges[i] instanceof Array) && val >= ranges[i][0] && val <= ranges[i][1])) return true; return false; } FusionPro.Composition.composeThisRecord = CheckRanges(CurrentRecordNumber()); Or more succinctly: FusionPro.Composition.composeThisRecord = [1,FusionPro.Composition.totalRecordCount].indexOf(CurrentRecordNumber()) > -1
  18. If you're using FusionPro 8 or later, it's really easy. All you have to do is set a global variable in the OnJobStart callback rule to initialize the number. Like this: OnJobStart number = 400; // Edit this starting number if needed Then you create a text rule: return number++; Make sure "Re-evaluate this rule for every text flow" is checked. That's the most important step because that makes FusionPro run the rule for every text frame it's called in. So, every time the rule is called, it increments 'number' by 1. Your first text frame will show "401", the second will show "402" and so forth throughout the job.
  19. Probably the easiest way to handle this would be to do a find/replace all on the "dot" in a text editor and replace it with the HTML bullet entity (•) But you could certainly try it this way too: return Field("PROFESSIONAL MEMBERSHIPS").replace(new RegExp(Chr(8226), 'g'), '<color name="Lime">•</color>');
  20. As I noted in this thread (despite the last post crediting Dan haha), there's a hacky way to do what you're trying to do. You can get the imposition file from the cfg file (JobOptions) and load it up as an external data file at the start of the job. Once you've loaded it, parse out the values for the three imposition columns and multiply them together and assign it to a global variable: OnJobStart // Get the name of the FPI file from the cfg file var fpiFile = FusionPro.Composition.JobOptions["ImpositionDefFileName"]; // Import the .fpi file as an external data file delimited by returns (\n) var ex = new ExternalDataFileEx(fpiFile,'\n'); // Print Error if the template can't link to the fpi file if(!ex.valid) Print('* Failed to link to the FPI file in OnJobStart. Assuming 1 up *'); // Create an object with the 'Repeat' properties on the fpi document var fpi = {}; for (var i=0; i<=ex.recordCount; i++){ var [prop,val] = ex.GetFieldValue(i,0).split("="); if (/Repeat/.test(prop)) fpi[prop] = val; } // Get the values of the 3 columns in the imposition setting and put them in "array" var array = []; ['Primary', 'Secondary', 'Tertiary'].forEach(function(s){ array.push([ fpi[s + 'RepeatDirection'], fpi[s + 'RepeatCount']]); }); // Remove the "Stack" Column and "None" Column // Assign the Vertical & Horizontal values to vert & hor (default to 1) var [vert,hor] = array.filter(function(m){ return (m[0] != "Stack" && m[0] != "None"); }).map(function(s){ return Int(s[1]) || 1; }); // Multiply horizontal and vertical counts to determine imposition impo = vert*hor; Then your code could be modified to: var chunkSize = FusionPro.Composition.JobOptions["RecordsPerChunk"]; var stack= chunkSize/[color="Red"]impo[/color] ; if(cover = FusionPro.Composition.inputRecordNumber % stack == 1) FusionPro.Composition.repeatRecordCount = 2; var page = (cover && FusionPro.Composition.repeatRecordNumber == 1) ? 'SetSheet' : 'Page1'; FusionPro.Composition.SetBodyPageUsage(page,true); }
  21. I think the only way to do this is to use TextMeasure. You'd have to check the width of the string as it relates to the width of the text frame for each item that you add. If the item causes the string to be greater than the width of the text frame, add it with a page break; otherwise, add it with a dash: /* // Make sure that "Treat returned strings as tagged text" and // "Re-evaluate this rule for every text flow" is checked. // Make sure that you have given the frame a name */ // Width of the frame. Set to 3 inches when validating the rule. var frameWidth = !FusionPro.inValidation ? GetSettableTextWidth(FindTextFrame(FusionPro.Composition.CurrentFlow.name)) : 21600; var str = Field('Extra Line').split(','); // Create an array of cars by splitting on a comma (,) var result = ''; // String to hold the result while (str.length) { var cat = [result,Trim(str.shift())].filter(String); // Array to hold concatenated string var glue = ' - '; // Join the new car to the result string with a dash (-) by default if (getTextWidth(cat.join(glue)) > frameWidth) // If joining with a dash exceeds the width of the frame, glue = '<br>'; // join with a line break instead result = cat.join(glue); // Set the result to the concatenated string } return result; /* // Helper function that determines the width of a string ('input') */ function getTextWidth(input){ var tm = new FusionProTextMeasure; tm.pointSize = "12pt"; // Font size of the string we're returning tm.font = "Helvetica"; // Font face of the string we're returning tm.CalculateTextExtent(input); return tm.textWidth; }
  22. I think what you're referencing is a div as opposed to an HTML table. Yes, in FusionPro, the "margin" refers to the area inside the cell. In FusionPro's table object, margins are a property of a given cell – not of the entire table. You are defining the bottom margin of the first cell of the first row of your table as 1.2 points (Top and Bottom margins should be entered as 10ths of a point – 12px = 9pt*10 = 90 in your case). Check out page 55 of the TagsRefGuide.pdf for more information on margins as they relate to FusionPro tables. After you've created your table, I'd add an additional row without borders and use the minHeight property of the row to give it a precise height: // .. table stuff var row = myTable.AddRow(); row.minHeight = 90; // 9 pts = 12 px
  23. This means that FP tried to output a record with no body pages turned on. You'd have to post the actual code that you're using in your OnRecordStart rule for me to tell you how to fix it. The code that I wrote simply tells FusionPro to compose a record or not to compose a record; it does not handle turning turning on/off body pages. But I imagine if you added the following line to turn on at least the first page, the error would go away: FusionPro.Composition.SetBodyPageUsage(1, true); By the way, after reviewing the code that I posted earlier, I noticed a problem with the regular expression that triggered the records composition. You should make the below alterations for more reliable results (I also commented what is happening in the code for better grasp of the concept): var records = [1, 8,'4-6']; // Records to compose // Turn the array into a Regular Expression records = records[color="Red"].filter(String)[/color].map(function(s){ s = Str(s); // convert the value to a string var [a,b] = s.split('-'); // Split the string into an array if there is a dash a = Int(a); // Set lower range limit (a) to an integer b = Int(b || a); // Set upper range limit (b) to an integer (b == a if b is null) s = [a]; // Array to hold all values for a range while (a < b) // Until we reach the upper range limit (b), s.push(++a); // increment 'a' and push it into the array of values (s) return s.join('|'); // Convert the array back to a string, delimited by a pipe (|) }).join('|'); // Convert the entire 'records' array into a string delimited by a pipe (|) // Determine if we should compose this record FusionPro.Composition.composeThisRecord = new RegExp([color="red"]'^(' +[/color] records [color="red"]+ ')$'[/color], '').test(FusionPro.Composition.inputRecordNumber); [color="red"]FusionPro.Composition.SetBodyPageUsage(1, true); // Turn on page 1[/color] /* The above example output: records = '1|8|4|5|6' The Regular Expression used will be: /^(1|8|4|5|6)$/ Testing the input number against the above Regular Expression will return 'true' if it's one of the numbers in the regex and 'false' if it's not. Therefore, the 'composeThisProperty' will in turn reflect the presence of a given record in 'records'. */
  24. You can do this by creating an array of records you want to compose and then comparing the inputRecordNumber against that array to determine whether a record should be suppressed or not: var records = [1, 8,'4-6']; // Records to compose records = records.map(function(s){ s = String(s); var [a,b] = s.split('-'); a = Int(a); b = Int(b || a); s = [a]; while (a < b) s.push(++a); return s.join('|'); }).join('|'); FusionPro.Composition.composeThisRecord = new RegExp(records, '').test(FusionPro.Composition.inputRecordNumber); Note that the order doesn't matter and that you specify a range of records as long as the range is a string (within quotes) – otherwise the numbers will just be subtracted. The above code would compose records 1,4,5,6, and 8. Alternatively it seems like you could only compose records that have a unique back by setting up a global array: var backs = []; And then comparing the back to be used for a specific record to the array. If it's not in the array, that means it's unique so compose the record and push it into the array. If it exists in the array, then you can skip that record because you've already composed a record with that back. To me, that seems easier than searching through your data for records to build a "proof" list but I may be missing something. var back = Field("Back"); // Field to determine which back page to turn on if (backs.indexOf(back) > -1) FusionPro.Composition.composeThisRecord = false; backs.push(back);
×
×
  • Create New...