Dynamic text and page breaks for Printing - InfoPath Dev Sign in | Join | Help in General InfoPath (Entire Site) InfoPath Dev InfoPath Dev is dedicated to bringing you the information and tools you need to be successful in your Microsoft Office InfoPath development projects. Home Blogs Forums Photos Downloads InfoPath Dev » InfoPath » General » Dynamic text and page breaks for Printing Dynamic text and page breaks for Printing Last post 07-09-2015 08:44 AM by jack eagly. 22 replies. Page 1 of 2 (23 items) 1 2 Next > Sort Posts: Oldest to newest Newest to oldest Previous Next 10-19-2005 06:56 AM Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Dynamic text and page breaks for Printing Reply Contact Ok, here's what I'm faced with. I need to create a print view to display relevant data based on input to my form. I have most of this print view done, except for one section.On this section, there will be rows in a table based on what the customer has bought. However, to make things look professional the rows are not allowed to be "split" across pages. Additionally, when the table breaks to a new page, the header of the page (seperate text) as well as the header on the table must be repeated.This whole project has been basically to convert all of our old proposal forms that were made in Word using very primitive calculations and functionalities into InfoPath documents with all of their rich and in-depth content and automating almost all of the calculations. Anyway, that's just to say that I have a Word document now that I am trying to re-create within InfoPath. I know that you can use the Word Print Engine to format things from InfoPath, but after playing around with that I couldn't see how that was going to be any easier than just doing it in InfoPath, if you could do it at all in Word. Here are some screenshots of what I'm looking for. Disregard the footer line and text for now, that will come later.What I have now:http://www.mattfaus.com/misc/ss_bad.JPGSome of the Word formatting options that are giving the necessary results when using the archaic Word document format:http://www.mattfaus.com/misc/ss_option.JPGGoal (disregard footer for now):http://www.mattfaus.com/misc/ss_good.JPG---------------Matt Faus Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge 10-19-2005 07:12 AM In reply to trentdudei Joined on 09-16-2005 USA Posts 20 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact I feel your pain - most of my forms are based on replacing our old Word standards. I hopefully will be proved wrong in saying this, but until Infopath addresses the shortcomings in the printing department, we are relegated to page breaks and code work arounds. Hopefully the next release of Infopath will address tables (and ideally sections) as they break in the printed document. Again, I hope I'm wrong, and if someone knows a better way to break tables for printing, I'd be glad to learn. 10-19-2005 10:05 AM In reply to vt_asparagus Joined on 08-05-2005 USA Posts 285 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact I completely agree. The printing functionality is not great. I was talking with another on another thread and they were complaining about printing functionality. If you go to InfoPath's fact sheet they specifically state that this is not a reporting tool, it is a data capture tool. They state to use a 3rd party tool for reporting. I know you really did not want to hear that. Jasonhttp://www.k2distillery.com/ 10-19-2005 11:10 PM In reply to Patrick Halstead Joined on 08-07-2006 Posts 5,112 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Unfortunately, you cannot use dynamic data in your header, so Company Name is probably hard. I have heard rumors that this is fixed in some future release ....Controlling where page breaks occur is possible but not programmatically so, which means you will get bad page breaks and your printed form will likely cut off. You can print InfoPath forms through Word using a special Print XSL. This is documented. Unfortunately, it's not easy to do and some things are still limited - like dynamic data in headers and footers. My suggestion would be to look at that. You should be able to reuse a template in Word from InfoPAth to print.Patrick Halstead [InfoPath MVP]InfoPathDev Patrick HalsteadProject Manager at Qdabra 10-21-2005 06:30 AM In reply to Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Just reporting some workarounds:To use dynamic data in your "header", go to Format -> View Properties -> Page Setup and set your top margin to a little less (I set mine to .4 inches). Then you can make your own "header" by simply typing near the top of the page and/or inserting controls.Here's how I plan to work around my problems described above. I will have one repeating section and within this section there will be a (1) page break line (2) dynamic header information (3) repeating table. I plan to use JScript to format my data and programatically insert it into my nested repeating table. Using code, I am going to keep a "line count" for the table, and using trial and error will come up with the correct line count that will keep the table from breaking across pages. After I format my data, I will take the line count of the new row I am about to add, and if it makes the table line count exceed my equilibrium line count, then instead of adding this row to the current nested table, I will create a new section from the repeating section control (with page break, header, nested table) and insert the new row into the first row of the nested table within the second instance of the repeating section.Hope this makes sense! (Pardon spelling/grammar errors, it's a little early)---------------Matt Faus Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge 11-16-2005 09:58 AM In reply to cjellick Joined on 11-10-2005 USA Posts 9 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Matt,Your work around sounds great. I'm experiencing more or less the same problem. Has you solution worked? If so, are you able to share the script you had to write to get it to work?~Craig 11-17-2005 11:57 AM In reply to Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Sure thing. A little bit more information: My form cycles through 3 master tables that have all of our products in them and combines them into one big "Product List" that goes to the customer. However, we only want to add items from the master tables if the customer actually bought the product and it is going to appear on their proposal (and a few other exception). The three master tables are on my secondary data source (FSHardware, FSSoftware, and FSServices). I included a picture for the schemas of the two data sources below. Hope this helps, let me know if you need any more help! I might clean out all of the "sensitive" data of my form and just post the XSN for inspection. By the way, I'm am still pretty new at this so I might be doing some of this stuff that long/hard way, but it worked for me! This code estimates page breaks pretty accurately and when it makes mistakes it makes them on the safe side and goes ahead and breaks the page even tho it might be a little early (better to have some extra white space at the bottom of a page than have a row being split between two pages).http://www.mattfaus.com/misc/schema.JPGfunction XDocument::OnSwitchView(eventObj){ if(XDocument.View.Name == "Customer Proposal Form") generateProductList(); }function generateProductList(){ /* This function will loop through each item in the FSSoftware, FSHardware, and FSServices section and determine whether or not they need to be in the Product List. If so, they will be formatted and added, if not, next item will be evaluted. Some special formatting has to occur for live scanners and software maintenance packages that include 1 year of maintenance. */ var lineCount = 0; var currentSection = 1; var scanFlag = "LITE"; // Nodes for the data we are going to read // from form var h_nodes = xDoc.selectNodes( "//my:h_item" ); var s_nodes = xDoc.selectNodes( "//my:s_item" ); var e_nodes = xDoc.selectNodes( "//my:e_item" ); // from price list var pl_h_nodes = intDoc.selectNodes( "//pl:FSHardware" ); var pl_s_nodes = intDoc.selectNodes( "//pl:FSSoftware" ); var pl_e_nodes = intDoc.selectNodes( "//pl:FSServices" ); // Nodes for the table we are going to build var tableNodes = xDoc.selectNodes( "//my:cp_prodDetail" ); var eg_tableNode = tableNodes.nextNode(); // get a node to be used for cloning tableNodes.removeAll(); // clear all so that we can rebuild from scratch var sectionNodes = xDoc.selectNodes( "//my:cp_prodDetails" ); var eg_sectionNode = sectionNodes.nextNode(); // get a node to be used for cloning sectionNodes.removeAll(); // clear all so that we can rebuild from scratch var newSect = eg_sectionNode.cloneNode( true ); xDoc.selectSingleNode( "//my:cp_prodDetails_TOP" ).appendChild( newSect ); //xDoc.selectSingleNode( "//my:cp_prodDetails_TOP" ).appendChild( newSect.cloneNode(true) ); var newRow = eg_tableNode.cloneNode( true ); xDoc.selectSingleNode( "//my:cp_prodDetails" ).appendChild( newRow ); // For some stupid reason, JScript allows a function to return an array, but if you // try to pass an array as an argument it comes out mangled within the function // you're trying to pass to. Therefore, I will be passing lineCount and currentSection // individually and returning them packaged in an array retArray = genSection( s_nodes, pl_s_nodes, currentSection, lineCount, "s" ); //unpackage return array currentSection = retArray[0]; lineCount = retArray[1]; retArray = genSection( h_nodes, pl_h_nodes, currentSection, lineCount, "h" ); //unpackage return array currentSection = retArray[0]; lineCount = retArray[1]; retArray = genSection( e_nodes, pl_e_nodes, currentSection, lineCount, "e" ); //unpackage return array currentSection = retArray[0]; lineCount = retArray[1]; // Now we must perform some clean-up // delete the first line - it is a remenant from last generation of product list // might be the blank row that is automaticaly inserted by InfoPath // or it might be a row that we generated and stuck in. Either way it is redundant and must be removed var remenant = xDoc.selectSingleNode( "//my:cp_prodDetail" ); if( remenant.selectSingleNode( "following-sibling::my:cp_prodDetail" ) ) // make sure that it is not the only row - otherwise we will have no eg_tableNode if we leave the view and come back { xDoc.selectSingleNode( "//my:cp_prodDetails" ).removeChild( remenant ); } }function genSection( my_nodes, pl_nodes, currentSection, lineCount, prefix ){ // "sample" nodes that we will be cloning later to add to the table var eg_tableNode = xDoc.selectSingleNode( "//my:cp_prodDetail" ); var eg_sectionNode = xDoc.selectSingleNode( "//my:cp_prodDetails" ); // loop through all of the nodes from the source table, determine if they belong in the destination table, and add them while( pl = pl_nodes.nextNode() ) { // determine whether or not the customer even bought this product var bought = false; while( my = my_nodes.nextNode() ) { if( getNodeTypedValue(my.selectSingleNode( "my:" + prefix + "_prodName" )) == getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_partNum" ) ) ) { bought = true; break; // we know it has been bought, that's all we need to know } }// end while() looping through all h_nodes in the form my_nodes.reset(); // reset NodeList iterator // if the product belongs in the list // we want it in the list when: // the customer has bought the item // AND it is not a maintenance item // AND it is not the special promotion item if( bought && pl.selectSingleNode( "pl:" + prefix + "_partNum" ).text.toLowerCase().indexOf( MAINT_FLAG ) == -1 // make sure it is not a live scanner maintenance item && pl.selectSingleNode( "pl:" + prefix + "_partNum" ).text != SPECIAL_PROMO_FLAG )// make sure it it not the user defined discount { // every new row has a title line in it - this counts as 2 lines var rowLines = 2; // copy XML structure var newRow = eg_tableNode.cloneNode(true); // get column nodes in our current working row var partNum = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_partNum" )); var prodName = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_name" )); var descrip = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_descrip" )); var unitPrice = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_price" )); var maint = MANUWARRANTY; // get the linecount for the description rowLines += countDescripLines( descrip ); if( lineCount + rowLines > MAX_LINES_PER_PAGE ) { // must insert a new section lineCount = rowLines; currentSection += 1; // add a new section (break to new page) xDoc.selectSingleNode( "//my:cp_prodDetails_TOP" ).appendChild( eg_sectionNode.cloneNode( false ) ); } else { lineCount += rowLines; } // there will never be any maintenance charges for the services products if( prefix == "e" ) maint = "N/A"; // get the maintenance cost or code for software category if( prefix == "s" ) maint = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_maint_year_2" )); // get the maintenance if it is a live scanner, otherwise it is MANUWARRANTY - the default if( prefix == "h" // performance boost && (model = pl.selectSingleNode( "pl:h_partNum" ).text).toLowerCase().indexOf( "lite" ) != -1 ) // determine if this is live scanner or not by looking at part number { model = model.charAt( model.length - 1); maint = intDoc.selectSingleNode( "//pl:FSHardware[ pl:h_partNum = 'X-" + model + "e-maint']/pl:h_price" ).text; } // if maintenance wound up being a number, we must format it var maintNum = parseFloat(maint); if( !isNaN(maintNum) ) { // actual dollar amount if( maintNum > 0 ) maint = dollarFormat( maint ); // warranty code else if( maintNum == WARRANTY_MANU ) maint = MANUWARRANTY; else if( maintNum == WARRANTY_NA ) maint = "N/A"; } // set nodes setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_partNum"), partNum ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_prodName" ), prodName ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_descrip" ), descrip ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_price" ), unitPrice ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_maint" ), maint ); // add row to table xDoc.selectSingleNode( "//my:cp_prodDetails[" + currentSection + "]" ).appendChild( newRow ); }// end if( bought ) }// end while() looping through all pl_h_nodes var r = new Array(currentSection, lineCount); return r;}function countDescripLines( str ){ // max characters per line (estimate how line will wrap) var chars_per_line = 45; // lines in this description var lines = 0; // split into array of line breaks - we KNOW these will be AT LEAST one line str = str.split( "\n" ); for( i = 0; i < str.length; i++ ) { lines += Math.ceil(str.length / chars_per_line); } return lines;}---------------Matt Faus Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge 11-17-2005 10:30 PM In reply to Patrick Halstead Joined on 08-07-2006 Posts 5,112 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Hi Matt,So you can do dynamic data in a header that appears on every page? I thought this was impossible. If you have a solution, you have figured something out that nobody else ever has. Printing the header on the first page is easy, but on every page? The layout code workaround in JScript is very interesting. In fact, it's so interesting that I think it can be used for many many InfoPath solutions. Great job!Patrick Halstead [InfoPath MVP]InfoPathDev Patrick HalsteadProject Manager at Qdabra 11-18-2005 06:19 AM In reply to Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Well, it's not EXACTLY a "header", but it looks and performs almost exactly the same. If you just make the top margin of the view you're working in less than default, you can put whatever you want (dynamic/static) at the top of each page (right beneath a page break) and it will look like a header. Or, if you want a page with no header, just put whitespace.I'm glad you think my JScript workaround is useful! However, I hope it becomes obsolete with MS's decision to add better print support. ( *sheesh* )---------------Matt Faus Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge 11-18-2005 09:54 AM In reply to JSG Joined on 11-18-2005 Posts 3 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Hello -I tried changing my margins, typing some text, it doesn't behave like a header. So... just to be clear, I'm supposed to:1. Select View2. Click "View Properties"3. Click "Page Setup"4. Change top margin to something less than default (like .4)5. Click OK6. Go top of page, type some text and/or add control7. Print preview, on each page I'll see the text and/or control I added?-JG 11-18-2005 10:48 AM In reply to Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Precisely!---------------Matt Faus Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge 11-18-2005 11:09 AM In reply to JSG Joined on 11-18-2005 Posts 3 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Matt, Thanks a lot for getting back me!It must be me (I haven't had lunch and I've sitting for hours trying to find a workaround for this problem!), but this just doesn't seem to work. I hit ctl+home to make sure I was at the very top of the view.I just double checked, and all is I described above. Yet, if I add somethign to the top of the view, it only shows up at the top of page one, nothing else. Do I need to add page breaks and text/controls everywhere I want the header? Thanks again.JSG-JG 11-18-2005 11:25 AM In reply to Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Yes, to create the header of each consecutive page you must insert a page break and type directly underneath that. Insert a page break with Insert -> Page Break. Remember that this is a psuedo-header that you are manually creating - hence it being a "workaround". If the number of pages that you have is variable (and therefore so is the number of headers) you will have to create a repeating section with a page break line and psuedo-header at the top and repeat it. This is what my code does. Stay tuned for a full "How To" write up on this issue.---------------Matt Faus Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge 11-21-2005 12:52 AM In reply to Coita Thierry Joined on 12-27-2004 Switzerland Posts 823 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact Hi,I want to give another way to make your word print view!In my opinion I think is easiest to wright a wordML transformation file! It's a simple xsl but with the power of word (prefix of namespace for wordML is w:)It's very easy to use you have a good reference schema that describe you all the things that you can made with wordML (100% compatible with normal word)! If you don't find what you want in this, you can make what you wan't in word save as xml and see how word has made to make the process that you need! For example the problem of this topic can be with wordml very easy to solve!And the only things that you have to code in infopath is the xsl transformation! I think that can be more quick to do as the code that you use! You don't have word 2003. Microsoft provide you a free wordML Viewer!Me I have do like this for make my print view it goes very well!This mail is only for give some other work around to create a print view!++ThierryEvery moment hesitated is a moment gone for life!!! Think about it Infopath 2007, Langage: C#2.0 (Modèle Objet 2003)merci de lire ceci 02-07-2006 09:53 AM In reply to Matt Faus Joined on 08-18-2006 Dallas, Texas Posts 1,558 Re: Dynamic text and page breaks for Printing Mark as Not AnswerMark as Answer... Reply Contact As a follow-up for anyone browsing the archives of the forum, this thread resulted in this HowTo:http://infopathdev.com/howto/tutorials/default.aspx?i=80c11a66b08a4572bc2b17f391319a0f---------------Matt FausInfoPath Dev Texas Matt Faus / Microsoft InfoPath MVPQdabra® Software / Streamline data gathering to turn process into knowledge Page 1 of 2 (23 items) 1 2 Next > Copyright © 2003-2019 Qdabra Software. All rights reserved.View our Terms of Use.
function XDocument::OnSwitchView(eventObj){ if(XDocument.View.Name == "Customer Proposal Form") generateProductList(); }function generateProductList(){ /* This function will loop through each item in the FSSoftware, FSHardware, and FSServices section and determine whether or not they need to be in the Product List. If so, they will be formatted and added, if not, next item will be evaluted. Some special formatting has to occur for live scanners and software maintenance packages that include 1 year of maintenance. */ var lineCount = 0; var currentSection = 1; var scanFlag = "LITE"; // Nodes for the data we are going to read // from form var h_nodes = xDoc.selectNodes( "//my:h_item" ); var s_nodes = xDoc.selectNodes( "//my:s_item" ); var e_nodes = xDoc.selectNodes( "//my:e_item" ); // from price list var pl_h_nodes = intDoc.selectNodes( "//pl:FSHardware" ); var pl_s_nodes = intDoc.selectNodes( "//pl:FSSoftware" ); var pl_e_nodes = intDoc.selectNodes( "//pl:FSServices" ); // Nodes for the table we are going to build var tableNodes = xDoc.selectNodes( "//my:cp_prodDetail" ); var eg_tableNode = tableNodes.nextNode(); // get a node to be used for cloning tableNodes.removeAll(); // clear all so that we can rebuild from scratch var sectionNodes = xDoc.selectNodes( "//my:cp_prodDetails" ); var eg_sectionNode = sectionNodes.nextNode(); // get a node to be used for cloning sectionNodes.removeAll(); // clear all so that we can rebuild from scratch var newSect = eg_sectionNode.cloneNode( true ); xDoc.selectSingleNode( "//my:cp_prodDetails_TOP" ).appendChild( newSect ); //xDoc.selectSingleNode( "//my:cp_prodDetails_TOP" ).appendChild( newSect.cloneNode(true) ); var newRow = eg_tableNode.cloneNode( true ); xDoc.selectSingleNode( "//my:cp_prodDetails" ).appendChild( newRow ); // For some stupid reason, JScript allows a function to return an array, but if you // try to pass an array as an argument it comes out mangled within the function // you're trying to pass to. Therefore, I will be passing lineCount and currentSection // individually and returning them packaged in an array retArray = genSection( s_nodes, pl_s_nodes, currentSection, lineCount, "s" ); //unpackage return array currentSection = retArray[0]; lineCount = retArray[1]; retArray = genSection( h_nodes, pl_h_nodes, currentSection, lineCount, "h" ); //unpackage return array currentSection = retArray[0]; lineCount = retArray[1]; retArray = genSection( e_nodes, pl_e_nodes, currentSection, lineCount, "e" ); //unpackage return array currentSection = retArray[0]; lineCount = retArray[1]; // Now we must perform some clean-up // delete the first line - it is a remenant from last generation of product list // might be the blank row that is automaticaly inserted by InfoPath // or it might be a row that we generated and stuck in. Either way it is redundant and must be removed var remenant = xDoc.selectSingleNode( "//my:cp_prodDetail" ); if( remenant.selectSingleNode( "following-sibling::my:cp_prodDetail" ) ) // make sure that it is not the only row - otherwise we will have no eg_tableNode if we leave the view and come back { xDoc.selectSingleNode( "//my:cp_prodDetails" ).removeChild( remenant ); } }function genSection( my_nodes, pl_nodes, currentSection, lineCount, prefix ){ // "sample" nodes that we will be cloning later to add to the table var eg_tableNode = xDoc.selectSingleNode( "//my:cp_prodDetail" ); var eg_sectionNode = xDoc.selectSingleNode( "//my:cp_prodDetails" ); // loop through all of the nodes from the source table, determine if they belong in the destination table, and add them while( pl = pl_nodes.nextNode() ) { // determine whether or not the customer even bought this product var bought = false; while( my = my_nodes.nextNode() ) { if( getNodeTypedValue(my.selectSingleNode( "my:" + prefix + "_prodName" )) == getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_partNum" ) ) ) { bought = true; break; // we know it has been bought, that's all we need to know } }// end while() looping through all h_nodes in the form my_nodes.reset(); // reset NodeList iterator // if the product belongs in the list // we want it in the list when: // the customer has bought the item // AND it is not a maintenance item // AND it is not the special promotion item if( bought && pl.selectSingleNode( "pl:" + prefix + "_partNum" ).text.toLowerCase().indexOf( MAINT_FLAG ) == -1 // make sure it is not a live scanner maintenance item && pl.selectSingleNode( "pl:" + prefix + "_partNum" ).text != SPECIAL_PROMO_FLAG )// make sure it it not the user defined discount { // every new row has a title line in it - this counts as 2 lines var rowLines = 2; // copy XML structure var newRow = eg_tableNode.cloneNode(true); // get column nodes in our current working row var partNum = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_partNum" )); var prodName = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_name" )); var descrip = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_descrip" )); var unitPrice = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_price" )); var maint = MANUWARRANTY; // get the linecount for the description rowLines += countDescripLines( descrip ); if( lineCount + rowLines > MAX_LINES_PER_PAGE ) { // must insert a new section lineCount = rowLines; currentSection += 1; // add a new section (break to new page) xDoc.selectSingleNode( "//my:cp_prodDetails_TOP" ).appendChild( eg_sectionNode.cloneNode( false ) ); } else { lineCount += rowLines; } // there will never be any maintenance charges for the services products if( prefix == "e" ) maint = "N/A"; // get the maintenance cost or code for software category if( prefix == "s" ) maint = getNodeTypedValue( pl.selectSingleNode( "pl:" + prefix + "_maint_year_2" )); // get the maintenance if it is a live scanner, otherwise it is MANUWARRANTY - the default if( prefix == "h" // performance boost && (model = pl.selectSingleNode( "pl:h_partNum" ).text).toLowerCase().indexOf( "lite" ) != -1 ) // determine if this is live scanner or not by looking at part number { model = model.charAt( model.length - 1); maint = intDoc.selectSingleNode( "//pl:FSHardware[ pl:h_partNum = 'X-" + model + "e-maint']/pl:h_price" ).text; } // if maintenance wound up being a number, we must format it var maintNum = parseFloat(maint); if( !isNaN(maintNum) ) { // actual dollar amount if( maintNum > 0 ) maint = dollarFormat( maint ); // warranty code else if( maintNum == WARRANTY_MANU ) maint = MANUWARRANTY; else if( maintNum == WARRANTY_NA ) maint = "N/A"; } // set nodes setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_partNum"), partNum ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_prodName" ), prodName ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_descrip" ), descrip ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_price" ), unitPrice ); setNodeTypedValue( newRow.selectSingleNode( "my:cp_pd_maint" ), maint ); // add row to table xDoc.selectSingleNode( "//my:cp_prodDetails[" + currentSection + "]" ).appendChild( newRow ); }// end if( bought ) }// end while() looping through all pl_h_nodes var r = new Array(currentSection, lineCount); return r;}function countDescripLines( str ){ // max characters per line (estimate how line will wrap) var chars_per_line = 45; // lines in this description var lines = 0; // split into array of line breaks - we KNOW these will be AT LEAST one line str = str.split( "\n" ); for( i = 0; i < str.length; i++ ) { lines += Math.ceil(str.length / chars_per_line); } return lines;}