[#8473] use jinja tojson instead of our own
diff --git a/Allura/allura/ext/admin/templates/project_admin.html b/Allura/allura/ext/admin/templates/project_admin.html
index 3633fc8..fafdc26 100644
--- a/Allura/allura/ext/admin/templates/project_admin.html
+++ b/Allura/allura/ext/admin/templates/project_admin.html
@@ -121,7 +121,7 @@
 {% block extra_js %}
 <script>
 $(function() {
-    var tour = {{ h.escape_json(tour)|safe }};
+    var tour = {{ tour|tojson }};
     tour.onError = function() {
         var step = hopscotch.getCurrStepNum();
         console.warn('Error on tour step #', step, tour.steps[step]);
diff --git a/Allura/allura/ext/admin/templates/project_install_tool.html b/Allura/allura/ext/admin/templates/project_install_tool.html
index b3e577d..556471e 100644
--- a/Allura/allura/ext/admin/templates/project_install_tool.html
+++ b/Allura/allura/ext/admin/templates/project_install_tool.html
@@ -79,7 +79,7 @@
 
 
 <script>
-    var _existingMountPoints = {{ h.escape_json(existing_mount_points)|safe }};
+    var _existingMountPoints = {{ existing_mount_points|tojson }};
 
     $('#admin_modal_title').hide();
     var mount_point = $('#id_url_input');
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 77523e8..2efce79 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -58,7 +58,7 @@
 import formencode
 from markupsafe import Markup
 from jinja2.filters import escape, do_filesizeformat
-from jinja2.utils import pass_context
+from jinja2.utils import pass_context, htmlsafe_json_dumps
 from paste.deploy.converters import asbool, aslist, asint
 from webhelpers2 import date, text
 from webob.exc import HTTPUnauthorized
@@ -153,8 +153,10 @@
     return s
 
 
-def escape_json(data):
-    return json.dumps(data).replace('<', '\\u003C')
+def escape_json(data) -> str:
+    # Templates should use `|tojson` instead of this
+    return str(htmlsafe_json_dumps(data))  # str() to keep previous behavior of being str, not MarkupSafe
+
 
 def querystring(request, url_params):
     """
diff --git a/Allura/allura/templates/jinja_master/top_nav.html b/Allura/allura/templates/jinja_master/top_nav.html
index 980f4ef..53923c1 100644
--- a/Allura/allura/templates/jinja_master/top_nav.html
+++ b/Allura/allura/templates/jinja_master/top_nav.html
@@ -53,7 +53,7 @@
     <script>
         'use strict';
         /*global ReactDOM, React, Main, ToggleAddNewTool */
-        var _data = {{ h.escape_json(c.project.nav_data(admin_options=True, navbar_entries=navbar_entries))|safe }};
+        var _data = {{ c.project.nav_data(admin_options=True, navbar_entries=navbar_entries)|tojson }};
         $(document).ready(function () {
             $('#toggle-admin-btn').click(function () {
                 if (typeof Main === 'undefined') {
diff --git a/Allura/allura/templates_responsive/jinja_master/top_nav.html b/Allura/allura/templates_responsive/jinja_master/top_nav.html
index 0627272..36e2f21 100644
--- a/Allura/allura/templates_responsive/jinja_master/top_nav.html
+++ b/Allura/allura/templates_responsive/jinja_master/top_nav.html
@@ -53,7 +53,7 @@
     <script>
         'use strict';
         /*global ReactDOM, React, Main, ToggleAddNewTool */
-        var _data = {{ h.escape_json(c.project.nav_data(admin_options=True, navbar_entries=navbar_entries))|safe }};
+        var _data = {{ c.project.nav_data(admin_options=True, navbar_entries=navbar_entries)|tojson }};
         $(document).ready(function () {
             $('#toggle-admin-btn').click(function () {
                 if (typeof Main === 'undefined') {
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 650ba02..16408b5 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -78,7 +78,7 @@
 
 def test_escape_json():
     inputdata = {"foo": "bar</script><img src=foobar onerror=alert(1)>"}
-    outputsample = '{"foo": "bar\\u003C/script>\\u003Cimg src=foobar onerror=alert(1)>"}'
+    outputsample = '{"foo": "bar\\u003c/script\\u003e\\u003cimg src=foobar onerror=alert(1)\\u003e"}'
     outputdata = h.escape_json(inputdata)
     assert_equals(outputdata, outputsample)
 
diff --git a/ForgeTracker/forgetracker/templates/tracker_widgets/ticket_search_results.html b/ForgeTracker/forgetracker/templates/tracker_widgets/ticket_search_results.html
index f57a466..308ac57 100644
--- a/ForgeTracker/forgetracker/templates/tracker_widgets/ticket_search_results.html
+++ b/ForgeTracker/forgetracker/templates/tracker_widgets/ticket_search_results.html
@@ -129,7 +129,7 @@
   {{widget.fields['page_list'].display(limit=limit, page=page, count=count)}}
   <script type="text/javascript">
     var q="{{query and h.urlquoteplus(query) or ''}}", count={{count}}, limit={{limit}}, page={{page}}, sort="{{sort if sort else ''}}";
-    var filter = {{h.escape_json(filter or {})|safe}};
+    var filter = {{(filter or {})|tojson}};
   </script>
 </div>
 {% block wiki_extra_css %}