Update attributes on existing iframe elements in nvarchar column via SQL - sql

I've implemented code inside a ckeditor that replaces the src attribute of iframe elements with data-src and adds the data-cookieconsent attribute. In addition, a placeholder div is added after the iframe element. Regex is used to match the iframe elements in the string.
var value = CKEDITOR.instances.editor1.getData();
const regex = new RegExp('(?:<iframe[^>]*)(?:(?:\/>)|(?:>.*?<\/iframe>))');
const matches = value.match(regex);
if (typeof matches !== "undefined" && matches != null) {
matches.forEach(element => {
if (!element.includes("data-cookieconsent")) {
value = value.replace(element, element.replace("src=", "data-add-placeholder data-cookieconsent=\"marketing\" data-src="))
value = value.replace("</iframe>", "</iframe><div class=\"row justify - content - center\">" +
"<div class=\"cookieconsent-optout-marketing blocked-media-placeholder\">" +
"<div class=\"col-xs-6 col-xs-offset-3\">" +
"<h3>For at se denne video skal vi bruge dit samtykke til at anvende cookies.Venligst tryk på dette link og vfremvist denne video.</h3>" +
"</div></div></div>")
}
});
}
However, I now need to replace the currently existing iframe elements and add the placeholder div in the database using sql. I'm aware that I can use update with the replace function to update parts of a text column, but this seems to require Regex to work, which as I understand, is quite limited in T-SQL.
What would be the best approach to this problem? How can I ensure only the iframe elements in the column are altered?

Related

Printing to pdf from Google Apps Script HtmlOutput

