Dynamic execution in Ajax returns to js in innerHTML

Source: Internet
Author: User

 

**************************************** ****************************
*Copyright Notice
*
* This document uses the Creative Commons release. Please strictly abide by this authorization protocol.
* This article was first published onBlogThis statement is an integral part of this article.
* Author's network name: prodigal son
* Author EMAIL: Dayichen (at) 163.com
* Author's BLOG: Http: // Www. Cnblogs. Com/Walkingboy
*
**************************************** ****************************

[CallbackPlus] js in innerHTML returned by dynamic execution in Ajax

-Written by prodigal son @ cnblogs.com (07-08-20)

 

Abstract:

Recently, a container update control similar to Asp.net ajax UpdatePanel and ca Callback is added for CallbackPlus, and innerHtml is used to update and generate html code, however, updating js script files is quite troublesome. I am not satisfied with the call method of scriptmanager in asp.net ajax, So I thought of a method for processing.

Insert Script dynamically:

The first problem encountered was that the generated html (including the html Tag and script) was inserted into the innerHtml of the corresponding container, but the script was missing. The returned script is like this. <script>... </script>. If you dynamically use document. the person who writes the output script to the page may understand that writing in this way will cause errors, you must </script> and write it apart ("</SCRIPT" + ">"). After modification (the Code is as follows), html insertion is normal.

<HTML><SCRIPT>function insertScript(){var sHTML="<input type=button onclick=" + "run()" + " value='Click Me'><BR>";var sScript="<SCRIPT>";sScript = sScript + "function run(){ alert('Hello from inserted script.') }";sScript = sScript + "</SCRIPT" + ">";divHtml.innerHTML = sHTML + sScript;}</SCRIPT><BODY onload="insertScript();"><DIV ID="divHtml"></DIV></BODY></HTML>

But there is a problem. I need to replace the entire html </script>. Because the controls in the container are developed by ourselves, the output of key scripts and the output of html can be written separately, so whether to split it into two parts for an update, put real html in a container, and script in a container. Modify the Code as follows:

<HTML><SCRIPT>function insertScript(){var sHTML="<input type=button onclick=" + "run()" + " value='Click Me'><BR>";var sScript="<SCRIPT>";sScript = sScript + "function run(){ alert('Hello from inserted script.') }";sScript = sScript + "</SCRIPT"+">";divHtml.innerHTML = sHTML;divScript.innerHTML = sScript;}</SCRIPT><BODY onload="insertScript();"><DIV ID="divHtml"></DIV><DIV ID="divScript"></DIV></BODY></HTML>

When the problem arises again, you will find that your script has been lost and has not been inserted into the divScript container.

After testing, if a script is inserted into innerHTML, it is impossible to insert the script code only. html must be included before the script, such as the input in the previous example, and cannot be placed behind the script, it must be in this format:

<Html> + <script>, not <script> or <script> +

 

Dynamic execution Script:

After the above modification, the current html and script have been correctly updated to the dom, but the methods defined in the script have not been executed.

To execute the script in the string, I first thought of using eval.

Currently, html and script are output together, so you need to separate the script code to be executed and then use eval.

First, I wrote a separation Script Function:

function AnalyzeHtml(html,start,end){var regexp=new RegExp(start+"((.|\r\n)*?)"+end,"g");var strings=html.match(regexp);var objs=new Array();var regexp2=new RegExp("(^"+start+"|"+end+"$)","g");var js;if(strings!=null){for(var i=0;i<strings.length;i++){objs[i] = strings[i].replace(regexp2,'');}var strScript = objs.join(";").replace(/\\\"/g,"\"").replace(/\\\'/g,"'");//eval(strScript);js += strScript+";"}html = null;regexp=null;strings=null;objs = null;regexp2 = null;eval(js);return js;}

Call the function returned by Callback:

Html = html. replace (/<script type = \ 'text \/javascript \ '>/g, "<script> "). replace (/<script type = \ "text \/javascript \">/g, "<script> "); // replace different script tags with the same AnalyzeHtml (html, "<script>", "</s" + "scripts> ");

I thought something was coming to an end, and a new problem came out.

The script executed through eval is run, but the script for defining classes is lost, for example:

// Loss of var a = "variable"; // loss of function run () {// TODO:} // normal operation of alert ("execution function ");

None of the scripts defining classes (such as variables, such as anonymous functions) can be added to the current window, and the script executed immediately runs correctly. It seems that the dynamic output of the script cannot be executed through eval.

After searching some articles on the Internet, a new method is obtained, which is implemented by using the mechanism of ie itself. That is, when the node is removed, ie will re-parse the html in the node and execute the relevant script if there is a script. However, the defer attribute must be set in the script. The new method is as follows:

/** Description: cross-browser setting innerHTML Method * allowed to insert HTML code contains script and style * Author: kenxu <ken@ajaxwing.com> * Date: * parameter: * el: valid DOM tree node * htmlCode: valid HTML code * tested browsers: ie5 +, firefox1.5 +, opera8.5 + */var setInnerHTML = function (el, htmlCode) {var ua = navigator. userAgent. toLowerCase (); if (ua. indexOf ('msi')> = 0 & ua. indexOf ('Opera ') <0) {htmlCode =' <div style = "display: none"> for IE </div> '+ htmlCode; htmlCode = htmlCode. replace (/<script ([^>] *)>/gi, '<script $1 defer>'); el. innerHTML = htmlCode; el. removeChild (el. firstChild);} else {var el_next = el. nextSibling; var el_parent = el. parentNode; el_parent.removeChild (el); el. innerHTML = htmlCode; if (el_next) {el_parent.insertBefore (el, el_next)} else {el_parent.appendChild (el );}}}

This method makes full use of the features of the browser, which ensures high execution efficiency and compatibility. The only drawback is that the script cannot contain document. write. Another method is as follows:

/* innerhtml.js   * Copyright Ma Bingyao <andot@ujn.edu.cn>   * Version: 1.9   * LastModified: 2006-06-04   * This library is free.  You can redistribute it and/or modify it.   * http://www.coolcode.cn/?p=117   */var global_html_pool = [];var global_script_pool = [];var global_script_src_pool = [];var global_lock_pool = [];var innerhtml_lock = null;var document_buffer = "";function set_innerHTML(obj_id, html, time) {if (innerhtml_lock == null) {innerhtml_lock = obj_id;}else if (typeof(time) == "undefined") {global_lock_pool[obj_id + "_html"] = html;window.setTimeout("set_innerHTML('" + obj_id + "', global_lock_pool['" + obj_id + "_html']);", 10);return;}else if (innerhtml_lock != obj_id) {global_lock_pool[obj_id + "_html"] = html;window.setTimeout("set_innerHTML('" + obj_id + "', global_lock_pool['" + obj_id + "_html'], " + time + ");", 10);return;}function get_script_id() {return "script_" + (new Date()).getTime().toString(36)+ Math.floor(Math.random() * 100000000).toString(36);}document_buffer = "";document.write = function (str) {document_buffer += str;}document.writeln = function (str) {document_buffer += str + "\n";}global_html_pool = [];var scripts = [];html = html.split(/<\/script>/i);for (var i = 0; i < html.length; i++) {global_html_pool[i] = html[i].replace(/<script[\s\S]*$/ig, "");scripts[i] = {text: '', src: '' };scripts[i].text = html[i].substr(global_html_pool[i].length);scripts[i].src = scripts[i].text.substr(0, scripts[i].text.indexOf('>') + 1);scripts[i].src = scripts[i].src.match(/src\s*=\s*(\"([^\"]*)\"|\'([^\']*)\'|([^\s]*)[\s>])/i);if (scripts[i].src) {if (scripts[i].src[2]) {scripts[i].src = scripts[i].src[2];}else if (scripts[i].src[3]) {scripts[i].src = scripts[i].src[3];}else if (scripts[i].src[4]) {scripts[i].src = scripts[i].src[4];}else {scripts[i].src = "";}scripts[i].text = "";}else {scripts[i].src = "";scripts[i].text = scripts[i].text.substr(scripts[i].text.indexOf('>') + 1);scripts[i].text = scripts[i].text.replace(/^\s*<\!--\s*/g, "");}}var s;if (typeof(time) == "undefined") {s = 0;}else {s = time;}var script, add_script, remove_script;for (var i = 0; i < scripts.length; i++) {var add_html = "document_buffer += global_html_pool[" + i + "];\n";add_html += "document.getElementById('" + obj_id + "').innerHTML = document_buffer;\n";script = document.createElement("script");if (scripts[i].src) {script.src = scripts[i].src;if (typeof(global_script_src_pool[script.src]) == "undefined") {global_script_src_pool[script.src] = true;s += 2000;}else {s += 10;}}else {script.text = scripts[i].text;s += 10;}script.defer = true;script.type =  "text/javascript";script.id = get_script_id();global_script_pool[script.id] = script;add_script = add_html;add_script += "document.getElementsByTagName('head').item(0)";add_script += ".appendChild(global_script_pool['" + script.id + "']);\n";window.setTimeout(add_script, s);remove_script = "document.getElementsByTagName('head').item(0)";remove_script += ".removeChild(document.getElementById('" + script.id + "'));\n";remove_script += "delete global_script_pool['" + script.id + "'];\n";window.setTimeout(remove_script, s + 10000);}var end_script = "if (document_buffer.match(/<\\/script>/i)) {\n";end_script += "set_innerHTML('" + obj_id + "', document_buffer, " + s + ");\n";end_script += "}\n";end_script += "else {\n";end_script += "document.getElementById('" + obj_id + "').innerHTML = document_buffer;\n";end_script += "innerhtml_lock = null;\n";end_script += "}";window.setTimeout(end_script, s);}

Postscript:

It took me half a day to complete this function. The process was ups and downs in the middle of the process. In this situation, I couldn't help thinking of the classic line "Qiu Xiang, it's really a few twists and turns !" ^_^ ......

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.