groue / GRMustache.swift

Flexible Mustache templates for Swift
http://mustache.github.com/
MIT License
594 stars 155 forks source link

Just not working #92

Closed jimijon closed 1 year ago

jimijon commented 1 year ago

So, I thought it might have been my ParseObject, so I tried a simple dict. If finds the {{vars}} but replaces them with nothing.

Xcode 14.3, SPM install

   do {
            let headerTemplate = try Template(named: templateFileName, bundle: Bundle.main, templateExtension: "html")
            //on Master 2.0 this returns a GRMustacheTemplate, here we get back HTML
            let dict = ["title": "INV0018", "no": "18", "year": "2023", "month": "5" ]
            html = try! headerTemplate.render(dict)
        }
        catch  {
            throw A4PrintPagerRendererError.TemplateNotFound
        }

What can I do?

fumito-ito commented 1 year ago

hi @jimijon. thanks for your feedback. Could you please upload the minimal HTML that reproduces this issue?

jimijon commented 1 year ago

"<!DOCTYPE html>\n\n\n\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n <!--[if !mso]>\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n \n \n <link rel=\"stylesheet\" href=\"https://use.typekit.net/wyi1srj.css\">\n \n <style type=\"text/css\">\n @media print {\n div {\n page-break-inside: avoid;\n }\n tr {\n page-break-inside: avoid;\n page-break-after: auto\n }\n }\n\n {\n margin: 0;\n padding: 0;\n }\n\n html {\n -webkit-print-color-adjust: exact;\n }\n\n body {\n color: #7E7666;\n font-family: \"ff-tisa-web-pro\", serif;\n font-weight: 400;\n font-style: normal;\n font-size: 16px;\n line-height: 1.25;\n }\n\n img {\n border: 0 none;\n height: auto;\n line-height: 100%;\n outline: none;\n text-decoration: none;\n display: block;\n }\n\n a {\n color: #6A73EA;\n }\n\n a img {\n border: 0 none;\n }\n\n strong {\n font-weight: 700;\n }\n\n table {\n display: table;\n width: 100%;\n }\n\n table,\n td {\n border-collapse: collapse;\n border-spacing: 0;\n padding: 0;\n }\n\n .flex-center {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .container {\n padding: 48px 0;\n width: 1024px;\n }\n\n .grid-2 {\n display: grid;\n grid-template-columns: 1fr 1fr;\n }\n\n .grid-3 {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n }\n\n .grid-4 {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr;\n }\n\n .grid-totals {\n display: grid;\n grid-template-columns: 3fr 2fr;\n }\n\n .line {\n background: #EFEBE7;\n height: 2px;\n width: 928px;\n z-index: -1;\n }\n / HEADER /\n\n .header-div {\n height: 40px;\n line-height: 40px;\n margin-bottom: 48px;\n padding-left: 48px;\n padding-right: 48px;\n }\n\n .header-div .line {\n margin-top: 22px;\n position: absolute;\n }\n\n .header-labels {\n color: #CAC7C3;\n font-size: 20px;\n line-height: 40px;\n }\n\n .header-labels span {\n background-color: white;\n }\n\n .header-title {\n background-color: white;\n color: #7E7666;\n font-size: 36px;\n font-style: italic;\n letter-spacing: 7px;\n text-align: center;\n text-transform: uppercase;\n }\n\n .content-div {\n padding-left: 48px;\n padding-right: 48px;\n }\n / PAYMENT INFO /\n\n .payment-info {\n border-bottom: 2px solid #EFEBE7;\n border-top: 2px solid #EFEBE7;\n height: 100px;\n margin-bottom: 80px;\n }\n\n .payment-info>div>div,\n .payment-info div {\n display: flex;\n align-items: center;\n }\n\n .payment-info .amount {\n background-color: white;\n border: 2px solid #EFEBE7;\n border-radius: 50%;\n height: 120px;\n margin: -12px 0;\n width: 120px;\n }\n\n .payment-info .total {\n color: #F16638;\n font-size: 22px;\n font-weight: 700;\n }\n / PRODUCTS /\n\n .products-div .line {\n margin-top: 24px;\n position: absolute;\n }\n\n .products-header {\n height: 40px;\n line-height: 40px;\n }\n\n .products-title {\n background-color: white;\n color: #CAC7C3;\n font-size: 26px;\n font-style: italic;\n }\n\n .products-labels,\n .products-items {\n border-bottom: 2px solid #EFEBE7;\n font-weight: 700;\n }\n\n .products-labels {\n color: #E69E17;\n height: 64px;\n line-height: 64px;\n }\n\n .products-items {\n color: #6B6353;\n padding: 24px 0;\n }\n\n .products-labels .total,\n .products-items .total {\n color: #F16638;\n }\n / TOTALS /\n\n .grid-totals .notes span {\n border: 2px solid #EFEBE7;\n display: block;\n margin: 24px 24px 0 0;\n padding: 24px;\n }\n\n .products-labels,\n .products-items {\n border-bottom: 2px solid #EFEBE7;\n font-weight: 700;\n }\n\n .totals-div .grid-2 {\n padding: 24px 0;\n }\n\n .totals-div .grid-2:not(:last-child) {\n border-bottom: 2px solid #EFEBE7;\n }\n\n .totals-div .grid-2 .center {\n font-weight: 700;\n }\n\n .totals-div .totals-subs .center,\n .totals-div .totals-tot .center {\n color: #E69E17;\n }\n\n .totals-div .grid-2 .right {\n color: #F16638;\n font-weight: 700;\n }\n / CONTACTS /\n\n .contact-div {\n border-bottom: 2px solid #EFEBE7;\n padding-bottom: 64px;\n }\n\n .contact-div .line {\n margin-top: 24px;\n position: absolute;\n }\n\n .contact-header {\n height: 40px;\n line-height: 40px;\n margin-bottom: 24px;\n }\n\n .contact-title {\n background-color: white;\n color: #CAC7C3;\n font-size: 26px;\n font-style: italic;\n }\n\n .contact-info p {\n padding-bottom: 2px;\n }\n\n .contact-info p.strong {\n color: #E69E17;\n padding-bottom: 8px;\n }\n / ALIGNMENT /\n\n .left {\n justify-content: left !important;\n text-align: left;\n }\n\n .center {\n justify-content: center;\n text-align: center;\n }\n\n .right {\n justify-content: right !important;\n text-align: right;\n }\n / PADDING */\n\n .pl-16 {\n padding-left: 16px\n }\n\n .pr-16 {\n padding-right: 16px\n }\n\n .pl-32 {\n padding-left: 32px\n }\n\n .pr-32 {\n padding-right: 32px\n }\n \n\n\n\n <div id=\"header\" style=\"display: none;\">

