innerHTML resets forms; any alternatives?

Hello,

I’m eager for an answer to this issue, so I’m afraid I’ve skipped the Introductions forum. (I hope I haven’t stepped on any toes by doing so!)

My Program
I’m working on a website that uses the Devanagari writing system (i.e. देवनागरी) extensively. Realizing that not everybody can read this font, I decided to write a transliterator for my site. When the value of a ‘select’ menu changes, all of the Devanagari is replaced with another writing system (I’ll using “writing system” to avoid confusion with “script”).

The Implementation
I select all of the text in the body of the document with document.body.innerHTML and iterate through it character by character.

<html>
   <head>
      <title>Test</title>
      <script type="text/javascript" src="script.js">
      </script>
   </head>
   <body>
   
   <p>&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340;</p>

      <label>Dummy menu</label>
      <select>
         <option>Apples</option>
         <option>Broccoli</option>
         <option>Cereal</option>
      </select>   
      <label>Script:</label>
      <select onchange="Transliterate( this )">
         <option>Default</option>
         <option value="s1">Script 1</option>
         <option value="s2">Script 2</option>
      </select>
   </body>
</html>

var backup = false;
var OLD;

var writingSystem1 = new Array(
   "&#2309;", "&#2310;", "&#2311;", "&#2312;", "&#2313;", "&#2314;",
   "&#2315;", "&#2400;", "&#2319;", "&#2320;", "&#2323;", "&#2324;",
   "&#2366;", "&#2367;", "&#2368;", "&#2369;", "&#2370;", "&#2371;", "&#2372;",
   "&#2375;", "&#2376;", "&#2379;", "&#2380;", "&#2306;", "&#2307;", "&#2381;",
   "&#2325;", "&#2326;", "&#2327;", "&#2328;", "&#2329;",
   "&#2330;", "&#2331;", "&#2332;", "&#2333;", "&#2334;",
   "&#2335;", "&#2336;", "&#2337;", "&#2338;", "&#2339;",
   "&#2340;", "&#2341;", "&#2342;", "&#2343;", "&#2344;",
   "&#2346;", "&#2347;", "&#2348;", "&#2349;", "&#2350;",
   "&#2351;", "&#2352;", "&#2354;", "&#2357;",
   "&#2358;", "&#2359;", "&#2360;", "&#2361;",
   "&#2384;", "&#2365;"
);
var writingSystem2 = new Array(
   "&#3205;", "&#3206;", "&#3207;", "&#3208;", "&#3209;", "&#3210;",
   "&#3211;", "&#3296;", "&#3214;", "&#3216;", "&#3218;", "&#3220;",
   "&#3262;", "&#3263;", "&#3264;", "&#3265;", "&#3266;", "&#3267;",   "&#3268;",
   "&#3270;", "&#3272;", "&#3274;", "&#3276;", "&#3202;", "&#3203;", "&#3277;",
   "&#3221;", "&#3222;", "&#3223;", "&#3224;", "&#3225;",
   "&#3226;", "&#3227;", "&#3228;", "&#3229;", "&#3230;",
   "&#3231;", "&#3232;", "&#3233;", "&#3234;", "&#3235;",
   "&#3236;", "&#3237;", "&#3238;", "&#3239;", "&#3240;",
   "&#3242;", "&#3243;", "&#3244;", "&#3245;", "&#3246;",
   "&#3247;", "&#3248;", "&#3250;", "&#3253;",
   "&#3254;", "&#3255;", "&#3256;", "&#3257;",
   "&#3219;&#3202;", "&#3261;"
);

var toScriptTwo = {};
for (var i = 0; i < writingSystem1.length; i++) {
   toScriptTwo[writingSystem1[i]] = writingSystem2[i];
}
function setBackup() {
   backup = true;
   OLD = document.body.innerHTML;
}
function Swap(map) {
   if (!backup) setBackup();
   var newHTML = "";
   for (var i = 0, oldL; oldL = OLD[i]; i++) {
      if (map.hasOwnProperty(oldL)) {
         newHTML += map[oldL]; 
      } else {
         newHTML += oldL;
      }
   }
   return newHTML;
}
function Transliterate(elem) {
   var value = elem.options[elem.selectedIndex].value;
   if (value == "s1") {
      document.body.innerHTML = Swap(toScriptTwo);
   }
   else if (backup && value == "s2") {
         document.body.innerHTML = OLD;
   }
}

The Problem
The writing system gets changed correctly; that’s not the issue. The issue is that all of the forms on the page are reset to their default value.

While looking for an answer, I came to understand that this is how innerHTML always works: all forms and fields are reset, since it does a “dumb replace” of these features and ignores their content. Many sites suggested that I use more standard DOM-related functions.

But my problem with these functions is that they focus exclusively on elements and their hierarchy, whereas I just want to iterate through the text and transliterate. More explicitly: other users seemed to have problems with creating or inserting elements, but I want to do neither, so I don’t know if a DOM-related approach is best.

Moreover, I want this function to be fast. Right now, it can transliterate 200 lines of Devanagari in about half a second.

My Question
Is there a reasonable way to (1) transliterate quickly and (2) retain all form data?

Thanks for reading!

Hm, gosh, I’m trying to think of a page that changes languages and doesn’t reset the forms… Do people change values and then decide to switch scripts? Or is it also resetting your language-selector form itself?

You can retain all of the form data by copying the elements property of each form.

The program would reset all forms, including the language select form. To fix that, I first put all of my page content in a separate div:


<html>
   <head>
   <title>Test</title>
   </head>
   <body>
      <div id="content">
         <!-- content -->
      </div>
      <div id="footer">
         <select>
            <!-- the select menu-->
         </select>
      </div>
   </body>
</html>

and then modified my Javascript to use “document.getElementById(‘content’)”. The problem, then, was that any forms in the “content” div would be reset.

Shucks, I was hoping I wouldn’t have to do that. But if I want to keep the speed of innerHTML, it seems like I don’t have much choice about it.

Thanks for your replies, you guys! I think I’ll add support for copying form data.

Why not save the form content, run the innerHTML, then restore the form content

gogo dom level 2


var treeWalker = document.createTreeWalker(
    document.firstChild,
    NodeFilter.SHOW_TEXT,
    { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
    false
);



while(treeWalker.nextNode()) {
    treeWalker.currentNode.nodeValue = translitToUpperCase(treeWalker.currentNode.nodeValue);
}


function translitToUpperCase(txt) {
    return txt.toUpperCase();
}

Seems to work, I just pasted this into the browser address bar on a few web pages


javascript:(function(){var treeWalker=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{acceptNode:function(node){return NodeFilter.FILTER_ACCEPT;}},false);while(treeWalker.nextNode()){treeWalker.currentNode.nodeValue=translitToUpperCase(treeWalker.currentNode.nodeValue);}function translitToUpperCase(txt){return txt.toUpperCase();}})()