For years, I have been using Google Cloud Print to print labels in our laboratories on campus (to standardize) using a Google Apps Script custom HtmlService form.
Now that GCP is becoming depreciated, I am in on a search for a solution. I have found a few options but am struggling to get the file to convert to a pdf as would be needed with these other vendors.
Currently, when you submit a text/html blob to the GCP servers in GAS, the backend converts the blob to application/pdf (as evidenced by looking at the job details in the GCP panel on Chrome under 'content type').
That said, because these other cloud print services require pdf printing, I have tried for some time now to have GAS change the file to pdf format before sending to GCP and I always get a strange result. Below, I'll show some of the strategies that I have used and include pictures of one of our simple labels generated with the different functions.
The following is the base code for the ticket and payload that has worked for years with GCP
//BUILD PRINT JOB FOR NARROW TAPES
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR",
vendor_id: "Color"
},
duplex: {
type: "NO_DUPLEX"
},
copies: {copies: parseFloat(quantity)},
media_size: {
width_microns: 27940,
height_microns:40960
},
page_orientation: {
type: "LANDSCAPE"
},
margins: {
top_microns:0,
bottom_microns:0,
left_microns:0,
right_microns:0
},
page_range: {
interval:
[{start:1,
end:1}]
},
}
};
var payload = {
"printerid" : QL710,
"title" : "Blank Template Label",
"content" : HtmlService.createHtmlOutput(html).getBlob(),
"contentType": 'text/html',
"ticket" : JSON.stringify(ticket)
};
This generates the expected following printout:
When trying to convert to pdf using the following code:
The following is the code used to transform to pdf:
var blob = HtmlService.createTemplate(html).evaluate().getContent();
var newBlob = Utilities.newBlob(html, "text/html", "text.html");
var pdf = newBlob.getAs("application/pdf").setName('tempfile');
var file = DriveApp.getFolderById("FOLDER ID").createFile(pdf);
var payload = {
"printerid" : QL710,
"title" : "Blank Template Label",
"content" : pdf,//HtmlService.createHtmlOutput(html).getBlob(),
"contentType": 'text/html',
"ticket" : JSON.stringify(ticket)
};
an unexpected result occurs:
This comes out the same way for direct coding in the 'content' field with and without .getBlob():
"content" : HtmlService.createHtmlOutput(html).getAs('application/pdf'),
note the createFile line in the code above used to test the pdf. This file is created as expected, of course with the wrong dimensions for label printing (not sure how to convert to pdf with the appropriate margins and page size?): see below
I have now tried to adopt Yuri's ideas; however, the conversion from html to document loses formatting.
var blob = HtmlService.createHtmlOutput(html).getBlob();
var docID = Drive.Files.insert({title: 'temp-label'}, blob, {convert: true}).id
var file = DocumentApp.openById(docID);
file.getBody().setMarginBottom(0).setMarginLeft(0).setMarginRight(0).setMarginTop(0).setPageHeight(79.2).setPageWidth(172.8);
This produces a document looks like this (picture also showing expected output in my hand).
Does anyone have insights into:
How to format the converted pdf to contain appropriate height, width
and margins.
How to convert to pdf in a way that would print correctly.
Here is a minimal code to get a better sense of context https://script.google.com/d/1yP3Jyr_r_FIlt6_aGj_zIf7HnVGEOPBKI0MpjEGHRFAWztGzcWKCJrD0/edit?usp=sharing
I've made the template (80 x 40 mm -- sorry, I don't know your size):
https://docs.google.com/document/d/1vA93FxGXcWLIEZBuQwec0n23cWGddyLoey-h0WR9weY/edit?usp=sharing
And there is the script:
function myFunction() {
// input data
var matName = '<b>testing this to <u>see</u></b> if it <i>actually</i> works <i>e.coli</i>'
var disposeWeek = 'end of semester'
var prepper = 'John Ruppert';
var className = 'Cell and <b>Molecular</b> Biology <u>Fall 2020</u> a few exercises a few exercises a few exercises a few exercises';
var hazards = 'Lots of hazards';
// make a temporary Doc from the template
var copyFile = DriveApp.getFileById('1vA93FxGXcWLIEZBuQwec0n23cWGddyLoey-h0WR9weY').makeCopy();
var doc = DocumentApp.openById(copyFile.getId());
var body = doc.getBody();
// replace placeholders with data
body.replaceText('{matName}', matName);
body.replaceText('{disposeWeek}', disposeWeek);
body.replaceText('{prepper}', prepper);
body.replaceText('{className}', className);
body.replaceText('{hazards}', hazards);
// make Italics, Bold and Underline
handle_tags(['<i>', '</i>'], body);
handle_tags(['<b>', '</b>'], body);
handle_tags(['<u>', '</u>'], body);
// save the temporary Doc
doc.saveAndClose();
// make a PDF
var docblob = doc.getBlob().setName('Label.pdf');
DriveApp.createFile(docblob);
// delete the temporary Doc
copyFile.setTrashed(true);
}
// this function applies formatting to text inside the tags
function handle_tags(tags, body) {
var start_tag = tags[0].toLowerCase();
var end_tag = tags[1].toLowerCase();
var found = body.findText(start_tag);
while (found) {
var elem = found.getElement();
var start = found.getEndOffsetInclusive();
var end = body.findText(end_tag, found).getStartOffset()-1;
switch (start_tag) {
case '<b>': elem.setBold(start, end, true); break;
case '<i>': elem.setItalic(start, end, true); break;
case '<u>': elem.setUnderline(start, end, true); break;
}
found = body.findText(start_tag, found);
}
body.replaceText(start_tag, ''); // remove tags
body.replaceText(end_tag, '');
}
The script just changes the {placeholders} with the data and saves the result as a PDF file (Label.pdf). The PDF looks like this:
There is one thing, I'm not sure if it's possible -- to change a size of the texts dynamically to fit them into the cells, like it's done in your 'autosize.html'. Roughly, you can take a length of the text in the cell and, in case it is bigger than some number, to make the font size a bit smaller. Probably you can use the jquery texfill function from the 'autosize.html' to get an optimal size and apply the size in the document.
I'm not sure if I got you right. Do you need make PDF and save it on Google Drive? You can do in Google Docs.
As example:
Make a new document with your table and text. Something like this
Add this script into your doc:
function myFunction() {
var copyFile = DriveApp.getFileById(ID).makeCopy();
var newFile = DriveApp.createFile(copyFile.getAs('application/pdf'));
newFile.setName('label');
copyFile.setTrashed(true);
}
Every time you run this script it makes the file 'label.pdf' on your Google Drive.
The size of this pdf will be the same as the page size of your Doc. You can make any size of page with add-on: Page Sizer https://webapps.stackexchange.com/questions/129617/how-to-change-the-size-of-paper-in-google-docs-to-custom-size
If you need to change the text in your label before generate pdf or/and you need change the name of generated file, you can do it via script as well.
Here is a variant of the script that changes a font size in one of the cells if the label doesn't fit into one page.
function main() {
// input texts
var text = {};
text.matName = '<b>testing this to <u>see</u></b> if it <i>actually</i> works <i>e.coli</i>';
text.disposeWeek = 'end of semester';
text.prepper = 'John Ruppert';
text.className = 'Cell and <b>Molecular</b> Biology <u>Fall 2020</u> a few exercises a few exercises a few exercises a few exercises';
text.hazards = 'Lots of hazards';
// initial max font size for the 'matName'
var size = 10;
var doc_blob = set_text(text, size);
// if we got more than 1 page, reduce the font size and repeat
while ((size > 4) && (getNumPages(doc_blob) > 1)) {
size = size-0.5;
doc_blob = set_text(text, size);
}
// save pdf
DriveApp.createFile(doc_blob);
}
// this function takes texts and a size and put the texts into fields
function set_text(text, size) {
// make a copy
var copyFile = DriveApp.getFileById('1vA93FxGXcWLIEZBuQwec0n23cWGddyLoey-h0WR9weY').makeCopy();
var doc = DocumentApp.openById(copyFile.getId());
var body = doc.getBody();
// replace placeholders with data
body.replaceText('{matName}', text.matName);
body.replaceText('{disposeWeek}', text.disposeWeek);
body.replaceText('{prepper}', text.prepper);
body.replaceText('{className}', text.className);
body.replaceText('{hazards}', text.hazards);
// set font size for 'matName'
body.findText(text.matName).getElement().asText().setFontSize(size);
// make Italics, Bold and Underline
handle_tags(['<i>', '</i>'], body);
handle_tags(['<b>', '</b>'], body);
handle_tags(['<u>', '</u>'], body);
// save the doc
doc.saveAndClose();
// delete the copy
copyFile.setTrashed(true);
// return blob
return docblob = doc.getBlob().setName('Label.pdf');
}
// this function formats the text beween html tags
function handle_tags(tags, body) {
var start_tag = tags[0].toLowerCase();
var end_tag = tags[1].toLowerCase();
var found = body.findText(start_tag);
while (found) {
var elem = found.getElement();
var start = found.getEndOffsetInclusive();
var end = body.findText(end_tag, found).getStartOffset()-1;
switch (start_tag) {
case '<b>': elem.setBold(start, end, true); break;
case '<i>': elem.setItalic(start, end, true); break;
case '<u>': elem.setUnderline(start, end, true); break;
}
found = body.findText(start_tag, found);
}
body.replaceText(start_tag, '');
body.replaceText(end_tag, '');
}
// this funcion takes saved doc and returns the number of its pages
function getNumPages(doc) {
var blob = doc.getAs('application/pdf');
var data = blob.getDataAsString();
var pages = parseInt(data.match(/ \/N (\d+) /)[1], 10);
Logger.log("pages = " + pages);
return pages;
}
It looks rather awful and hopeless. It turned out that Google Docs has no page number counter. You need to convert your document into a PDF and to count pages of the PDF file. Gross!
Next problem, even if you managed somehow to count the pages, you have no clue which of the cells was overflowed. This script takes just one cell, changes its font size, counts pages, changes the font size again, etc. But it doesn't granted a success, because there can be another cell with long text inside. You can reduce font size of all the texts, but it doesn't look like a great idea as well.