\n <div id=\"content\" class=\"container\">\n\n <div class=\"header-div\">\n <span class=\"line\">\n <div class=\"header-labels grid-3\">\n
\n <span class=\"pr-16\">{{formattedDate}}\n
\n <div class=\"header-title center\">\n Invoice\n
\n <div class=\"right\">\n <span class=\"pl-16\">{{orderString}}\n \n \n \n\n <div class=\"content-div\">\n\n <div class=\"payment-info grid-3\">\n <div class=\"left pl-32\">\n <span class=\"info\">Invoice sent to you by {{lang.SentFrom}} for the amount of:\n \n <div class=\"center\">\n <div class=\"amount center\">\n <span class=\"total\">{{totalPrice}}\n \n \n <div class=\"right pr-32\">\n <span class=\"due\">Due {{paymentDueDate}}\n \n \n\n <div class=\"products-div\">\n <span class=\"line\">\n\n <div class=\"products-header grid-3\">\n
\n <div class=\"products-title center\">Products\n
\n \n\n <div class=\"products-labels grid-4\">\n <div class=\"left pl-32\">\n {{lang.Description}}\n \n <div class=\"center\">\n {{lang.Price}}\n \n <div class=\"center\">\n {{lang.Unit}}\n \n <div class=\"right pr-32\">\n <span class=\"total\">{{lang.Total}}\n \n \n\n {{#lineItems}}\n <div class=\"products-items grid-4\">\n <div class=\"left pl-32\">\n {{notes}}\n \n <div class=\"center\">\n {{unitPrice}}\n \n <div class=\"center\">\n {{quantityString}}\n \n <div class=\"right pr-32\">\n <span class=\"total\">{{totalPrice}}\n \n \n {{/lineItems}}\n\n \n\n <div class=\"grid-totals\">\n\n <div class=\"notes\">\n {{notes}}\n \n\n <div class=\"totals-div\">\n\n <div class=\"totals-subs grid-2\">\n <div class=\"center\">\n {{lang.SubTotal}}\n \n <div class=\"right pr-32\">\n <span class=\"total\">{{subTotalString}}\n \n \n\n {{#netItems}}\n <div class=\"totals-tax grid-2\">\n <div class=\"center\">\n {{title}}\n \n <div class=\"right pr-32\">\n <span class=\"total\">{{value}}\n \n \n {{/netItems}}\n\n <div class=\"totals-tot grid-2\">\n <div class=\"center\">\n {{lang.Total}}\n \n <div class=\"right pr-32\">\n <span class=\"total\">{{totalPrice}}\n \n \n\n \n\n\n\n \n\n <div class=\"contact-div\">\n <span class=\"line\">\n\n <div class=\"contact-header grid-3\">\n
\n <div class=\"contact-title center\">Contact\n
\n \n\n <div class=\"contact-info grid-3\">\n
\n <p class=\"strong\">{{lang.SentFrom}}

