2

Motivation: https://stackoverflow.com/questions/28120689/create-self-modifying-html-page-on-box

Bug: String escaping , formatting html , js generated by initial edited , saved html , js

e.g.,

a) if open "saveFile.html" at local browser ;

b) type "abc" into textarea ;

c) click save file button ;

d) click Save at Save File dialog ;

e) file-*[date according to universal time].html saved to disk ;

f) open file-*[date according to universal time].html in browser ;

g) type "def" into textarea ;

h) repeat d) , e) , f) ;

i) Bug: result at second file-*[date according to universal time].html does display textarea containing "abc def" text content ; buttonnot displayed at html:

// at rendered `html` from second `file-*[date according to universal time].html` // `textarea` containing "abc def" displayed here , // `button` _not_ displayed ; following string displayed following `textarea`: ');"console.log(clone);var file = new Blob([clone], {'type':'text/html'});a.href = URL.createObjectURL(file);a.download = 'file-' + new Date().getTime() + '.html';a.click();}; 

generated at line 26 , "saveFile.html"

+ "var clone = '<!doctype html>'+ document.documentElement.outerHTML.replace(/<textarea>.*<.+textarea>/, '<textarea>'+document.getElementsByTagName('textarea')[0].value+'<\/textarea>');" 

"saveFile.html" v 1.0.0

html , js

<!doctype html> <html> <!-- saveFile.html 1.0.0 2015 guest271314 edit, save `html` document --> <head> </head> <body> <textarea> </textarea> <button>save file</button> <script type="text/javascript"> var saveFile = document.getElementsByTagName("button")[0]; var input = document.getElementsByTagName("textarea")[0]; var a = document.createElement("a"); saveFile.onclick = function(e) { var clone = ["<!doctype html><head></head><body><textarea>" + input.value + "</textarea>" + "<button>save file</button>" + "<script type='text/javascript'>" + "var saveFile = document.getElementsByTagName('button')[0];" + "var input = document.getElementsByTagName('textarea')[0];" + "var a = document.createElement('a');" + "saveFile.onclick = function(e) {" + "var clone = '<!doctype html>'+ document.documentElement.outerHTML.replace(/<textarea>.*<.+textarea>/, '<textarea>'+document.getElementsByTagName('textarea')[0].value+'<\/textarea>');" + "console.log(clone);" + "var file = new Blob([clone], {'type':'text/html'});" + "a.href = URL.createObjectURL(file);" + "a.download = 'file-' + new Date().getTime() + '.html';" + "a.click();" + "};" + "</scr"+"ipt>" + "</body>" + "</html>"]; var file = new Blob([clone], {"type":"text/html"}); a.href = URL.createObjectURL(file); a.download = "file-" + new Date().getTime() + ".html"; a.click(); }; </script> </body> </html> 
2
  • 2
    Can you explain more clearly and simply what should be happening vs what is actually occurring? Maybe give some better context on the overall concept as well?
    – Anthony
    CommentedJun 1, 2015 at 3:21
  • @Anthony Expected result is saved file following click on "save file" button , when opened , should render text input into textarea element from previous html document , including sibling button element. Context is attempt to create self-modifying , pseudo-polymorphic html document , where changes made at textarea , saved at one version , rendered at next saved version.CommentedJun 1, 2015 at 3:53

2 Answers 2

1

Your replace function replaces until the /textarea> that is in your clone variable. It doesn't do it from the first file because there's a newline character after textarea in the html. One way to fix it would be to add a newline character in the generated html. Like this:

var clone = ["<!doctype html><head></head><body><textarea>" + input.value // add newline here + "</textarea>\n" + "<button>save file</button>" + "<script type='text/javascript'>" + "var saveFile = document.getElementsByTagName('button')[0];" + "var input = document.getElementsByTagName('textarea')[0];" + "var a = document.createElement('a');" + "saveFile.onclick = function(e) {" + "var clone = '<!doctype html>'+ document.documentElement.outerHTML.replace(/<textarea>.*<.+textarea>/, '<textarea>'+document.getElementsByTagName('textarea')[0].value+'<\/textarea>');" + "console.log(clone);" + "var file = new Blob([clone], {'type':'text/html'});" + "a.href = URL.createObjectURL(file);" + "a.download = 'file-' + new Date().getTime() + '.html';" + "a.click();" + "};" + "</scr"+"ipt>" + "</body>" + "</html>"]; 
2
  • Tried + '</textarea>\n');" , button was displayed , though appeared to render new line at js ; next line beginning with ');console.log(clone) rendered as text string , not js at source.CommentedJun 1, 2015 at 3:42
  • 1
    see edit, you need to add \n after first "</textarea>"CommentedJun 1, 2015 at 3:53
1

I'm not sure what is breaking the third-generation clone so that it results in the js info being output to the page, but it would probably be better to use an actual document object to clone/manipulate the original and output its contents as string for the Blob object. For example, I tested using your base saveFile.html with the following changes:

//remove original clone var and replace with: var clone = document.cloneNode(true); // grab textarea elements from both original document and clone: var doc_input = document.getElementsByTagName("textarea")[0]; var clone_input = clone.getElementsByTagName("textarea")[0]; // set clone textarea's innerHTML to current textarea value: clone_input.innerHTML = doc_input.value; // use outerHTML of clone.documentElement to get string for Blob var clone_string = [clone.documentElement.outerHTML]; var file = new Blob([clone_string], {"type":"text/html"}); 

The only downsides I am seeing are:

  1. This may be hard to expand into a more generic framework for generating a "live HTML file" of current state of loaded HTML page (though it shouldn't be more complicated than your example approach).

  2. The string returned by clone.documentElement.outerHTML appears to drop the document type declaration to a simple element so that :

is not in the output string. You could probably use something like:

var clone_string = ["<!doctype html>" + clone.documentElement.outerHTML]; 

as a workaround. Or, for something more robust:

var doc_doctype = new XMLSerializer().serializeToString(document.doctype); var clone_string = [doc_doctype + clone.documentElement.outerHTML]; 
1
  • 1
    Updated. Also added a v2 of the html that just uses serializeToString instead of outerHTML. Make sure that you test against any browsers you want it to work with.
    – Anthony
    CommentedJun 1, 2015 at 4:51

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.