How to add data-attributes to a Bootstrap Treeview?

I am using bootstrap-treeview 1.2.0 (from Jon Miles).
My goal is to add custom data-attributes to my list items' markup, e.g.
<li class="list-group-item node-tree" data-id="100" data-type="user" ...>
I tried to follow these instructions see here and here is part of my JSON:
[{"text":"Root","icon":null,"data-id":1,"data-type":"branch","nodes":[{"text":"Steve","icon":null,"data-id":17, "data-type":"user","nodes":...
To me the JSON looks good. But none of my data-attributes gets rendered in the markup.
Any ideas?
Sorry, I see it's too late. I searched about this and couldn't find anything. But you can
change bootstrap-treeview.js file a bit. There is some attribute set code in buildTree function. It's looking like this:
Tree.prototype.buildTree = function (nodes, level) {
if (!nodes) return;
level += 1;
var _this = this;
$.each(nodes, function addNodes(id, node) {
var treeItem = $(_this.template.item)
.addClass('node-' + _this.elementId)
.addClass(node.state.checked ? 'node-checked' : '')
.addClass(node.state.disabled ? 'node-disabled': '')
.addClass(node.state.selected ? 'node-selected' : '')
.addClass(node.searchResult ? 'search-result' : '')
.attr('data-nodeid', node.nodeId)
.attr('style', _this.buildStyleOverride(node));
......................SOME CODES ........SOME CODES..........................}
You can add :
.attr('data-type', node.dataType)
.attr('data-id', node.dataId)
And then change the object(json) like this:
[{"text":"Root","icon":null,"dataId":1,"dataType":"branch","nodes":
[{"text":"Steve","icon":null,"dataId":17, "dataType":"user","nodes":...
The link provided simply instructs how to expand the node object with additional properties. There is no correlation between a node's properties and the attributes assigned in HTML.
You might want to do something like this:
var allNodes = $('#tree').treeview('getNodes);
$(allNodes).each(function(index, element) {
$(this.$el[0]).attr('data-attribute-name', this.data-attribute-name);
});

httpagility pack scraping between broken tag

i need to scrape a p tag which has h3 tag after it but does not have a closing p tag. It looks like this :
<script ad>asdasdasd</script>
<p>Translation companies are
-----------------------
-----------------------
<h3 class="this_class">mind blown site</h3>
There is no </p> tag so i cannot parse it completely. Now i have two questions :
1) can this be parsed using httpagility xpath ?
2) i have a function to find text between two strings (getbetween). But i have a doubt - If i use "asdasdasd" and " is it always 100% that vb.net will use the script tag which is just above h3 because there are 2-3 same lines - "asdasdasd"
3) Any other method you guys are aware of ?
(had to write in code so html does not mess up)
Regards,
It might be a good idea to post some more "real" html to really help you, at least the tags between the h3 and the p.
Anyway, this should get you the p-Tag from the h3-Tag.
HtmlDocument doc = new HtmlDocument();
doc.Load(... //Load the Html...
//Either of these lines will do
HtmlNode pNode = doc.DocumentNode.SelectSingleNode("//h3[#class='this_class']/preceding-sibling::p");
//HtmlNode pNode = doc.DocumentNode.SelectSingleNode("//h3[contains(text(),'mind blown site')]/preceding-sibling::p");
string pInnerHtml = pNode.NextSibling.InnerHtml; //Has the text "Translation companies are...."
So in general, to get all the nodes from the opening p tag to the start of a tag you don't want, you could do this:
var p = doc.DocumentNode.SelectSingleNode("//p");
var h3 = p.SelectSingleNode("following-sibling::h3[#class='this_class']");
var following = new List<string>();
for (var current = p.NextSibling; current != h3; current = current.NextSibling)
{
following.Add(current.InnerText);
}
var innerText = String.Concat(following);

Content templates rendering in TYPO3

I've got a strange problem connected with content rendering.
I use following code to grab the content:
lib.otherContent = CONTENT
lib.otherContent {
table = tt_content
select {
pidInList = this
orderBy = sorting
where = colPos=0
languageField = sys_language_uid
}
renderObj = COA
renderObj {
10 = TEXT
10.field = header
10.wrap = <h2>|</h2>
20 = TEXT
20.field = bodytext
20.wrap = <div class="article">|</div>
}
}
and everything works fine, except that I'd like to use also predefined column-content templates other than simple text (Text with image, Images only, Bullet list etc.).
The question is: with what I have to replace renderObj = COA and the rest between the brackets to let the TYPO3 display it properly?
Thanks,
I.
The available cObjects are more or less listed in TSRef, chapter 8.
TypoScript for rendering Text w/image can be found in typo3/sysext/css_styled_content/static/v4.3/setup.txt at line 724, and in the neighborhood you'll find e.g. bullets (below) and image (above), which is referenced in textpic line 731. Variants of this is what you'll write in your renderObj.
You will find more details in the file typo3/sysext/cms/tslib/class.tslib_content.php, where e.g. text w/image is found at or around line 897 and is called IMGTEXT (do a case-sensitive search). See also around line 403 in typo3/sysext/css_styled_content/pi1/class.cssstyledcontent_pi1.php, where the newer css-based rendering takes place.

Manual Page Break in TCPDF

I am using TCPDF to generate the PDF in one of my projects. I simply create a HTML file and give it to the TCPDF to handle the PDF generation. But now I have some HTML where multiple certificates are added one after the other and I want to have a page break in it. Page Break should be decided by HTML i.e. I want to know if there is any identifier in HTML which TCPDF understands and then accordingly adds a page break into the generated PDF.
How could I do this?
I'm using <br pagebreak="true"/>.
Find method writeHTML and code
if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) {
// check for pagebreak
if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) {
// add a page (or trig AcceptPageBreak() for multicolumn mode)
$this->checkPageBreak($this->PageBreakTrigger + 1);
}
if ((($dom[$key]['attribute']['pagebreak'] == 'left') AND (((!$this->rtl) AND (($this->page % 2) == 0)) OR (($this->rtl) AND (($this->page % 2) != 0))))
OR (($dom[$key]['attribute']['pagebreak'] == 'right') AND (((!$this->rtl) AND (($this->page % 2) != 0)) OR (($this->rtl) AND (($this->page % 2) == 0))))) {
// add a page (or trig AcceptPageBreak() for multicolumn mode)
$this->checkPageBreak($this->PageBreakTrigger + 1);
}
}
You might use TCPDF's AddPage() method in combination with explode() and a suitable delimiter:
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8',
false);
// TCPDF initialization code (...)
$delimiter = '<h1>';
$html = file_get_contents('./test.html');
$chunks = explode($delimiter, $html);
$cnt = count($chunks);
for ($i = 0; $i < $cnt; $i++) {
$pdf->writeHTML($delimiter . $chunks[$i], true, 0, true, 0);
if ($i < $cnt - 1) {
$pdf->AddPage();
}
}
// Reset pointer to the last page
$pdf->lastPage();
// Close and output PDF document
$pdf->Output('test.pdf', 'I');
I tried using
<br pagebreak="true" />
or
<tcpdf method="AddPage" />
each of them resulted not in starting new page at the top of the page but adding the full A4-page empty space in between HTML text. So if text ended in the middle of the page and then page break was inserted, the new text was written from the middle of the next page. Which I didn't want.
What worked was this (found it here TCPDF forcing a new page):
$pdf->writeHTML($content, true, 0, true, 0);
$pdf->AddPage();
$pdf->setPage($pdf->getPage());
This now starts with writing text on top of the page.
TCPDF support the 'pagebreak' attribute for HTML tags and CSS properties 'page-break-before' and 'page-break-after'.
For example you can use <br pagebreak="true" />.
Check the official http://www.tcpdf.org website and forums for further information.
With version 5.9.142 from 2011-12-23 we could use the page-break-before, page-break-inside css properties, like this:
<div style="page-break-inside:avoid;">
some non breakable text
</div>
For someone who still has the same problem with page-break TCPDF library
You can use <div style="page-break-before:always"></div> OR <br pagebreak="true"/>
to break page manually in your HTML content.
Use $tcpdf->AddPage() to break page manually in your code.
When you set SetAutoPageBreak(TRUE, 10); that means: when the height of document reach to (bottom - 10) then move the cursor to new page. So if you want to have more space, just reduce the number into 0. It will draw until the end of the document without any margin from bottom.
Remember that TCPDF only accept the double quote (") for attributes of tags. Don't use single quote (') for your tag.
<div style='page-break-before:always' => WRONG
<div style="page-break-before:always" => RIGHT
It takes 8 hours from me because this issue :(
According to http://www.tcpdf.org/examples/example_049.phps you can use something like this
$html .= '<tcpdf method="AddPage" /><h2>Graphic Functions</h2>';
You need to verify that parameter K_TCPDF_CALLS_IN_HTML in TCPDF configuration file is true.
You can also follow this method to accomplish your needs:
$htmlcontent1="CERTIFICATE NUMBER 1 IMAGE HERE";
// output the HTML content
$pdf->writeHTML($htmlcontent1, true, 0, true, 0);
// reset pointer to the last page
$pdf->lastPage();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Print a table
// add a page
$pdf->AddPage();
$htmlcontent1="CERTIFICATE NUMBER 1 IMAGE HERE";
// output the HTML content
$pdf->writeHTML($htmlcontent1, true, 0, true, 0);
// reset pointer to the last page
$pdf->lastPage();
// ---------------------------------------------------------
//Close and output PDF document
$pdf->Output('textcertificate.pdf', 'D');
Hopes it helps someone :)
Thanks
Giving your element the page-break-after, page-break-before or page-break-inside property via CSS will apply the attribute pagebreak or pagebreakafter to the html tag during TCPDF runtime.
// page-break-inside
if (isset($dom[$key]['style']['page-break-inside']) AND ($dom[$key]['style']['page-break-inside'] == 'avoid')) {
$dom[$key]['attribute']['nobr'] = 'true';
}
// page-break-before
if (isset($dom[$key]['style']['page-break-before'])) {
if ($dom[$key]['style']['page-break-before'] == 'always') {
$dom[$key]['attribute']['pagebreak'] = 'true';
} elseif ($dom[$key]['style']['page-break-before'] == 'left') {
$dom[$key]['attribute']['pagebreak'] = 'left';
} elseif ($dom[$key]['style']['page-break-before'] == 'right') {
$dom[$key]['attribute']['pagebreak'] = 'right';
}
}
// page-break-after
if (isset($dom[$key]['style']['page-break-after'])) {
if ($dom[$key]['style']['page-break-after'] == 'always') {
$dom[$key]['attribute']['pagebreakafter'] = 'true';
} elseif ($dom[$key]['style']['page-break-after'] == 'left') {
$dom[$key]['attribute']['pagebreakafter'] = 'left';
} elseif ($dom[$key]['style']['page-break-after'] == 'right') {
$dom[$key]['attribute']['pagebreakafter'] = 'right';
}
}