\n

{{companyName}}

\n

{{{companyAddress}}}

\n
\n
\n <p class=\"strong\">{{lang.SentTo}}

\n

{{clientName}}

\n

{{{clientAddress}}}

\n
\n
\n \n\n \n\n \n <div id=\"footer\" style=\"display: none;\">\n\n\n\n"

fumito-ito commented 1 year ago

@jimijon https://github.com/groue/GRMustache.swift/issues/92#issuecomment-1585664530 is not valid html. Can you upload the complete html or paste the code (use code block style!) ?

jimijon commented 1 year ago

"<!DOCTYPE html>\n<html>\n\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n <!--[if !mso]><!-- -->\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <!--<![endif]-->\n <!-- Typescript -->\n <link rel=\"stylesheet\" href=\"https://use.typekit.net/wyi1srj.css\">\n <!-- BASICS -->\n <style type=\"text/css\">\n @media print {\n div {\n page-break-inside: avoid;\n }\n tr {\n page-break-inside: avoid;\n page-break-after: auto\n }\n }\n\n * {\n margin: 0;\n padding: 0;\n }\n\n html {\n -webkit-print-color-adjust: exact;\n }\n\n body {\n color: #7E7666;\n font-family: \"ff-tisa-web-pro\", serif;\n font-weight: 400;\n font-style: normal;\n font-size: 16px;\n line-height: 1.25;\n }\n\n img {\n border: 0 none;\n height: auto;\n line-height: 100%;\n outline: none;\n text-decoration: none;\n display: block;\n }\n\n a {\n color: #6A73EA;\n }\n\n a img {\n border: 0 none;\n }\n\n strong {\n font-weight: 700;\n }\n\n table {\n display: table;\n width: 100%;\n }\n\n table,\n td {\n border-collapse: collapse;\n border-spacing: 0;\n padding: 0;\n }\n\n .flex-center {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .container {\n padding: 48px 0;\n width: 1024px;\n }\n\n .grid-2 {\n display: grid;\n grid-template-columns: 1fr 1fr;\n }\n\n .grid-3 {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n }\n\n .grid-4 {\n display: grid;\n grid-template-columns: 2fr 1fr 1fr 1fr;\n }\n\n .grid-totals {\n display: grid;\n grid-template-columns: 3fr 2fr;\n }\n\n .line {\n background: #EFEBE7;\n height: 2px;\n width: 928px;\n z-index: -1;\n }\n /* HEADER */\n\n .header-div {\n height: 40px;\n line-height: 40px;\n margin-bottom: 48px;\n padding-left: 48px;\n padding-right: 48px;\n }\n\n .header-div .line {\n margin-top: 22px;\n position: absolute;\n }\n\n .header-labels {\n color: #CAC7C3;\n font-size: 20px;\n line-height: 40px;\n }\n\n .header-labels span {\n background-color: white;\n }\n\n .header-title {\n background-color: white;\n color: #7E7666;\n font-size: 36px;\n font-style: italic;\n letter-spacing: 7px;\n text-align: center;\n text-transform: uppercase;\n }\n\n .content-div {\n padding-left: 48px;\n padding-right: 48px;\n }\n /* PAYMENT INFO */\n\n .payment-info {\n border-bottom: 2px solid #EFEBE7;\n border-top: 2px solid #EFEBE7;\n height: 100px;\n margin-bottom: 80px;\n }\n\n .payment-info>div>div,\n .payment-info div {\n display: flex;\n align-items: center;\n }\n\n .payment-info .amount {\n background-color: white;\n border: 2px solid #EFEBE7;\n border-radius: 50%;\n height: 120px;\n margin: -12px 0;\n width: 120px;\n }\n\n .payment-info .total {\n color: #F16638;\n font-size: 22px;\n font-weight: 700;\n }\n /* PRODUCTS */\n\n .products-div .line {\n margin-top: 24px;\n position: absolute;\n }\n\n .products-header {\n height: 40px;\n line-height: 40px;\n }\n\n .products-title {\n background-color: white;\n color: #CAC7C3;\n font-size: 26px;\n font-style: italic;\n }\n\n .products-labels,\n .products-items {\n border-bottom: 2px solid #EFEBE7;\n font-weight: 700;\n }\n\n .products-labels {\n color: #E69E17;\n height: 64px;\n line-height: 64px;\n }\n\n .products-items {\n color: #6B6353;\n padding: 24px 0;\n }\n\n .products-labels .total,\n .products-items .total {\n color: #F16638;\n }\n /* TOTALS */\n\n .grid-totals .notes span {\n border: 2px solid #EFEBE7;\n display: block;\n margin: 24px 24px 0 0;\n padding: 24px;\n }\n\n .products-labels,\n .products-items {\n border-bottom: 2px solid #EFEBE7;\n font-weight: 700;\n }\n\n .totals-div .grid-2 {\n padding: 24px 0;\n }\n\n .totals-div .grid-2:not(:last-child) {\n border-bottom: 2px solid #EFEBE7;\n }\n\n .totals-div .grid-2 .center {\n font-weight: 700;\n }\n\n .totals-div .totals-subs .center,\n .totals-div .totals-tot .center {\n color: #E69E17;\n }\n\n .totals-div .grid-2 .right {\n color: #F16638;\n font-weight: 700;\n }\n /* CONTACTS */\n\n .contact-div {\n border-bottom: 2px solid #EFEBE7;\n padding-bottom: 64px;\n }\n\n .contact-div .line {\n margin-top: 24px;\n position: absolute;\n }\n\n .contact-header {\n height: 40px;\n line-height: 40px;\n margin-bottom: 24px;\n }\n\n .contact-title {\n background-color: white;\n color: #CAC7C3;\n font-size: 26px;\n font-style: italic;\n }\n\n .contact-info p {\n padding-bottom: 2px;\n }\n\n .contact-info p.strong {\n color: #E69E17;\n padding-bottom: 8px;\n }\n /* ALIGNMENT */\n\n .left {\n justify-content: left !important;\n text-align: left;\n }\n\n .center {\n justify-content: center;\n text-align: center;\n }\n\n .right {\n justify-content: right !important;\n text-align: right;\n }\n /* PADDING */\n\n .pl-16 {\n padding-left: 16px\n }\n\n .pr-16 {\n padding-right: 16px\n }\n\n .pl-32 {\n padding-left: 32px\n }\n\n .pr-32 {\n padding-right: 32px\n }\n </style>\n</head>\n\n<body>\n <div id=\"header\" style=\"display: none;\"></div>\n <div id=\"content\" class=\"container\">\n\n <div class=\"header-div\">\n <span class=\"line\"></span>\n <div class=\"header-labels grid-3\">\n <div>\n <span class=\"pr-16\">{{formattedDate}}</span>\n </div>\n <div class=\"header-title center\">\n <span>Invoice</span>\n </div>\n <div class=\"right\">\n <span class=\"pl-16\">{{orderString}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"content-div\">\n\n <div class=\"payment-info grid-3\">\n <div class=\"left pl-32\">\n <span class=\"info\">Invoice sent to you by <strong>{{lang.SentFrom}}</strong> for the amount of:</span>\n </div>\n <div class=\"center\">\n <div class=\"amount center\">\n <span class=\"total\">{{totalPrice}}</span>\n </div>\n </div>\n <div class=\"right pr-32\">\n <span class=\"due\">Due <strong>{{paymentDueDate}}</strong></span>\n </div>\n </div>\n\n <div class=\"products-div\">\n <span class=\"line\"></span>\n\n <div class=\"products-header grid-3\">\n <div></div>\n <div class=\"products-title center\">Products</div>\n <div></div>\n </div>\n\n <div class=\"products-labels grid-4\">\n <div class=\"left pl-32\">\n <span>{{lang.Description}}</span>\n </div>\n <div class=\"center\">\n <span>{{lang.Price}}</span>\n </div>\n <div class=\"center\">\n <span>{{lang.Unit}}</span>\n </div>\n <div class=\"right pr-32\">\n <span class=\"total\">{{lang.Total}}</span>\n </div>\n </div>\n\n {{#lineItems}}\n <div class=\"products-items grid-4\">\n <div class=\"left pl-32\">\n <span>{{notes}}</span>\n </div>\n <div class=\"center\">\n <span>{{unitPrice}}</span>\n </div>\n <div class=\"center\">\n <span>{{quantityString}}</span>\n </div>\n <div class=\"right pr-32\">\n <span class=\"total\">{{totalPrice}}</span>\n </div>\n </div>\n {{/lineItems}}\n\n </div>\n\n <div class=\"grid-totals\">\n\n <div class=\"notes\">\n <span>{{notes}}</span>\n </div>\n\n <div class=\"totals-div\">\n\n <div class=\"totals-subs grid-2\">\n <div class=\"center\">\n <span>{{lang.SubTotal}}</span>\n </div>\n <div class=\"right pr-32\">\n <span class=\"total\">{{subTotalString}}</span>\n </div>\n </div>\n\n {{#netItems}}\n <div class=\"totals-tax grid-2\">\n <div class=\"center\">\n <span>{{title}}</span>\n </div>\n <div class=\"right pr-32\">\n <span class=\"total\">{{value}}</span>\n </div>\n </div>\n {{/netItems}}\n\n <div class=\"totals-tot grid-2\">\n <div class=\"center\">\n <span>{{lang.Total}}</span>\n </div>\n <div class=\"right pr-32\">\n <span class=\"total\">{{totalPrice}}</span>\n </div>\n </div>\n\n </div>\n\n\n\n </div>\n\n <div class=\"contact-div\">\n <span class=\"line\"></span>\n\n <div class=\"contact-header grid-3\">\n <div></div>\n <div class=\"contact-title center\">Contact</div>\n <div></div>\n </div>\n\n <div class=\"contact-info grid-3\">\n <div>\n <p class=\"strong\">{{lang.SentFrom}}</p>\n <p>{{companyName}}</p>\n <p>{{{companyAddress}}}</p>\n </div>\n <div>\n <p class=\"strong\">{{lang.SentTo}}</p>\n <p>{{clientName}}</p>\n <p>{{{clientAddress}}}</p>\n </div>\n <div></div>\n </div>\n\n </div>\n\n </div>\n <div id=\"footer\" style=\"display: none;\"></div>\n</body>\n\n</html>\n"

