<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -83,14 +83,16 @@ Object.extend(String.prototype, {
   escapeHTML: function() {
     var self = arguments.callee;
     self.text.data = this;
-    return self.div.innerHTML;
+    return self.container.innerHTML;
   },
 
   unescapeHTML: function() {
     var div = new Element('div');
-    div.innerHTML = this.stripTags();
+    // Safari requires the text nested inside another element to render correctly
+    div.innerHTML = '&lt;pre&gt;' + this.stripTags() + '&lt;/pre&gt;';
+    div = div.firstChild;
     return div.childNodes[0] ? (div.childNodes.length &gt; 1 ? 
-      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : 
+      $A(div.childNodes).inject('', function(memo, node) { return memo + node.nodeValue }) : 
       div.childNodes[0].nodeValue) : '';
   },
   
@@ -211,15 +213,6 @@ Object.extend(String.prototype, {
   }
 });
 
-if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
-  escapeHTML: function() {
-    return this.replace(/&amp;/g,'&amp;amp;').replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');
-  },
-  unescapeHTML: function() {
-    return this.stripTags().replace(/&amp;amp;/g,'&amp;').replace(/&amp;lt;/g,'&lt;').replace(/&amp;gt;/g,'&gt;');
-  }
-});
-
 String.prototype.gsub.prepareReplacement = function(replacement) {
   if (Object.isFunction(replacement)) return replacement;
   var template = new Template(replacement);
@@ -229,11 +222,39 @@ String.prototype.gsub.prepareReplacement = function(replacement) {
 String.prototype.parseQuery = String.prototype.toQueryParams;
 
 Object.extend(String.prototype.escapeHTML, {
-  div:  document.createElement('div'),
+  container: document.createElement('pre'),
   text: document.createTextNode('')
 });
 
-String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
+String.prototype.escapeHTML.container.appendChild(String.prototype.escapeHTML.text);
+
+if (Prototype.Browser.IE)
+  // IE converts all newlines to carriage returns so we swap them back
+  String.prototype.unescapeHTML = String.prototype.unescapeHTML.wrap(function(proceed) {
+    return proceed().replace(/\r/g, '\n')
+  });
+
+if (Prototype.Browser.WebKit &amp;&amp; Prototype.BrowserFeatures.SelectorsAPI)
+  // Safari 3.x has issues with escaping the &quot;&gt;&quot; character
+  (function() {
+    var escapeHTML = String.prototype.escapeHTML;
+    Object.extend(
+      String.prototype.escapeHTML = escapeHTML.wrap(function(proceed) {
+        return proceed().replace(/&gt;/g, &quot;&amp;gt;&quot;)
+      }), {
+      container: escapeHTML.container,
+      text: escapeHTML.text
+    })
+  })();
+  
+if ('&amp;'.escapeHTML() !== '&amp;amp;') {
+  // Safari 2.x has issues with escaping html inside a &quot;pre&quot; element so we use the deprecated &quot;xmp&quot; element instead
+  Object.extend(String.prototype.escapeHTML, {
+    container: document.createElement('xmp'),
+    text: document.createTextNode('')
+  });
+  String.prototype.escapeHTML.container.appendChild(String.prototype.escapeHTML.text);
+}
 
 var Template = Class.create({
   initialize: function(template, pattern) {</diff>
      <filename>src/string.js</filename>
    </modified>
    <modified>
      <diff>@@ -255,9 +255,13 @@ new Test.Unit.Runner({
     
     this.assertEqual(largeTextUnescaped, largeTextEscaped.unescapeHTML());
     
+    this.assertEqual('test \xfa', 'test &amp;uacute;'.unescapeHTML());
     this.assertEqual('1\n2', '1\n2'.unescapeHTML());
     this.assertEqual('Pride &amp; Prejudice', '&lt;h1&gt;Pride &amp;amp; Prejudice&lt;/h1&gt;'.unescapeHTML());
     
+    var escapedTest = '&quot;&amp;lt;&quot; means &quot;&lt;&quot; in HTML';
+    this.assertEqual(escapedTest, escapedTest.escapeHTML().unescapeHTML());
+    
     this.benchmark(function() { largeTextEscaped.unescapeHTML() }, 1000);
     
   },</diff>
      <filename>test/unit/string_test.js</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>7a1ee73953690cc420d4887b2214bb07534f2ca3</id>
    </parent>
  </parents>
  <author>
    <name>jdalton</name>
    <email>john.david.dalton@gmail.com</email>
  </author>
  <url>http://github.com/sstephenson/prototype/commit/57a901febacfd831bdb6c9b5b95753f4d256a65b</url>
  <id>57a901febacfd831bdb6c9b5b95753f4d256a65b</id>
  <committed-date>2008-05-19T15:09:56-07:00</committed-date>
  <authored-date>2008-04-25T12:18:09-07:00</authored-date>
  <message>Fix String#escapeHTML and String#unescapeHTML (to ensure no memory leakage and more consistent output). [#47:resolved]</message>
  <tree>1b60e48b5c8e0548f3c15f130e0cb281721420e5</tree>
  <committer>
    <name>Andrew Dupont</name>
    <email>prototype@andrewdupont.net</email>
  </committer>
</commit>
