http://codepen.io/kevinchappell/pen/mPQMYZ
function showPreview() {
let formRenderOpts = {
formData: fbTemplate.value,
render: false
},
renderedForm = new FormRenderFn(formRenderOpts).markup,
html = `<!doctype html><title>Form Preview</title><body>${renderedForm}</body></html>`;
var formPreviewWindow = '';//window.open('', 'formPreview', 'height=480,width=640,toolbar=no,scrollbars=yes');
formPreviewWindow.document.write(html);
var style = document.createElement('link');
style.appendChild(document.createTextNode(''));
style.setAttribute('href', '//formbuilder.online/assets/css/form-render.min.css');
style.setAttribute('rel', 'stylesheet');
style.setAttribute('type', 'text/css');
formPreviewWindow.document.head.appendChild(style);
}
Instead of opening the html using window.open, how can I save the html to a variable?
With jQuery available, it's simple to just use the jQuery/$ constructor shortcut to turn your HTML string into a jQuery object. You can then use jQuery's append methods to more succinctly append your stylesheet.
The resulting object can then either be inserted in to the document, or have return the full HTML with jQuery's html() method.
var formRenderOpts = {
formData: fbTemplate.value,
render: false
},
renderedForm = new FormRenderFn(formRenderOpts).markup,
html = $('<!doctype html><head><title>Form Preview</title></head><body>' + renderedForm + '</body></html>');
html.find('head').append('<link rel="stylesheet" href="//formbuilder.online/assets/css/form-render.min.css"></style>');
//Output the HTML:
console.log(html.html());
Related
i am using javascript code to get html content from one the pages, while at the same time i also want to change the content i get from html (inside the carttitle id). how can i change the value of id=carttitle on the cartbox.html below dynamically?
this is the code (div where the html will be located)
<!-- index.html -->
<!-- button to trigger the function -->
<button onclick="getcontent('cartbox.html','#cartboxes','#cartbox');">getcontent</button> <!-- the cartbox.html will fill the content below -->
<ul class="cartboxes" id="cartboxes">
</ul>
this is the javascript code function to get the html
// select.js
function getcontent(url, from, to) {
var cached = sessionStorage[url];
if (!from) {
from = "body";
} // default to grabbing body tag
if (to && to.split) {
to = document.querySelector(to);
} // a string TO turns into an element
if (!to) {
to = document.querySelector(from);
} // default re-using the source elm as the target elm
if (cached) {
return to.innerHTML = cached;
} // cache responses for instant re-use re-use
var XHRt = new XMLHttpRequest; // new ajax
XHRt.responseType = 'document'; // ajax2 context and onload() event
XHRt.onload = function() {
sessionStorage[url] = to.innerHTML = XHRt.response.querySelector(from).innerHTML;
};
XHRt.open("GET", url, true);
XHRt.send();
return XHRt;
}
this is the html code that i will get the content from
<!-- cartbox.html -->
<div id="cartbox">
<li>
<div class="cartbox">
<div class="cartboxleft">
<img src="img/search.png" width="60px" height="60px">
</div>
<div class="cartboxright">
<!-- i want to change the value of the carttitle below dynamically -->
<b class="carttitle" id="carttitle">nice Pizza</b>
<p class="cartdescription">Number: <b>1</b></p>
<p class="cartdescription">Price: <b>$ 11.22</b></p>
</div>
<div class="cartboxdelete">
<button class="deletebutton" onclick="deleteitem(this);">X</button>
</div>
</div>
</li>
</div>
You should use responseType = 'text' as document responseType is not recommended to avoids wasting time parsing HTML uselessly. Now regarding your issue, you can do like this:
function getcontent(url, fromSelector, toSelector) {
var cached = sessionStorage[url];
if (cached) {
return toSelector.innerHTML = cached;
}
fromSelector = fromSelector || 'body';
toSelector = toSelector && document.querySelector(toSelector) || document.querySelector(fromSelector);
var XHRt = new XMLHttpRequest();
XHRt.open("GET", url, true);
XHRt.responseType = 'text';
XHRt.onload = function() {
if (XHRt.readyState === XHRt.DONE && XHRt.status === 200) {
toSelector.innerHTML = XHRt.responseText;
document.getElementById('carttitle').innerHTML = 'your new value';
sessionStorage[url] = toSelector.innerHTML; // Now it will work after loading from session storage.
}
};
XHRt.send();
}
Your cache process will not work because you are selecting a property with the brackets operator [] on the session storage object.
Instead use the getItem() method to get the key that you are looking for.
var cached = sessionStorage.getItem(url);
In your second if statement you check to and to.split. Unless the to string has a split property, this will fail. Your intentions here seem unknown. Instead just check for the string to be a valid string instead.
if (to && 'string' === typeof to) {
The part where you create a new instance of XMLHttpRequest will fail because you are missing the parenthesis to call the constructor.
var XHRt = new XMLHttpRequest();
Then in your onload callback you have to save the innerHTML of your result in the session storage using the setItem() method.
But before doing that, select the cart title element with querySelector and change the content of the element if you need it to.
XHRt.onload = function() {
let element = this.response.querySelector(from);
if (element !== null) {
let cartTitle = element.querySelector('#carttitle');
cartTitle.textContent = 'An even better pizza';
let html = element.innerHTML;
to.innerHTML = html;
sessionStorage.setItem(url, html);
}
};
I am trying to create an sdk in javscript/jquery for creating templates based on user input, such as the type of templates - profile template, dialog template. These templates require data from an ajax call for their creation.
User Input should include some config param and type of templates.
Since I don't have much experience creating sdk's, I am trying to create a scalable and flexible sdk which can adopt some more functionalities and properties in future.
I am stuck on the problem that what is the basic and best way to create an javascript/jquery sdk?
var dialogTemplate , var = template2 I have added sample templates. The requirement is when user passes template/templates name in tmpConfig.config.type create that particular template/templates by fetching their data simultaneously for each template/templates.Suppose, when call 'dialog template' create dialog template. when call 'dialog template' and 'template2' create both and append it. These template name can be send in array in config.
Below is what I have tried:-
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="mySDK.js"></script>
</head>
<body>
// container for templates
<div id="tmpBox"></div>
</body>
<script type="text/javascript">
const tmpConfig = {
config: {
type: ['dialog','template2',...,...,....]
},
boxId: '#tmpBox'
};
var mySDK= new tmpSDK(tmpConfig );
mySDK.createtemplate(); // create template
</script>
</html>
mySDK.js
function tmpSDK(confg){
// implementation of sdk
this.config = confg;
}
tmpSDK.prototype.createtemplate= function(){
var idsToAppendTemplate = this.config.boxId;
var templateTypes = this.config.type;
// checking number of templates to create
for(var i=0 ; i < templateTypes.length; i++){
if(templateTypes === 'dialog'){
createDialog(idsToAppendTemplate )
}else if(templateTypes === 'template2'){
createTemplate2 (idsToAppendTemplate )
}
}
}
function getData(ajaxConfig){
$.ajax(){
return data;
}
}
// different templates html defined below:-
var dialogTemplate = function(data){
// play with data
var html = '<div class='dialog-template'>MY Dialog Template</div>';
return html;
}
var template2 = function(data){
// play with data
var html = '<div class='template2'>MY Template2</div>';
return html;
}
tmpSDK.prototype.createDialog = function(id){
var ajaxConfig = {
'url' : 'http://dialog endponts/',
....
}
var data = getData(ajaxConfig);
$(id).append(dialogTemplate(data)); // var dialogTemplate
}
tmpSDK.prototype.createTemplate2 = function(id){
var ajaxConfig = {
'url' : 'http://template2endponts/',
....
}
var data = getData(ajaxConfig);
$(id).append(template2(data) ); //// var template2
}
Please, consider to create your sdk as jQuery module with Class using.
(function ( $ ) {
$.fn.mySdk = function(options) {
const element = $(this);
const sdk = new MySdk(options, element);
element.data('plugin-my-sdk', sdk);
return $(this);
};
$.fn.getMySdk = function() {
const element = $(this);
return element.data('plugin-my-sdk');
};
class MySdk {
constructor(options, element) {
this.element = element;
this.settings = $.extend({
type: 'dialog',
}, options );
this.fetchTemplate().done(this.applyTemplate.bind(this));
}
fetchTemplate() {
return $.post({
url: `${document.location.origin}/your-endpoint-for-getting-template`,
data: {
'id': this.element.attr('id'),
'type': this.settings.type
}
});
}
applyTemplate(template) {
this.element.html(template);
}
apiMethod() {
const yourElement = this.element;
const yourElementId = this.element.attr('id');
const yourType = this.settings.type;
}
}
}( jQuery ));
// This snippet - is example of using your sdk
jQuery(function ($) {
const element = $('#tmpBox');
element.mySdk({
type: 'dialog'
});
const sdk = element.getMySdk();
sdk.apiMethod();
});
What this snippet do?
Wrap jQuery function for creating a not global scope and for avoiding jQuery conflict with $ function name
Uses MySdk class for the element.
This works for the case when there is only one jquery element in collection taking by the selector. In this case - const element = $('#tmpBox'); is taking only one element.
This snippet
this.settings = this.settings = $.extend({
type: 'dialog',
}, options );
merges default options with your options. If there is no option in your options object - then default option will be used
If you need to use jquery collection
For example, your sdk element is $('.tmpBox') where is there are more than 1 element - please, consider to use in mySdk each function for init every element.
const elements = $(this);
element.each(function(){
// init for every element;
})
This is simple and I have done it before but can't make it work right now.
I need to change the name of the image in below href
var href="https://www.facebook.com/sharer/sharer.php?u=http://myurl.com/&description='tets'&picture=http://myurl.com/img/name-1654-45654.jpg"
$('.share, .share-2').prop('href', function () {
$(this).replace(/(picture=).*?(&)/,'$1' + imgNew + '$2');
});
Since the href string is a URL, you can take advantage of the URL object.
var imgNew = 'http://example.com/img.png';
var href = "https://www.facebook.com/sharer/sharer.php?u=http://myurl.com/&description='tets'&picture=http://myurl.com/img/name-1654-45654.jpg";
var url = new URL(href);
url.searchParams.set('picture', imgNew);
console.log(url.href);
Note that not all browsers are supported at this time, so you can use a polyfill.
The replace function is a method of string, so you can't call replace from $(this) because it is a jQuery object, not a string.
If you need to change the href attribute, just use this.href = ....
EDIT: As you are using jQuery.prop method you should use it as docs proposes.
$(".some-element").prop('some-prop', function(index, old_value){
// do something
return new_value;
});
Snippet updated:
var new_img = "http://my.domain.com/img/my_new_image.jpg";
var regex_img = /\bpicture=[^&]*/
$('.share, .share-2').prop('href', function (index, old_href) {
var new_href = old_href.replace(regex_img, 'picture=' + new_img);
console.log(new_href);
return new_href;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Test
<br>
Test-2
var href="https://www.facebook.com/sharer/sharer.php?
u=http://myurl.com/&description='tets'&picture=http://myurl.com/img/name-
1654-45654.jpg"
href.split('/')
["https:", "", "www.facebook.com", "sharer", "sharer.php?u=http:", "",
"myurl.com", "&description='tets'&picture=http:", "", "myurl.com", "img",
"name-1654-45654.jpg"]
href.split('/').length
12
href.split('/')[11]
"name-1654-45654.jpg"
You should change your code to the following one.
href="https://www.facebook.com/sharer/sharer.php?u=http://myurl.com/&description='tets'&picture=http://myurl.com/img/name-1654-45654.jpg"
$('.share, .share-2').prop('href', function () {
$(this).replace(/\/(?=[^\/]*$)/, '/newpicturename'));
});
The last slash and following words will be replaced by the new picture name.
An example
var str = "http://one/two/three/four";
console.log(str.replace(/\/(?=[^\/]*$)/, '/newpicturename'));
I am using Meteor and I am trying to check if a text is html. But usual ways do not work. This is my code:
post: function() {
var postId = Session.get("postId");
var post = Posts.findOne({
_id: postId
});
var object = new Object();
if (post) {
object.title = post.title;
if ($(post.content).has("p")) { //$(post.content).has("p") / post.content instanceof HTMLElement
object.text = $(post.content).text();
if (post.content.match(/<img src="(.*?)"/)) {
object.image = post.content.match(/<img src="(.*?)"/)[1];
}
} else {
console.log("it is not an html------------------------");
object.text = post.content;
}
}
return object;
}
Actually, this is the most "working" solution I have used up to now. Also, I pointed out the two most common ways which I use (next to the if statement). Is it possible to happen without regex.
Can use approach you already started with jQuery but append response to a new <div> and check if that element has children. If jQuery finds children it is html.
If it is html you can then search that div for any type of element using find().
// create element and inject content into it
var $div=$('<div>').html(post.content);
// if there are any children it is html
if($div.children().length){
console.log('this is html');
var $img = $div.find('img');
console.log('There are ' + $img.length +' image(s)');
}else{
console.log('this is not html');
}
Use the jquery $.parseHTML function to parse the string into an array of DOM nodes and check if it has any HTMLElement.
var htmlText = "----<b>abc</b>----<h3>GOOD</h3>----";
htmlText = prompt("Please enter something:", "----<b>abc</b>----");
var htmlArray = $.parseHTML(htmlText);
var isHtml = htmlArray.filter(function(e){ return e instanceof HTMLElement;}).length;
console.log(htmlText);
//console.log(htmlArray);
if (isHtml)
console.log(isHtml + " HTML Element(s) found.");
else
console.log("No HTML Elements found!");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'd like to save the html string of the DOM, and later restore it to be exactly the same. The code looks something like this:
var stringified = document.documentElement.innerHTML
// later, after serializing and deserializing
document.documentElement.innerHTML = stringified
This works when everything is perfect, but when the DOM is not w3c-comliant, there's a problem. The first line works fine, stringified matches the DOM exactly. But when I restore from the (non-w3c-compliant) stringified, the browser does some magic and the resulting DOM is not the same as it was originally.
For example, if my original DOM looks like
<p><div></div></p>
then the final DOM will look like
<p></p><div></div><p></p>
since div elements are not allowed to be inside p elements. Is there some way I can get the browser to use the same html parsing that it does on page load and accept broken html as-is?
Why is the html broken in the first place? The DOM is not controlled by me.
Here's a jsfiddle to show the behavior http://jsfiddle.net/b2x7rnfm/5/. Open your console.
<body>
<div id="asdf"><p id="outer"></p></div>
<script type="text/javascript">
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
document.getElementById('outer').appendChild(insert);
var e = document.getElementById('asdf')
console.log(e.innerHTML);
e.innerHTML = e.innerHTML;
console.log(e.innerHTML); // This is different than 2 lines above!!
</script>
</body>
If you need to be able to save and restore an invalid HTML structure, you could do it by way of XML. The code which follows comes from this fiddle.
To save, you create a new XML document to which you add the nodes you want to serialize:
var asdf = document.getElementById("asdf");
var outer = document.getElementById("outer");
var add = document.getElementById("add");
var save = document.getElementById("save");
var restore = document.getElementById("restore");
var saved = undefined;
save.addEventListener("click", function () {
if (saved !== undefined)
return; /// Do not overwrite
// Create a fake document with a single top-level element, as
// required by XML.
var parser = new DOMParser();
var doc = parser.parseFromString("<top/>", "text/xml");
// We could skip the cloning and just move the nodes to the XML
// document. This would have the effect of saving and removing
// at the same time but I wanted to show what saving while
// preserving the data would look like
var clone = asdf.cloneNode(true);
var top = doc.firstChild;
var child = asdf.firstChild;
while (child) {
top.appendChild(child);
child = asdf.firstChild;
}
saved = top.innerHTML;
console.log("saved as: ", saved);
// Perform the removal here.
asdf.innerHTML = "";
});
To restore, you create an XML document to deserialize what you saved and then add the nodes to your document:
restore.addEventListener("click", function () {
if (saved === undefined)
return; // Don't restore undefined data!
// We parse the XML we saved.
var parser = new DOMParser();
var doc = parser.parseFromString("<top>" + saved + "</top>", "text/xml");
var top = doc.firstChild;
var child = top.firstChild;
while (child) {
asdf.appendChild(child);
// Remove the extra junk added by the XML parser.
child.removeAttribute("xmlns");
child = top.firstChild;
}
saved = undefined;
console.log("inner html after restore", asdf.innerHTML);
});
Using the fiddle, you can:
Press the "Add LadyGaga..." button to create the invalid HTML.
Press "Save and Remove from Document" to save the structure in asdf and clear its contents. This prints to the console what was saved.
Press "Restore" to restore the structure that was saved.
The code above aims to be general. It would be possible to simplify the code if some assumptions can be made about the HTML structure to be saved. For instance blah is not a well-formed XML document because you need a single top element in XML. So the code above takes pains to add a top-level element (top) to prevent this problem. It is also generally not possible to just parse an HTML serialization as XML so the save operation serializes to XML.
This is a proof-of-concept more than anything. There could be side-effects from moving nodes created in an HTML document to an XML document or the other way around that I have not anticipated. I've run the code above on Chrome and FF. I don't have IE at hand to run it there.
This won't work for your most recent clarification, that you must have a string copy. Leaving it, though, for others who may have more flexibility.
Since using the DOM seems to allow you to preserve, to some degree, the invalid structure, and using innerHTML involves reparsing with (as you've observed) side-effects, we have to look at not using innerHTML:
You can clone the original, and then swap in the clone:
var e = document.getElementById('asdf')
snippet.log("1: " + e.innerHTML);
var clone = e.cloneNode(true);
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
document.getElementById('outer').appendChild(insert);
snippet.log("2: " + e.innerHTML);
e.parentNode.replaceChild(clone, e);
e = clone;
snippet.log("3: " + e.innerHTML);
Live Example:
var e = document.getElementById('asdf')
snippet.log("1: " + e.innerHTML);
var clone = e.cloneNode(true);
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
document.getElementById('outer').appendChild(insert);
snippet.log("2: " + e.innerHTML);
e.parentNode.replaceChild(clone, e);
e = clone;
snippet.log("3: " + e.innerHTML);
<div id="asdf">
<p id="outer">
<div>ladygaga</div>
</p>
</div>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Note that just like the innerHTML solution, this will wipe out event handlers on the elements in question. You could preserve handlers on the outermost element by creating a document fragment and cloning its children into it, but that would still lose handlers on the children.
This earlier solution won't apply to you, but may apply to others in the future:
My earlier solution was to track what you changed, and undo the changes one-by-one. So in your example, that means removing the insert element:
var e = document.getElementById('asdf')
console.log("1: " + e.innerHTML);
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
var outer = document.getElementById('outer');
outer.appendChild(insert);
console.log("2: " + e.innerHTML);
outer.removeChild(insert);
console.log("3: " + e.innerHTML);
var e = document.getElementById('asdf')
snippet.log("1: " + e.innerHTML);
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
var outer = document.getElementById('outer');
outer.appendChild(insert);
snippet.log("2: " + e.innerHTML);
outer.removeChild(insert);
snippet.log("3: " + e.innerHTML);
<div id="asdf">
<p id="outer">
<div>ladygaga</div>
</p>
</div>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Try utilizing Blob , URL.createObjectURL to export html ; include script tag in exported html which removes <div></div><p></p> elements from rendered html document
html
<body>
<div id="asdf">
<p id="outer"></p>
</div>
<script>
var insert = document.createElement("div");
var text = document.createTextNode("ladygaga");
insert.appendChild(text);
document.getElementById("outer").appendChild(insert);
var elem = document.getElementById("asdf");
var r = document.querySelectorAll("[id=outer] ~ *");
// remove last `div` , `p` elements from `#asdf`
for (var i = 0; i < r.length; ++i) {
elem.removeChild(r[i])
}
</script>
</body>
js
var e = document.getElementById("asdf");
var html = e.outerHTML;
console.log(document.body.outerHTML);
var blob = new Blob([document.body.outerHTML], {
type: "text/html"
});
var objUrl = window.URL.createObjectURL(blob);
var popup = window.open(objUrl, "popup", "width=300, height=200");
jsfiddle http://jsfiddle.net/b2x7rnfm/11/
see this example: http://jsfiddle.net/kevalbhatt18/1Lcgaprc/
MDN cloneNode
var e = document.getElementById('asdf')
console.log(e.innerHTML);
backupElem = e.cloneNode(true);
// Your tinkering with the original
e.parentNode.replaceChild(backupElem, e);
console.log(e.innerHTML);
You can not expect HTML to be parsed as a non-compliant HTML. But since the structure of compiled non-compliant HTML is very predictable you can make a function which makes the HTML non-compliant again like this:
function ruinTheHtml() {
var allElements = document.body.getElementsByTagName( "*" ),
next,
afterNext;
Array.prototype.map.call( allElements,function( el,i ){
if( el.tagName !== 'SCRIPT' && el.tagName !== 'STYLE' ) {
if(el.textContent === '') {
next = el.nextSibling;
afterNext = next.nextSibling;
if( afterNext.textContent === '' ) {
el.parentNode.removeChild( afterNext );
el.appendChild( next );
}
}
}
});
}
See the fiddle:
http://jsfiddle.net/pqah8e25/3/
You have to clone the node instead of copying html. Parsing rules will force the browser to close p when seeing div.
If you really need to get html from that string and it is valid xml, then you can use following code ($ is jQuery):
var html = "<p><div></div></p>";
var div = document.createElement("div");
var xml = $.parseXML(html);
div.appendChild(xml.documentElement);
div.innerHTML === html // true
You can use outerHTML, it perseveres the original structure:
(based on your original sample)
<div id="asdf"><p id="outer"></p></div>
<script type="text/javascript">
var insert = document.createElement('div');
var text = document.createTextNode('ladygaga');
insert.appendChild(text);
document.getElementById('outer').appendChild(insert);
var e = document.getElementById('asdf')
console.log(e.outerHTML);
e.outerHTML = e.outerHTML;
console.log(e.outerHTML);
</script>
Demo: http://jsfiddle.net/b2x7rnfm/7