Hello I have an ASP script that I need to edit. Actually I need to restyle the email that it sends, so I need to edit the HTML from it.
The problem is the html (from the asp file) has on every row
HTML = HTML & ="
in it (plus some other changes). I need to take the HTML code from that ASP, get rid of the beginning html = html part, edit the double "" and convert them to a single " (I need to do that one by one, because the variables also have quotes in them).
Than, I restyle the page with HTML and after that I need to convert it back so I can integrate it in ASP (basically introduce the double '"' again and stuff).
Yeah, I could edit the HTML from the ASP directly, but I don't know how it might look, because I can't run the script (it needs other files from the server, which I don't have access to).
The question:
Is there a better way of doing this?
Some way of previewing what I'm doing in ASP directly. Or maybe a tool that let's me move from ASP HTML to HTML and back faster.
I sure know that what I'm doing right now is quite dumb, so there must be a better way.
You could create a html template file with some placeholders in it, read it in, replace the placeholders and then use it in your email. Saves you having to keep messing about building up the html using variables. This previous answer has some more details about a possible solution (with code examples).
As #steve-holland mentions creating a template is a great way to avoid all the annoying HTML strings in the code and makes changing layouts a breeze.
I've worked on HTML templating scripts myself in the past, usually I build a Scripting.Dictionary that contains the key value pairs I will be replacing inside the template.
Function getHTMLTemplate(url, params)
Dim stream, keys, html, idx
Set stream = Server.CreateObject("ADODB.Stream")
With stream
.Type = adTypeText
.Charset = "utf-8"
Call .Open()
Call .LoadFromFile(url)
html = .ReadText(adReadAll)
Call .Close()
End With
Set stream = Nothing
keys = o_params.Keys
For idx = 0 To UBound(keys, 1)
html = Replace(html, keys(idx), params.Item(keys(idx)))
Next
Set keys = Nothing
Set params = Nothing
getHTMLTemplate = html
End Function
Usage:
Dim params, html
Set params = Server.CreateObject("Scripting.Dictionary")
With params
.Add("[html_title]", "Title Here")
.Add("[html_logo]", "/images/logo.gif")
'... and so on
End With
html = getHTMLTemplate(Server.MapPath("/templates/main.htm"), params)
Call Response.Write(html)
Example main.htm structure:
<!doctype html>
<html>
<head>
<title>[html_title]</title>
<link rel="stylesheet" type="text/css" href="/styles/main.css" />
</head>
<body>
<div class="header">
<img src="[html_logo]" alt="Company Name" />
</div>
</body>
</html>
Why use a ADODB.Stream instead of the Scripting.FileSystemObject?;
You can control the Charset being returned and even convert from one to another if you need to.
If the template is particular large, you can stream the content in using the Read() method with a specific buffer size to improve the performance of the read.
Related
Problem
I have a collection of images with linked captions on a page. I want them each to have identical HTML.
Typically, i copy and paste the HTML over and over for each item. The problem is, if i want to tweak the HTML, i have to do it for all of them. It's time-consuming, and there's risk of mistakes.
Quick and Dirty Templating
I'd like to write just one copy of the HTML, list the content items as plain text, and on page-render the HTML would get automatically repeated for each content-item.
HTML
<p><img src=IMAGE-URL>
<br>
<a target='_blank' href=LINK-URL>CAPTION</a></p>
Content List
IMAGE-URL, LINK-URL, CAPTION
/data/khang.jpg, https://khangssite.com, Khang Le
/data/sam.jpg, https://samssite.com, Sam Smith
/data/joy.jpg, https://joyssite.com, Joy Jones
/data/sue.jpg, https://suessite.com, Sue Sneed
/data/dog.jpg, https://dogssite.com, Brown Dog
/data/cat.jpg, https://catssite.com, Black Cat
Single Item
Ideally, i could put the plain-text content for a single item anywhere on a page, with some kind of identifier to indicate which HTML template to use (similar to classes with CSS).
TEMPLATE=MyTemplate1, IMAGE-URL=khang.jpg, LINK-URL=https://khangssite.com, CAPTION=Khang Le
Implementation
Templating systems are widely used, like Django and Smarty on the server side, and Mustache on the client side. This question seeks a simple, single-file template solution, without using external libs.
I want to achieve this without a framework, library, etc. I'd like to put the HTML and content-list in the same .html file.
Definitely no database. It should be quick and simple to set it up within a page, without installing or configuring additional services.
Ideally, i'd like to do this without javascript, but that's not a strict requirement. If there's javascript, it should be ignorant of the fieldnames. Ideally, very short and simple. No jquery please.
you mean Template literals (Template strings) ?
const arrData =
[ { img: '/data/khang.jpg', link: 'https://khangssite.com', txt: 'Khang Le' }
, { img: '/data/sam.jpg', link: 'https://samssite.com', txt: 'Sam Smith' }
, { img: '/data/joy.jpg', link: 'https://joyssite.com', txt: 'Joy Jones' }
, { img: '/data/sue.jpg', link: 'https://suessite.com', txt: 'Sue Sneed' }
, { img: '/data/dog.jpg', link: 'https://dogssite.com', txt: 'Brown Dog' }
, { img: '/data/cat.jpg', link: 'https://catssite.com', txt: 'Black Cat' }
]
const myObj = document.querySelector('#my-div')
arrData.forEach(({ img, link, txt }) =>
{
myObj.innerHTML += `
<p>
<img src="${img}">
<br>
<a target='_blank' href="${link}">${txt}</a>
</p>`
});
<div id="my-div"></div>
This answer is a complete solution. It's exciting to edit the HTML template in codepen and watch the layout of each copy change in real time -- similar to the experience of editing a CSS class and watching the live changes.
Here's the code, followed by explanation.
HTML
<span id="template-container"></span>
<div hidden id="template-data">
IMG,, LINK,, CAPTION
https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive.jpg,, khangssite.com,, Khang Le
https://i.redd.it/jeuusd992wd41.jpg,, suessite.com,, Sue Sneed
https://picsum.photos/536/354,, catssite.com,, Black Cat
</div>
<template id="art-template">
<span class="art-item">
<p>
<a href="${LINK}" target="_blank">
<img src="${IMG}" alt="" />
<br>
${CAPTION}
</a>
</p>
</span>
</template>
Javascript
window.onload = function LoadTemplate() {
// get template data.
let sRawData = document.querySelector("#template-data").innerHTML.trim();
// load header and data into arrays
const headersEnd = sRawData.indexOf("\n");
const headers = sRawData.slice(0, headersEnd).split(",,");
const aRows = sRawData.slice(headersEnd).trim().split("\n");
const data = aRows.map((element) => {
return element.split(",,");
});
// grab template and container
const templateHtml = document.querySelector("template").innerHTML;
const container = document.querySelector("#template-container");
// make html for each record
data.forEach((row) => {
let workingCopy = templateHtml;
// load current record into template
headers.forEach((header, column) => {
let value = row[column].trim();
let placeholder = `\$\{${header.trim()}\}`;
workingCopy = workingCopy.replaceAll(placeholder, value);
});
// append template to page, and loop to next record
container.innerHTML += workingCopy;
});
};
New version on github:
https://github.com/johnaweiss/HTML-Micro-Templating
Requirement
As specified in the question, this solution is intended to optimize the coding experience on the HTML side. That's the whole point of any web templating. Therefore, the JS has to work a little harder to make life easier for the HTML programmer.
The question seeks a reusable solution. Therefore, JS should be ignorant of the template, fields, and data-list. So unlike #MisterJojo's answer, the template and all data are in my HTML, not javascript. The JS code is generic.
Design
My solution is based on the <template> tag, which is intended for precisely this usage. It has various advantages, like the template isn't displayed, processed, or validated by the browser, so it has less impact on performance. Programmer doesn't have to write an explicit display:none style.
https://news.ycombinator.com/item?id=33089975
However, <template> tags are normally only intended for loading content into the layout. That's inadequate. This tool allows template variables anywhere in the HTML, including inside the tags (eg attributes like <img src).
HTML
My HTML has three blocks:
template: The HTML coder develops their desired display-structure of the output, in real HTML (not plain text). Uses <template>
data: The list of records each of which should be rendered using the same template. Uses <span> with a HIDDEN attribute.
container: The place to display all the output blocks. Uses <span>.
Template
My sample template includes 3 placeholders for data:
${LINK}
${IMG}
${CAPTION}
But of course you can use any placeholders, any number of them. I use string-literal delimiting-style (although i'm not actually using them as string-literals -- i just borrowed the delimiter style.)
Data Element
The question specifies data should be stored in HTML. It should require minimal keystrokes.
I didn't want to redundantly retype the fieldnames on every row. I didn't use slotting, JSO, Jason, or XML syntax, because those are all verbose.
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots
It's a simple delimited list. I eliminated all braces, brackets, equals, parens, colons etc.
I put the fieldname-headers only on the first row. The headers are a visual aid for the HTML developer, and a key for Javascript to know the fieldnames and order.
Record Delimiter: End-of-line
Field Delimiter: Double-commas. Seems safe, and they're easy to type. I don't expect to see double-commas in any actual data. Beware, the developer must enter a space for any empty cells, to prevent unintended double-commas. The programmer can easily use a different delimiter if they prefer, as long as they update the Javascript. You can use single-commas if you're sure there will be no embedded commas within a cell.
The data block is hidden using the hidden attribute. No CSS needed.
It's a span to ensure it takes up no room on the page.
JAVASCRIPT
Data
The data is processed by Javascript with two split statements, first on newline delimiter, then on the double-comma delimiter. That puts the whole thing into a 2D array. My JS uses trims to get rid of extra whitespace as needed.
Place-holder Substitution
Handling multiple entries requires plugging each entry into the template.
i went with simple string-replacement instead of string literals.
Multiple Templates
New version which supports multiple templates, and ability to use same template in multiple locations on same page.
https://github.com/johnaweiss/HTML-Micro-Templating
Future
Inspired by #MisterJojo, an earlier version of my solution used template literals to do the substitution. However, that was a bit more complicated and verbose, and seemed to require use of eval. So i switched to .replaceAll. Yet template-literals seems like a more appropriate method for templates, so maybe i'll revisit that.
A future version may adapt to whatever custom field-delimiter the HTML developer uses for the data block.
The dollar-curly delimiter for placeholders is a bit awkward to type. So i'm interested in finding a less awkward non-alpha delimiter that won't conflict with HTML. Considering double-brackets or braces [[NAME]]
Maybe there are simpler ways to pull the data-table into JS.
I've read components work well with <template>, but i didn't go there.
Imo, the JS committee should develop a variable-placeholder feature for <template> tags, and natively accommodate storing the data in HTML. It would be great if something like this solution was part of the rendering engine.
I am making a forum with markdown support.
I've been using meteor's markdown parser {{#markdown}} and have found something disturbing that I can't seem to figure out.
I am using {{#markdown}}{{content}}{{/markdown}} to render the content inserted into database.
The disturbing thing, for example, if someone writes up html without inserting it into the code block in the content...
example
<div class = "col-md-12">
Content Here
</div>
This will render as a column. They could also make buttons and etc through writing the HTML for it.
How to disable this behaviour so that when HTML is written it will not render into HTML but just simply show it as text?
You can write global helper, which will strip all html tags:
function stripHTML(string){
s = string.replace(/(<([^>]+)>)/ig, '');
return s;
}
Template.registerHelper('stripHTML', stripHTML)
Usage :
{{#markdown}}{{stripHTML content}}{{/markdown}}
Test it in console:
stripHTML("<div>Inside dive</div> Text outside")
First a bit of background information. I create HTML emails at my work place and the whole process is very tedious. It goes a little little like this...
Code markup for HTML using tables and some CSS
Parse HTML and CSS using Premailer so all CSS is inline
Test HTML works in all email clients
Create a copy of the inline version of HTML and start adding in proprietary variables to email tool used for sending emails, ie <%=constant.first_name%>, <%=unsubscribe_link%>
Test in email client to see if it works and client is happy. If not repeat steps 1 through 5 again.
So as you can see it gets really tedious after a while.
What I would like to do is create a command line script similar to Premailer which allows me to parse a HTML file with variables stored in it without destroying the example text already in the HTML. That way when you are previewing the HTML it all looks dandy.
For example...
Store the first name function as a variable for own use.
$first_name = "<%=constant.first_name%>
Then tell the parser what word(s) to replace with the appropriate variable.
<p>My name is <!-- $first_name -->Gavin<!-- /$first_name --></p>
So that the final output looks something like:
<p>My name is <%=constat.first_name%></p>
Would such a thing be possible? Is there a better syntax I could, a custom tag like <first_name>Gavin</first_name>, if the browser can handle it.
Any advice is helpful. :)
I've seen this done before using a syntax like:
{assign_variable:first_name="Jesse"}
Then, you could use it like:
{first_name}
The way you'd parse this (provided you're using PHP) would be something like:
<?php
// Our Template Code
$strHTML = <<<EOT
{assign_variable:first_name="Jesse"}
{assign_variable:last_name="Bunch"}
Hello, {first_name}!
EOT;
// Get all the variables
$arrMatches = array();
preg_match_all('/\{assign\_variable\:([a-zA-Z\_\-]*)\=\"([a-zA-Z0-9]+)\"\}/', $strHTML, $arrMatches);
// Remove the assign_variable tags
$strHTML = preg_replace('/\{assign\_variable\:([a-zA-Z\_\-]*)\=\"([a-zA-Z0-9]+)\"\}/', '', $strHTML);
// Combine them into key/values
$arrVariables = array_combine($arrMatches[1], $arrMatches[2]);
foreach($arrVariables as $key=>$value) {
// Replace the variable occurrences
$strHTML = str_replace('{' . $key . '}', $value, $strHTML);
}
// Send the parsed template
echo $strHTML;
Which outputs:
Hello, Jesse!
Note, this is a very basic example. Here are some improvements to make on this code before using it in production:
Edit the regex to allow the right characters.
Maybe implement a better replacement method than a loop
Check for parse errors
Benchmark performance
All in all, I think you get the idea. Hope this points you in the right direction.
I have a similar situation
I have created a "format template" like this:
<?php // section1 $var1/$var2 ?>
<head>
<title>$var1</title>
<meta name="description" content="$var2">
</head>
<?php // section2 $var1/$var2 ?>
<body>
hello: <p>$var1</p>
news for you: <p>$var2</p>
</body>
it is valid php code and valid html code, so you can edit it with dreamwaver or similar, and you can host it also.
then a php script replaces all ocurrences of vars in all sections.
I'm using WebBrowser to get source of html pages .
Our page source have some text and some html tags . like this :
FONT></P><P align=center><FONT color=#ccffcc size=3>**Hello There , This is a text in our html page** </FONT></P><P align=center> </P>
Html tags are random and we can not guess them . So is there any way to get texts only and separating them from html tags ?
you can use a TWebBrowser instance to parse and select the plaint text from html code.
see this sample
uses
MSHTML,
SHDocVw,
ActiveX;
function GetPlainText(Const Html: string): string;
var
DummyWebBrowser: TWebBrowser;
Document : IHtmlDocument2;
DummyVar : Variant;
begin
Result := '';
DummyWebBrowser := TWebBrowser.Create(nil);
try
//open an blank page to create a IHtmlDocument2 instance
DummyWebBrowser.Navigate('about:blank');
Document := DummyWebBrowser.Document as IHtmlDocument2;
if (Assigned(Document)) then //Check the Document
begin
DummyVar := VarArrayCreate([0, 0], varVariant); //Create a variant array to write the html code to the IHtmlDocument2
DummyVar[0] := Html; //assign the html code to the variant array
Document.Write(PSafeArray(TVarData(DummyVar).VArray)); //set the html in the document
Document.Close;
Result :=(Document.body as IHTMLBodyElement).createTextRange.text;//get the plain text
end;
finally
DummyWebBrowser.Free;
end;
end;
You should look at using the Delphi DOM HTML parser
If your asterisk is constant, you can simply get everychar between **.
If your asterisk is not constant you can rewrite this string and erase all tags (things who starting from < and ending with >. Or you can use some DOM parser library for it.
In essence: in general you can't.
HTML is a markup language with such a wide use and mind boggling possibilities to change the content dynamically that it is virtually impossible to do this (just look at how hard the web browser suppliers need to work to pass for instance the acid tests). So you can only do a subset.
For specific and well defined subsets of HTML, then you have a better chance:
First you need to get the HTML in a
string, then parse that HTML.
Getting the HTML can be done for instance using Indy (see answers to this question).
Parsing highly depends on your HTML and can be quite complex, you can try this question or this search.
You could use TWebBrowser as RRuz suggests, but it depends on Internet Explorer.
Modern Windows systems do not guarantee that Internet Explorer is installed any more...
--jeroen
Using Delphi HTML Component Library getting text only from HTML document is simple.
THtDocument.InnerText property returns formatted text without tags.
How can you prevent any automatic formatting when in CKEditor when viewing in source mode?
I like to edit HTML source code directly instead of using the WYSIWYG interface, but whenever I write new lines, or layout tags how I would indent them, it all gets formatted when I switch to WYSIWYG mode and then back to source mode again.
I stumbled upon a CKEditor dev ticket, Preserve formatting of ProtectedSource elements, that alluded to a setting which may have existed once upon a time which would be exactly what I'm after. I just want to know how I can completely turn off all automatic formatting when editing in source mode.
I came up with a solution I thought would be foolproof (albeit not a pleasant one).
I learned about the protectedSource setting, so I thought, well maybe I can just use that and create an HTML comment tag before all my HTML and another after it and then push a regular expression finding the comment tags into the protectedSource array, but even that (believe it or not) doesn't work.
I've tried my expression straight up in the browser outside of CKEditor and it is working, but CKEditor doesn't protect the code as expected (which I suspect is a bug involving comment tags, since I can get it to work with other strings). In case you are wondering, this is what I had hoped would work as a work-around, but doesn't:
config.protectedSource.push( /<!-- src -->[\s\S]*<!-- end src-->/gi );
and what I planned on doing (for what appears to be the lack of a setting to disable formatting in source mode) was to nest all my HTML within the commented tags like this:
<!-- src -->
<div>some code that shouldn't be messed with (but is)</div>
<!-- end src -->
I'd love to hear if anyone has any suggestions for this scenario, or knows of a setting which I have described, or even if someone can just fill me in as to why I can't get protectedSource to work properly with two comment tags.
I really think it's gotta be a bug because I can get so many other expressions to work fine, and I can even protect HTML within the area of a single comment tag, but I simply cannot get HTML within two different comment tags to stay untouched.
My solution to this was to use comments in my system, but before feeding the page content to CKEditor, convert them to custom HTML tags. Then, upon save, convert them back to my comment tags.
For your syntax that would be something like this in PHP. Before printing the page content to the textarea:
$content = str_replace(array('<!-- src -->','<!-- end src -->'),array('<protected>','</protected>'),$content);
Before saving the resulting content:
$content = str_replace(array('<protected>','</protected>'),array('<!-- src -->','<!-- end src -->'),$content);
In the CKEditor configuration:
protectedSource:[/<protected>[\s\S]*<\/protected>/g]
Hope that helps!
I wanted to preserve newlines in my source, and the protectedSource feature works well for that. I added this to my config.js:
config.protectedSource = [/\r|\n/g];
config.allowedContent=true; will do the trick
Here is the full HTML code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CKEditor</title>
<script src="http://cdn.ckeditor.com/4.5.10/standard/ckeditor.js"></script>
</head>
<body>
<textarea name="editor1"></textarea>
<script>
CKEDITOR.config.allowedContent=true;
CKEDITOR.replace( 'editor1' );
</script>
</body>
</html>
I solved this problem by simply surrounding the back-end output of edit form page with a conditional on a $_GET variable - when you click on "Expert Mode" it loads a plain textarea instead of the ckeditor system. Your invocation of the ckeditor object will vary depending on your setup. ( I have a custom class that calls/builds the editor object )
<div id="postdivrich" class="postarea">
<?php
if( isset( $_GET['expert'] ) )
{
print "<div style=\"text-align:right;\">Editor mode</div>\n";
print "<textarea name=\"content\" style=\"height:400px;width:{$nEwidth}px;\">{$aDoc['content']}</textarea>\n";
}
else
{
print "<div style=\"text-align:right;\">Expert mode</div>\n";
require_once( 'admin/editor.class.php' );
$aDoc['content'] = str_replace( "\r", '', str_replace( "\n", '', nl2br( $aDoc['content'] ) ) );
$oEditor = new setEditor( $aDoc['content'], $nEwidth, "400", 'content' );
$oEditor->ShowEditor();
}
?>
</div>
Does this answer help? Basically you can turn off the options adding a javascript, it looks like.