This is the string. And it used to work on the very old mustache pre package.

fumito-ito commented 1 year ago

@jimijon https://github.com/groue/GRMustache.swift/issues/92#issuecomment-1585667327 has some problems to render with the code.

let dict = ["title": "INV0018", "no": "18", "year": "2023", "month": "5" ] let html = try! headerTemplate.render(dict)

jimijon commented 1 year ago

ok, that was my fake test,, so Title needs netItems?

jimijon commented 1 year ago

ok, I see it is nested,,, here is the real object that I used

jimijon commented 1 year ago

po object <PFInvoice GrClI6CCLN title: 'Testing Line Breaks' no: 2320230530 year: 2023 month: 5 total: (null) state: Draft lines: 1 >

(NSObject) $R2 = 0x00006000036fa920 { basePFDocumentInstance@0 = { basePFObject@0 = { NSObject = { isa = PFInvoice } lock = 0x0000600001ff87b0 { isa = NSObject } _pfinternal_state = 0x000060000088e800 { baseNSObject@0 = { isa = PFObjectState } _parseClassName = 0x0000000107130348 "Invoice" _objectId = 0x0000600001df3f60 "GrClI6CCLN" _createdAt = 0xa31f100f33b4f546 2023-05-31 03:31:20 UTC _updatedAt = 0xa31f1008d89ef12e 2023-05-31 03:39:10 UTC _serverData = 0x0000600001a2f420 26 key/value pairs _complete = true _deleted = false } _estimatedData = 0x0000600001fde220 { baseNSObject@0 = { isa = PFObjectEstimatedData } _dataDictionary = 0x0000600001a2f2e0 27 key/value pairs } _availableKeys = 0x0000600001a2eec0 30 elements _deletingEventuallyCount = 0 localId = 0x0000000000000000 _eventuallyTaskQueue = 0x0000600001a2f0c0 { baseNSObject@0 = { isa = PFTaskQueue } _mutex = 0x0000600001fde130 { isa = NSObject } _tail = 0x0000000000000000 } saveDelegate = 0x0000000000000000 dirty = NO operationSetQueue = 0x00006000012e4870 1 element taskQueue = 0x0000600001a2f0a0 { baseNSObject@0 = { isa = PFTaskQueue } _mutex = 0x0000600001fde120 { isa = NSObject } _tail = 0x0000000000000000 } } } isSampleInvoice = false }

fumito-ito commented 1 year ago

see tag references.