summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_resources.grd3
-rw-r--r--chrome/browser/resources/plugins.html256
-rw-r--r--chrome/browser/resources/plugins.js255
-rw-r--r--chrome/browser/resources/shared/js/jstemplate_compiled.js10
-rw-r--r--chrome/browser/resources/shared_resources.grd2
-rw-r--r--chrome/browser/ui/webui/plugins_ui.cc120
-rw-r--r--chrome/common/common_resources.grd2
-rw-r--r--chrome/third_party/jstemplate/README.chromium15
-rwxr-xr-xchrome/third_party/jstemplate/compile.py9
-rw-r--r--chrome/third_party/jstemplate/jstemplate_compiled.js13
10 files changed, 359 insertions, 326 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 67bf93f..689b212 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -61,7 +61,8 @@
<include name="IDR_NOTIFICATION_1LINE_HTML" file="resources\notification_1line.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_NOTIFICATION_2LINE_HTML" file="resources\notification_2line.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_NOTIFICATION_ICON_HTML" file="resources\notification_icon.html" type="BINDATA" />
- <include name="IDR_PLUGINS_HTML" file="resources\plugins.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_PLUGINS_HTML" file="resources\plugins.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PLUGINS_JS" file="resources\plugins.js" type="BINDATA" />
<include name="IDR_READER_OUT_OF_DATE_HTML" file="resources\reader_out_of_date.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_PRINT_PREVIEW_HTML" file="resources\print_preview.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SAFE_BROWSING_MALWARE_BLOCK" file="resources\safe_browsing_malware_block.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/resources/plugins.html b/chrome/browser/resources/plugins.html
index 07d61f7..6d4517a 100644
--- a/chrome/browser/resources/plugins.html
+++ b/chrome/browser/resources/plugins.html
@@ -2,6 +2,11 @@
<html i18n-values="dir:textdirection;">
<head>
<meta charset="utf-8">
+<!-- X-WebKit-CSP is our development name for Content-Security-Policy.
+ The 'unsafe-eval' is required for jstemplate_compiled.js.
+ TODO(tsepez) rename when Content-security-policy is done.
+-->
+<meta http-equiv="X-WebKit-CSP" content="object-src 'none'; script-src chrome://resources 'self' 'unsafe-eval'">
<title i18n-content="pluginsTitle"></title>
<style>
body {
@@ -242,230 +247,7 @@ body.showTmiMode .showInTmiMode {
button {
font-size: 104%;
}
-
</style>
-<script>
-
-/**
- * This variable structure is here to document the structure that the template
- * expects to correctly populate the page.
- */
-var pluginDataFormat = {
- 'plugins': [
- {
- 'name': 'Group Name',
- 'description': 'description',
- 'version': 'version',
- 'update_url': 'http://update/',
- 'critical': true,
- 'enabled': true,
- 'plugin_files': [
- {
- 'path': '/blahblah/blahblah/MyCrappyPlugin.plugin',
- 'name': 'MyCrappyPlugin',
- 'version': '1.2.3',
- 'description': 'My crappy plugin',
- 'mimeTypes': [
- { 'description': 'Foo Media',
- 'fileExtensions': [ 'foo' ],
- 'mimeType': 'application/x-my-foo' },
- { 'description': 'Bar Stuff',
- 'fileExtensions': [ 'bar','baz' ],
- 'mimeType': 'application/my-bar' }
- ],
- 'enabledMode': 'enabledByUser'
- },
- {
- 'path': '/tmp/MyFirst.plugin',
- 'name': 'MyFirstPlugin',
- 'version': '3.14r15926',
- 'description': 'My first plugin',
- 'mimeTypes': [
- { 'description': 'New Guy Media',
- 'fileExtensions': [ 'mfp' ],
- 'mimeType': 'application/x-my-first' }
- ],
- 'enabledMode': 'enabledByPolicy'
- },
- {
- 'path': '/foobar/baz/YourGreatPlugin.plugin',
- 'name': 'YourGreatPlugin',
- 'version': '4.5',
- 'description': 'Your great plugin',
- 'mimeTypes': [
- { 'description': 'Baz Stuff',
- 'fileExtensions': [ 'baz' ],
- 'mimeType': 'application/x-your-baz' }
- ],
- 'enabledMode': 'disabledByUser'
- },
- {
- 'path': '/foobiz/bar/HisGreatPlugin.plugin',
- 'name': 'HisGreatPlugin',
- 'version': '1.2',
- 'description': 'His great plugin',
- 'mimeTypes': [
- { 'description': 'More baz Stuff',
- 'fileExtensions': [ 'bor' ],
- 'mimeType': 'application/x-his-bor' }
- ],
- 'enabledMode': 'disabledByPolicy'
- }
- ]
- }
- ]
-};
-
-/**
- * Takes the |pluginsData| input argument which represents data about the
- * currently installed/running plugins and populates the html jstemplate with
- * that data. It expects an object structure like the above.
- * @param {Object} pluginsData Detailed info about installed plugins
- */
-function renderTemplate(pluginsData) {
- // This is the javascript code that processes the template:
- var input = new JsEvalContext(pluginsData);
- var output = document.getElementById('pluginTemplate');
- jstProcess(input, output);
-}
-
-/**
- * Asks the C++ PluginsDOMHandler to get details about the installed plugins and
- * return detailed data about the configuration. The PluginsDOMHandler should
- * reply to returnPluginsData() (below).
- */
-function requestPluginsData() {
- chrome.send('requestPluginsData', []);
- chrome.send('getShowDetails', []);
-}
-
-function loadShowDetailsFromPrefs(show_details) {
- tmiModeExpanded = show_details;
- document.getElementById('collapse').style.display =
- show_details ? 'inline' : 'none';
- document.getElementById('expand').style.display =
- show_details ? 'none' : 'inline';
-
- document.body.className =
- show_details ? 'showTmiMode' : 'hideTmiMode';
-}
-
-/**
- * Asks the C++ PluginsDOMHandler to show the terms of service (about:terms).
- */
-function showTermsOfService() {
- chrome.send('showTermsOfService', []);
-}
-
-/**
- * Called by the web_ui_ to re-populate the page with data representing the
- * current state of installed plugins.
- */
-function returnPluginsData(pluginsData){
- var bodyContainer = document.getElementById('body-container');
- var body = document.body;
-
- // Set all page content to be visible so we can measure heights.
- bodyContainer.style.visibility = 'hidden';
- body.className = '';
- var slidables = document.getElementsByClassName('showInTmiMode');
- for (var i = 0; i < slidables.length; i++)
- slidables[i].style.height = 'auto';
-
- renderTemplate(pluginsData);
-
- // Make sure the left column (with "Description:", "Location:", etc.) is the
- // same size for all plugins.
- var labels = document.getElementsByClassName('plugin-details-label');
- var maxLabelWidth = 0;
- for (var i = 0; i < labels.length; i++)
- labels[i].style.width = 'auto';
- for (var i = 0; i < labels.length; i++)
- maxLabelWidth = Math.max(maxLabelWidth, labels[i].offsetWidth);
- for (var i = 0; i < labels.length; i++)
- labels[i].style.width = maxLabelWidth + 'px';
-
- // Explicitly set the height for each element that wants to be "slid" in and
- // out when the tmiModeExpanded is toggled.
- var slidables = document.getElementsByClassName('showInTmiMode');
- for (var i = 0; i < slidables.length; i++)
- slidables[i].style.height = slidables[i].offsetHeight + 'px';
-
- // Reset visibility of page based on the current tmi mode.
- document.getElementById('collapse').style.display =
- tmiModeExpanded ? 'inline' : 'none';
- document.getElementById('expand').style.display =
- tmiModeExpanded ? 'none' : 'inline';
- bodyContainer.style.visibility = 'visible';
- body.className = tmiModeExpanded ?
- 'showTmiModeInitial' : 'hideTmiModeInitial';
-}
-
-/**
- * Handles a 'enable' or 'disable' button getting clicked.
- */
-function handleEnablePlugin(node, enable, isGroup) {
- // Tell the C++ PluginsDOMHandler to enable/disable the plugin.
- chrome.send('enablePlugin', [String(node.path), String(enable),
- String(isGroup)]);
-}
-
-// Keeps track of whether details have been made visible (expanded) or not.
-var tmiModeExpanded = false;
-
-/*
- * Toggles visibility of details.
- */
-function toggleTmiMode() {
- tmiModeExpanded = !tmiModeExpanded;
-
- document.getElementById('collapse').style.display =
- tmiModeExpanded ? 'inline' : 'none';
- document.getElementById('expand').style.display =
- tmiModeExpanded ? 'none' : 'inline';
-
- document.body.className =
- tmiModeExpanded ? 'showTmiMode' : 'hideTmiMode';
-
- chrome.send('saveShowDetailsToPrefs', [String(tmiModeExpanded)]);
-}
-
-/**
- * Determines whether a plugin's version should be displayed.
- */
-function shouldDisplayPluginVersion(plugin) {
- return !!plugin.version && plugin.version != '0';
-}
-
-/**
- * Determines whether a plugin's description should be displayed.
- */
-function shouldDisplayPluginDescription(plugin) {
- // Only display the description if it's not blank and if it's not just the
- // name, version, or combination thereof.
- return plugin.description &&
- plugin.description != plugin.name &&
- plugin.description != plugin.version &&
- plugin.description != 'Version ' + plugin.version &&
- plugin.description != plugin.name + ' ' + plugin.version;
-}
-
-/**
- * Determines whether a plugin is enabled or not.
- */
-function isPluginEnabled(plugin) {
- return plugin.enabledMode == 'enabledByUser' ||
- plugin.enabledMode == 'enabledByPolicy';
-}
-
-// Unfortunately, we don't have notifications for plugin (list) status changes
-// (yet), so in the meanwhile just update regularly.
-setInterval(requestPluginsData, 30000);
-
-// Get data and have it displayed upon loading.
-document.addEventListener('DOMContentLoaded', requestPluginsData);
-
-</script>
</head>
<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
<div id="body-container" style="visibility:hidden">
@@ -487,15 +269,14 @@ document.addEventListener('DOMContentLoaded', requestPluginsData);
jscontent="plugins.length"></span>)</span>
</td>
<td width="18">
- <img id="collapse" class="tmi-mode-image"
- style="display:none" onclick="toggleTmiMode();"
+ <img id="collapse" class="tmi-mode-image" style="display:none"
src="shared/images/minus.png">
<img id="expand" class="tmi-mode-image"
- onclick="toggleTmiMode();" src="shared/images/plus.png">
+ src="shared/images/plus.png">
</td>
<td>
<div class="tmi-mode-link">
- <a onclick="toggleTmiMode();" style="cursor: default"
+ <a id="details-link" style="cursor: default"
i18n-content="pluginsDetailsModeLink">DETAILS</a>
</div>
</td>
@@ -578,17 +359,17 @@ document.addEventListener('DOMContentLoaded', requestPluginsData);
i18n-content="pluginEnabledByPolicy">(ENABLED_BY_POLICY)</span>
<span>
<a
+ class="disable-plugin-link"
jsvalues=".path:path"
jsdisplay="enabledMode == 'enabledByUser'"
- onclick="handleEnablePlugin(this, false, false)"
- href="javascript:void(0);"
+ href="#"
i18n-content="disable"
>DISABLE</a>
<a
+ class="enable-plugin-link"
jsvalues=".path:path"
jsdisplay="enabledMode == 'disabledByUser'"
- onclick="handleEnablePlugin(this, true, false)"
- href="javascript:void(0);"
+ href="#"
i18n-content="enable"
>ENABLE</a>
<span
@@ -635,17 +416,17 @@ document.addEventListener('DOMContentLoaded', requestPluginsData);
<div class="plugin-actions">
<span>
<a
+ class="disable-group-link"
jsvalues=".path:name"
jsdisplay="enabledMode == 'enabledByUser'"
- onclick="handleEnablePlugin(this, false, true)"
- href="javascript:void(0);"
+ href="#"
i18n-content="disable"
>DISABLE</a>
<a
+ class="enable-group-link"
jsvalues=".path:name"
jsdisplay="enabledMode == 'disabledByUser'"
- onclick="handleEnablePlugin(this, true, true)"
- href="javascript:void(0);"
+ href="#"
i18n-content="enable"
>ENABLE</a>
<span
@@ -666,5 +447,10 @@ document.addEventListener('DOMContentLoaded', requestPluginsData);
</div>
</div>
</div>
+<script src="chrome://plugins/plugins.js"></script>
+<script src="chrome://plugins/strings.js"></script>
+<script src="chrome://resources/js/i18n_template.js"></script>
+<script src="chrome://resources/js/i18n_process.js"></script>
+<script src="chrome://resources/js/jstemplate_compiled.js"></script>
</body>
</html>
diff --git a/chrome/browser/resources/plugins.js b/chrome/browser/resources/plugins.js
new file mode 100644
index 0000000..3851192
--- /dev/null
+++ b/chrome/browser/resources/plugins.js
@@ -0,0 +1,255 @@
+
+/**
+ * This variable structure is here to document the structure that the template
+ * expects to correctly populate the page.
+ */
+var pluginDataFormat = {
+ 'plugins': [
+ {
+ 'name': 'Group Name',
+ 'description': 'description',
+ 'version': 'version',
+ 'update_url': 'http://update/',
+ 'critical': true,
+ 'enabled': true,
+ 'plugin_files': [
+ {
+ 'path': '/blahblah/blahblah/MyCrappyPlugin.plugin',
+ 'name': 'MyCrappyPlugin',
+ 'version': '1.2.3',
+ 'description': 'My crappy plugin',
+ 'mimeTypes': [
+ { 'description': 'Foo Media',
+ 'fileExtensions': [ 'foo' ],
+ 'mimeType': 'application/x-my-foo' },
+ { 'description': 'Bar Stuff',
+ 'fileExtensions': [ 'bar','baz' ],
+ 'mimeType': 'application/my-bar' }
+ ],
+ 'enabledMode': 'enabledByUser'
+ },
+ {
+ 'path': '/tmp/MyFirst.plugin',
+ 'name': 'MyFirstPlugin',
+ 'version': '3.14r15926',
+ 'description': 'My first plugin',
+ 'mimeTypes': [
+ { 'description': 'New Guy Media',
+ 'fileExtensions': [ 'mfp' ],
+ 'mimeType': 'application/x-my-first' }
+ ],
+ 'enabledMode': 'enabledByPolicy'
+ },
+ {
+ 'path': '/foobar/baz/YourGreatPlugin.plugin',
+ 'name': 'YourGreatPlugin',
+ 'version': '4.5',
+ 'description': 'Your great plugin',
+ 'mimeTypes': [
+ { 'description': 'Baz Stuff',
+ 'fileExtensions': [ 'baz' ],
+ 'mimeType': 'application/x-your-baz' }
+ ],
+ 'enabledMode': 'disabledByUser'
+ },
+ {
+ 'path': '/foobiz/bar/HisGreatPlugin.plugin',
+ 'name': 'HisGreatPlugin',
+ 'version': '1.2',
+ 'description': 'His great plugin',
+ 'mimeTypes': [
+ { 'description': 'More baz Stuff',
+ 'fileExtensions': [ 'bor' ],
+ 'mimeType': 'application/x-his-bor' }
+ ],
+ 'enabledMode': 'disabledByPolicy'
+ }
+ ]
+ }
+ ]
+};
+
+/**
+ * Takes the |pluginsData| input argument which represents data about the
+ * currently installed/running plugins and populates the html jstemplate with
+ * that data. It expects an object structure like the above.
+ * @param {Object} pluginsData Detailed info about installed plugins
+ */
+function renderTemplate(pluginsData) {
+ // This is the javascript code that processes the template:
+ var input = new JsEvalContext(pluginsData);
+ var output = document.getElementById('pluginTemplate');
+ jstProcess(input, output);
+}
+
+/**
+ * Asks the C++ PluginsDOMHandler to get details about the installed plugins and
+ * return detailed data about the configuration. The PluginsDOMHandler should
+ * reply to returnPluginsData() (below).
+ */
+function requestPluginsData() {
+ chrome.send('requestPluginsData', []);
+ chrome.send('getShowDetails', []);
+}
+
+function loadShowDetailsFromPrefs(show_details) {
+ tmiModeExpanded = show_details;
+ document.getElementById('collapse').style.display =
+ show_details ? 'inline' : 'none';
+ document.getElementById('expand').style.display =
+ show_details ? 'none' : 'inline';
+
+ document.body.className =
+ show_details ? 'showTmiMode' : 'hideTmiMode';
+}
+
+/**
+ * Asks the C++ PluginsDOMHandler to show the terms of service (about:terms).
+ */
+function showTermsOfService() {
+ chrome.send('showTermsOfService', []);
+}
+
+/**
+ * Called by the web_ui_ to re-populate the page with data representing the
+ * current state of installed plugins.
+ */
+function returnPluginsData(pluginsData){
+ var bodyContainer = document.getElementById('body-container');
+ var body = document.body;
+
+ // Set all page content to be visible so we can measure heights.
+ bodyContainer.style.visibility = 'hidden';
+ body.className = '';
+ var slidables = document.getElementsByClassName('showInTmiMode');
+ for (var i = 0; i < slidables.length; i++)
+ slidables[i].style.height = 'auto';
+
+ renderTemplate(pluginsData);
+
+ // Add handlers to dynamically created HTML elements.
+ var links = document.getElementsByClassName('disable-plugin-link');
+ for (var i = 0; i < links.length; ++i) {
+ links[i].onclick = function () {
+ handleEnablePlugin(this, false, false);
+ return false;
+ };
+ }
+ links = document.getElementsByClassName('enable-plugin-link');
+ for (var i = 0; i < links.length; ++i) {
+ links[i].onclick = function () {
+ handleEnablePlugin(this, true, false);
+ return false;
+ };
+ }
+ links = document.getElementsByClassName('disable-group-link');
+ for (var i = 0; i < links.length; ++i) {
+ links[i].onclick = function () {
+ handleEnablePlugin(this, false, true);
+ return false;
+ };
+ }
+ links = document.getElementsByClassName('enable-group-link');
+ for (var i = 0; i < links.length; ++i) {
+ links[i].onclick = function () {
+ handleEnablePlugin(this, true, true);
+ return false;
+ };
+ }
+
+ // Make sure the left column (with "Description:", "Location:", etc.) is the
+ // same size for all plugins.
+ var labels = document.getElementsByClassName('plugin-details-label');
+ var maxLabelWidth = 0;
+ for (var i = 0; i < labels.length; i++)
+ labels[i].style.width = 'auto';
+ for (var i = 0; i < labels.length; i++)
+ maxLabelWidth = Math.max(maxLabelWidth, labels[i].offsetWidth);
+ for (var i = 0; i < labels.length; i++)
+ labels[i].style.width = maxLabelWidth + 'px';
+
+ // Explicitly set the height for each element that wants to be "slid" in and
+ // out when the tmiModeExpanded is toggled.
+ var slidables = document.getElementsByClassName('showInTmiMode');
+ for (var i = 0; i < slidables.length; i++)
+ slidables[i].style.height = slidables[i].offsetHeight + 'px';
+
+ // Reset visibility of page based on the current tmi mode.
+ document.getElementById('collapse').style.display =
+ tmiModeExpanded ? 'inline' : 'none';
+ document.getElementById('expand').style.display =
+ tmiModeExpanded ? 'none' : 'inline';
+ bodyContainer.style.visibility = 'visible';
+ body.className = tmiModeExpanded ?
+ 'showTmiModeInitial' : 'hideTmiModeInitial';
+}
+
+/**
+ * Handles a 'enable' or 'disable' button getting clicked.
+ */
+function handleEnablePlugin(node, enable, isGroup) {
+ // Tell the C++ PluginsDOMHandler to enable/disable the plugin.
+ chrome.send('enablePlugin', [String(node.path), String(enable),
+ String(isGroup)]);
+}
+
+// Keeps track of whether details have been made visible (expanded) or not.
+var tmiModeExpanded = false;
+
+/*
+ * Toggles visibility of details.
+ */
+function toggleTmiMode() {
+ tmiModeExpanded = !tmiModeExpanded;
+
+ document.getElementById('collapse').style.display =
+ tmiModeExpanded ? 'inline' : 'none';
+ document.getElementById('expand').style.display =
+ tmiModeExpanded ? 'none' : 'inline';
+
+ document.body.className =
+ tmiModeExpanded ? 'showTmiMode' : 'hideTmiMode';
+
+ chrome.send('saveShowDetailsToPrefs', [String(tmiModeExpanded)]);
+}
+
+/**
+ * Determines whether a plugin's version should be displayed.
+ */
+function shouldDisplayPluginVersion(plugin) {
+ return !!plugin.version && plugin.version != '0';
+}
+
+/**
+ * Determines whether a plugin's description should be displayed.
+ */
+function shouldDisplayPluginDescription(plugin) {
+ // Only display the description if it's not blank and if it's not just the
+ // name, version, or combination thereof.
+ return plugin.description &&
+ plugin.description != plugin.name &&
+ plugin.description != plugin.version &&
+ plugin.description != 'Version ' + plugin.version &&
+ plugin.description != plugin.name + ' ' + plugin.version;
+}
+
+/**
+ * Determines whether a plugin is enabled or not.
+ */
+function isPluginEnabled(plugin) {
+ return plugin.enabledMode == 'enabledByUser' ||
+ plugin.enabledMode == 'enabledByPolicy';
+}
+
+// Unfortunately, we don't have notifications for plugin (list) status changes
+// (yet), so in the meanwhile just update regularly.
+setInterval(requestPluginsData, 30000);
+
+// Get data and have it displayed upon loading.
+document.addEventListener('DOMContentLoaded', requestPluginsData);
+
+// Add handlers to static HTML elements.
+document.getElementById('collapse').onclick = toggleTmiMode;
+document.getElementById('expand').onclick = toggleTmiMode;
+document.getElementById('details-link').onclick = toggleTmiMode;
+
diff --git a/chrome/browser/resources/shared/js/jstemplate_compiled.js b/chrome/browser/resources/shared/js/jstemplate_compiled.js
new file mode 100644
index 0000000..d503e90
--- /dev/null
+++ b/chrome/browser/resources/shared/js/jstemplate_compiled.js
@@ -0,0 +1,10 @@
+(function(){var i=null;function k(){return Function.prototype.call.apply(Array.prototype.slice,arguments)}function l(a,b){var c=k(arguments,2);return function(){return b.apply(a,c)}}function m(a,b){var c=new n(b);for(c.f=[a];c.f.length;){var e=c,d=c.f.shift();e.g(d);for(d=d.firstChild;d;d=d.nextSibling)d.nodeType==1&&e.f.push(d)}}function n(a){this.g=a}function o(a){a.style.display=""}function p(a){a.style.display="none"};var q=":",r=/\s*;\s*/;function s(){this.i.apply(this,arguments)}s.prototype.i=function(a,b){if(!this.a)this.a={};if(b){var c=this.a,e=b.a,d;for(d in e)c[d]=e[d]}else for(c in d=this.a,e=t,e)d[c]=e[c];this.a.$this=a;this.a.$context=this;this.d=typeof a!="undefined"&&a!=i?a:"";if(!b)this.a.$top=this.d};var t={$default:i},u=[];function v(a){for(var b in a.a)delete a.a[b];a.d=i;u.push(a)}function w(a,b,c){try{return b.call(c,a.a,a.d)}catch(e){return t.$default}}
+function x(a,b,c,e){if(u.length>0){var d=u.pop();s.call(d,b,a);a=d}else a=new s(b,a);a.a.$index=c;a.a.$count=e;return a}var y="a_",z="b_",A="with (a_) with (b_) return ",D={};function E(a){if(!D[a])try{D[a]=new Function(y,z,A+a)}catch(b){}return D[a]}function F(a){for(var b=[],a=a.split(r),c=0,e=a.length;c<e;++c){var d=a[c].indexOf(q);if(!(d<0)){var f;f=a[c].substr(0,d).replace(/^\s+/,"").replace(/\s+$/,"");d=E(a[c].substr(d+1));b.push(f,d)}}return b};var G="jsinstance",H="jsts",I="*",J="div",K="id";function L(){}var M=0,N={0:{}},P={},Q={},R=[];function S(a){a.__jstcache||m(a,function(a){T(a)})}var U=[["jsselect",E],["jsdisplay",E],["jsvalues",F],["jsvars",F],["jseval",function(a){for(var b=[],a=a.split(r),c=0,e=a.length;c<e;++c)if(a[c]){var d=E(a[c]);b.push(d)}return b}],["transclude",function(a){return a}],["jscontent",E],["jsskip",E]];
+function T(a){if(a.__jstcache)return a.__jstcache;var b=a.getAttribute("jstcache");if(b!=i)return a.__jstcache=N[b];for(var b=R.length=0,c=U.length;b<c;++b){var e=U[b][0],d=a.getAttribute(e);Q[e]=d;d!=i&&R.push(e+"="+d)}if(R.length==0)return a.setAttribute("jstcache","0"),a.__jstcache=N[0];var f=R.join("&");if(b=P[f])return a.setAttribute("jstcache",b),a.__jstcache=N[b];for(var h={},b=0,c=U.length;b<c;++b){var d=U[b],e=d[0],g=d[1],d=Q[e];d!=i&&(h[e]=g(d))}b=""+ ++M;a.setAttribute("jstcache",b);N[b]=
+h;P[f]=b;return a.__jstcache=h}function V(a,b){a.h.push(b);a.k.push(0)}function W(a){return a.c.length?a.c.pop():[]}
+L.prototype.e=function(a,b){var c=X(b),e=c.transclude;if(e)(c=Y(e))?(b.parentNode.replaceChild(c,b),e=W(this),e.push(this.e,a,c),V(this,e)):b.parentNode.removeChild(b);else if(c=c.jsselect){var c=w(a,c,b),d=b.getAttribute(G),f=!1;d&&(d.charAt(0)==I?(d=parseInt(d.substr(1),10),f=!0):d=parseInt(d,10));var h=c!=i&&typeof c=="object"&&typeof c.length=="number",e=h?c.length:1,g=h&&e==0;if(h)if(g)d?b.parentNode.removeChild(b):(b.setAttribute(G,"*0"),p(b));else if(o(b),d===i||d===""||f&&d<e-1){f=W(this);
+d=d||0;for(h=e-1;d<h;++d){var j=b.cloneNode(!0);b.parentNode.insertBefore(j,b);Z(j,c,d);g=x(a,c[d],d,e);f.push(this.b,g,j,v,g,i)}Z(b,c,d);g=x(a,c[d],d,e);f.push(this.b,g,b,v,g,i);V(this,f)}else d<e?(f=c[d],Z(b,c,d),g=x(a,f,d,e),f=W(this),f.push(this.b,g,b,v,g,i),V(this,f)):b.parentNode.removeChild(b);else c==i?p(b):(o(b),g=x(a,c,0,1),f=W(this),f.push(this.b,g,b,v,g,i),V(this,f))}else this.b(a,b)};
+L.prototype.b=function(a,b){var c=X(b),e=c.jsdisplay;if(e){if(!w(a,e,b)){p(b);return}o(b)}if(e=c.jsvars)for(var d=0,f=e.length;d<f;d+=2){var h=e[d],g=w(a,e[d+1],b);a.a[h]=g}if(e=c.jsvalues){d=0;for(f=e.length;d<f;d+=2)if(g=e[d],h=w(a,e[d+1],b),g.charAt(0)=="$")a.a[g]=h;else if(g.charAt(0)=="."){for(var g=g.substr(1).split("."),j=b,O=g.length,B=0,$=O-1;B<$;++B){var C=g[B];j[C]||(j[C]={});j=j[C]}j[g[O-1]]=h}else g&&(typeof h=="boolean"?h?b.setAttribute(g,g):b.removeAttribute(g):b.setAttribute(g,""+
+h))}if(e=c.jseval){d=0;for(f=e.length;d<f;++d)w(a,e[d],b)}e=c.jsskip;if(!e||!w(a,e,b))if(c=c.jscontent){if(c=""+w(a,c,b),b.innerHTML!=c){for(;b.firstChild;)e=b.firstChild,e.parentNode.removeChild(e);b.appendChild(this.j.createTextNode(c))}}else{c=W(this);for(e=b.firstChild;e;e=e.nextSibling)e.nodeType==1&&c.push(this.e,a,e);c.length&&V(this,c)}};function X(a){if(a.__jstcache)return a.__jstcache;var b=a.getAttribute("jstcache");if(b)return a.__jstcache=N[b];return T(a)}
+function Y(a,b){var c=document;if(b){var e=c.getElementById(a);if(!e){var e=b(),d=H,f=c.getElementById(d);if(!f)f=c.createElement(J),f.id=d,p(f),f.style.position="absolute",c.body.appendChild(f);d=c.createElement(J);f.appendChild(d);d.innerHTML=e;e=c.getElementById(a)}c=e}else c=c.getElementById(a);return c?(S(c),c=c.cloneNode(!0),c.removeAttribute(K),c):i}function Z(a,b,c){c==b.length-1?a.setAttribute(G,I+c):a.setAttribute(G,""+c)};window.jstGetTemplate=Y;window.JsEvalContext=s;window.jstProcess=function(a,b){var c=new L;S(b);c.j=b?b.nodeType==9?b:b.ownerDocument||document:document;var e=l(c,c.e,a,b),d=c.h=[],f=c.k=[];c.c=[];e();for(var h,g,j;d.length;)h=d[d.length-1],e=f[f.length-1],e>=h.length?(e=c,g=d.pop(),g.length=0,e.c.push(g),f.pop()):(g=h[e++],j=h[e++],h=h[e++],f[f.length-1]=e,g.call(c,j,h))};
+})() \ No newline at end of file
diff --git a/chrome/browser/resources/shared_resources.grd b/chrome/browser/resources/shared_resources.grd
index a66ece9..3cf1dfd 100644
--- a/chrome/browser/resources/shared_resources.grd
+++ b/chrome/browser/resources/shared_resources.grd
@@ -110,6 +110,8 @@ without changes to the corresponding grd file. paaaae -->
file="shared/js/i18n_process.js" type="BINDATA" />
<include name="IDR_SHARED_JS_I18N_TEMPLATE"
file="shared/js/i18n_template.js" type="BINDATA" />
+ <include name="IDR_SHARED_JS_JSTEMPLATE_COMPILED"
+ file="shared/js/jstemplate_compiled.js" type="BINDATA" />
<include name="IDR_SHARED_JS_LOCAL_STRINGS"
file="shared/js/local_strings.js" type="BINDATA" />
<include name="IDR_SHARED_JS_MEDIA_COMMON"
diff --git a/chrome/browser/ui/webui/plugins_ui.cc b/chrome/browser/ui/webui/plugins_ui.cc
index 7672fd4..8fa1446 100644
--- a/chrome/browser/ui/webui/plugins_ui.cc
+++ b/chrome/browser/ui/webui/plugins_ui.cc
@@ -20,9 +20,9 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
@@ -31,31 +31,30 @@
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/plugins/npapi/plugin_list.h"
+static const char kStringsJsFile[] = "strings.js";
+static const char kPluginsJsFile[] = "plugins.js";
+
namespace {
///////////////////////////////////////////////////////////////////////////////
//
-// PluginsHTMLSource
+// PluginsUIHTMLSource
//
///////////////////////////////////////////////////////////////////////////////
-class PluginsUIHTMLSource : public ChromeURLDataManager::DataSource {
+class PluginsUIHTMLSource : public ChromeWebUIDataSource {
public:
- PluginsUIHTMLSource()
- : DataSource(chrome::kChromeUIPluginsHost, MessageLoop::current()) {}
+ PluginsUIHTMLSource();
// Called when the network layer has requested a resource underneath
// the path we registered.
virtual void StartDataRequest(const std::string& path,
bool is_incognito,
int request_id);
- virtual std::string GetMimeType(const std::string&) const {
- return "text/html";
- }
+ virtual std::string GetMimeType(const std::string&) const;
private:
~PluginsUIHTMLSource() {}
@@ -63,67 +62,54 @@ class PluginsUIHTMLSource : public ChromeURLDataManager::DataSource {
DISALLOW_COPY_AND_ASSIGN(PluginsUIHTMLSource);
};
+PluginsUIHTMLSource::PluginsUIHTMLSource()
+ : ChromeWebUIDataSource(chrome::kChromeUIPluginsHost) {
+ AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE);
+ AddLocalizedString("pluginsDetailsModeLink",
+ IDS_PLUGINS_DETAILS_MODE_LINK);
+ AddLocalizedString("pluginsNoneInstalled", IDS_PLUGINS_NONE_INSTALLED);
+ AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN);
+ AddLocalizedString("pluginDisabledByPolicy",
+ IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN);
+ AddLocalizedString("pluginCannotBeEnabledDueToPolicy",
+ IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY);
+ AddLocalizedString("pluginEnabledByPolicy",
+ IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN);
+ AddLocalizedString("pluginCannotBeDisabledDueToPolicy",
+ IDS_PLUGINS_CANNOT_DISABLE_DUE_TO_POLICY);
+ AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD);
+ AddLocalizedString("pluginName", IDS_PLUGINS_NAME);
+ AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION);
+ AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION);
+ AddLocalizedString("pluginPath", IDS_PLUGINS_PATH);
+ AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES);
+ AddLocalizedString("pluginMimeTypesMimeType",
+ IDS_PLUGINS_MIME_TYPES_MIME_TYPE);
+ AddLocalizedString("pluginMimeTypesDescription",
+ IDS_PLUGINS_MIME_TYPES_DESCRIPTION);
+ AddLocalizedString("pluginMimeTypesFileExtensions",
+ IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS);
+ AddLocalizedString("disable", IDS_PLUGINS_DISABLE);
+ AddLocalizedString("enable", IDS_PLUGINS_ENABLE);
+ AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS);
+}
+
void PluginsUIHTMLSource::StartDataRequest(const std::string& path,
bool is_incognito,
int request_id) {
- // Strings used in the JsTemplate file.
- DictionaryValue localized_strings;
- localized_strings.SetString("pluginsTitle",
- l10n_util::GetStringUTF16(IDS_PLUGINS_TITLE));
- localized_strings.SetString("pluginsDetailsModeLink",
- l10n_util::GetStringUTF16(IDS_PLUGINS_DETAILS_MODE_LINK));
- localized_strings.SetString("pluginsNoneInstalled",
- l10n_util::GetStringUTF16(IDS_PLUGINS_NONE_INSTALLED));
- localized_strings.SetString("pluginDisabled",
- l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN));
- localized_strings.SetString("pluginDisabledByPolicy",
- l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN));
- localized_strings.SetString("pluginCannotBeEnabledDueToPolicy",
- l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY));
- localized_strings.SetString("pluginEnabledByPolicy",
- l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN));
- localized_strings.SetString("pluginCannotBeDisabledDueToPolicy",
- l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_DISABLE_DUE_TO_POLICY));
- localized_strings.SetString("pluginDownload",
- l10n_util::GetStringUTF16(IDS_PLUGINS_DOWNLOAD));
- localized_strings.SetString("pluginName",
- l10n_util::GetStringUTF16(IDS_PLUGINS_NAME));
- localized_strings.SetString("pluginVersion",
- l10n_util::GetStringUTF16(IDS_PLUGINS_VERSION));
- localized_strings.SetString("pluginDescription",
- l10n_util::GetStringUTF16(IDS_PLUGINS_DESCRIPTION));
- localized_strings.SetString("pluginPath",
- l10n_util::GetStringUTF16(IDS_PLUGINS_PATH));
- localized_strings.SetString("pluginMimeTypes",
- l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES));
- localized_strings.SetString("pluginMimeTypesMimeType",
- l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_MIME_TYPE));
- localized_strings.SetString("pluginMimeTypesDescription",
- l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_DESCRIPTION));
- localized_strings.SetString("pluginMimeTypesFileExtensions",
- l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS));
- localized_strings.SetString("disable",
- l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLE));
- localized_strings.SetString("enable",
- l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLE));
- localized_strings.SetString("noPlugins",
- l10n_util::GetStringUTF16(IDS_PLUGINS_NO_PLUGINS));
-
- ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
-
- static const base::StringPiece plugins_html(
- ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PLUGINS_HTML));
- std::string full_html(plugins_html.data(), plugins_html.size());
- jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
- jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
- jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
- jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
-
- scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
- html_bytes->data.resize(full_html.size());
- std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
-
- SendResponse(request_id, html_bytes);
+ if (path == kStringsJsFile) {
+ SendLocalizedStringsAsJSON(request_id);
+ } else {
+ int idr = (path == kPluginsJsFile) ? IDR_PLUGINS_JS : IDR_PLUGINS_HTML;
+ SendFromResourceBundle(request_id, idr);
+ }
+}
+
+std::string PluginsUIHTMLSource::GetMimeType(const std::string& path) const {
+ if (path == kStringsJsFile || path == kPluginsJsFile)
+ return "application/javascript";
+
+ return "text/html";
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd
index a90b009..efc8179 100644
--- a/chrome/common/common_resources.grd
+++ b/chrome/common/common_resources.grd
@@ -12,7 +12,7 @@
<include name="IDR_EXTENSION_API_JSON" file="extensions\api\extension_api.json" type="BINDATA" />
<include name="IDR_I18N_PROCESS_JS" file="..\browser\resources\shared\js\i18n_process.js" type="BINDATA" />
<include name="IDR_I18N_TEMPLATE_JS" file="..\browser\resources\shared\js\i18n_template.js" type="BINDATA" />
- <include name="IDR_JSTEMPLATE_JS" file="..\third_party\jstemplate\jstemplate_compiled.js" type="BINDATA" />
+ <include name="IDR_JSTEMPLATE_JS" file="..\browser\resources\shared\js\jstemplate_compiled.js" type="BINDATA" />
<include name="IDR_WEB_APP_SCHEMA" file="web_app_schema.json" type="BINDATA" />
</includes>
</release>
diff --git a/chrome/third_party/jstemplate/README.chromium b/chrome/third_party/jstemplate/README.chromium
index 153d6a6..439ac77 100644
--- a/chrome/third_party/jstemplate/README.chromium
+++ b/chrome/third_party/jstemplate/README.chromium
@@ -10,8 +10,15 @@ output with an incremental change to the original input data."
Uncalled functions have been removed from util.js to make the resulting
javascript smaller.
-compile.py is a simple program used to generate the single compiled
-jsfile.
+compile.py is a simple program used to generate the single compiled jsfile.
+
+NOTE: output is now simply written to stdout so as to allow you to redirect
+it to a location required by the shared resource bundle.
+
+See IDR_SHARED_JS_JSTEMPLATE_COMPILED's file attribute in shared_resources.grd
+to determine the correct location for the output.
+
+The jstemplate_compiled.js file which formerly resided in this directory is
+no longer used.
+
-jstemplate_compiled.js is the output after passing the code through
-compile.sh.
diff --git a/chrome/third_party/jstemplate/compile.py b/chrome/third_party/jstemplate/compile.py
index 3d16d96..ddfc4fe 100755
--- a/chrome/third_party/jstemplate/compile.py
+++ b/chrome/third_party/jstemplate/compile.py
@@ -4,13 +4,14 @@
# found in the LICENSE file.
# A python script that combines the javascript files needed by jstemplate into
-# a single file.
+# a single file. Writes to standard output; you are responsible for putting
+# the file into the tree where it belongs.
import httplib
+import sys
import urllib
srcs ="util.js jsevalcontext.js jstemplate.js exports.js".split()
-out = "jstemplate_compiled.js"
# Wrap the output in an anonymous function to prevent poluting the global
# namespace.
@@ -32,7 +33,5 @@ headers = {'Content-type': 'application/x-www-form-urlencoded'}
conn = httplib.HTTPConnection('closure-compiler.appspot.com')
conn.request('POST', '/compile', params, headers)
response = conn.getresponse()
-out_file = file(out, 'w')
-out_file.write(output_wrapper % response.read())
-out_file.close()
+sys.stdout.write(output_wrapper % response.read())
conn.close()
diff --git a/chrome/third_party/jstemplate/jstemplate_compiled.js b/chrome/third_party/jstemplate/jstemplate_compiled.js
deleted file mode 100644
index afe2769..0000000
--- a/chrome/third_party/jstemplate/jstemplate_compiled.js
+++ /dev/null
@@ -1,13 +0,0 @@
-(function(){function j(a,b){for(var c in b)a[c]=b[c]}function l(){return Function.prototype.call.apply(Array.prototype.slice,arguments)}function m(a,b){var c=l(arguments,2);return function(){return b.apply(a,c)}}var n=9;function o(a,b){b=new p(b);for(b.f=[a];b.f.length;){a=b.f.shift();b.g(a);for(a=a.firstChild;a;a=a.nextSibling)a.nodeType==1&&b.f.push(a)}}function p(a){this.g=a}function q(a,b,c){a.setAttribute(b,c)}function r(a,b){a.removeAttribute(b)}function s(a){a.style.display=""}
-function t(a){a.style.display="none"};var u=":",v=/\s*;\s*/;function w(){this.i.apply(this,arguments)}w.prototype.i=function(a,b){var c=this;if(!c.a)c.a={};b?j(c.a,b.a):j(c.a,x);c.a.$this=a;c.a.$context=c;c.d=typeof a!="undefined"&&a!=null?a:"";if(!b)c.a.$top=c.d};var x={};(function(a,b){x[a]=b})("$default",null);var y=[];function z(a){for(var b in a.a)delete a.a[b];a.d=null;y.push(a)}function A(a,b,c){try{return b.call(c,a.a,a.d)}catch(e){return x.$default}}
-function B(a,b,c,e){if(y.length>0){var d=y.pop();w.call(d,b,a);a=d}else a=new w(b,a);a.a.$index=c;a.a.$count=e;return a}var C="a_",E="b_",F="with (a_) with (b_) return ",G={};function H(a){if(!G[a])try{G[a]=new Function(C,E,F+a)}catch(b){}return G[a]}function I(a){return a}function J(a){var b=[];a=a.split(v);for(var c=0,e=a.length;c<e;++c){var d=a[c].indexOf(u);if(!(d<0)){var f;f=a[c].substr(0,d).replace(/^\s+/,"").replace(/\s+$/,"");d=H(a[c].substr(d+1));b.push(f,d)}}return b}
-function K(a){var b=[];a=a.split(v);for(var c=0,e=a.length;c<e;++c)if(a[c]){var d=H(a[c]);b.push(d)}return b};var L="jsinstance",aa="jsts",M="*",N="div",ba="id";function ca(a,b){var c=new O;P(b);c.j=b?b.nodeType==n?b:b.ownerDocument||document:document;var e=m(c,c.e,a,b);a=c.h=[];b=c.k=[];c.c=[];e();for(var d,f,g;a.length;){d=a[a.length-1];e=b[b.length-1];if(e>=d.length){e=a.pop();e.length=0;c.c.push(e);b.pop()}else{f=d[e++];g=d[e++];d=d[e++];b[b.length-1]=e;f.call(c,g,d)}}}function O(){}var da=0,Q={};Q[0]={};var R={},S={},T=[];function P(a){a.__jstcache||o(a,function(b){U(b)})}
-var V=[["jsselect",H],["jsdisplay",H],["jsvalues",J],["jsvars",J],["jseval",K],["transclude",I],["jscontent",H],["jsskip",H]];
-function U(a){if(a.__jstcache)return a.__jstcache;var b=a.getAttribute("jstcache");if(b!=null)return a.__jstcache=Q[b];b=T.length=0;for(var c=V.length;b<c;++b){var e=V[b][0],d=a.getAttribute(e);S[e]=d;d!=null&&T.push(e+"="+d)}if(T.length==0){a.setAttribute("jstcache","0");return a.__jstcache=Q[0]}var f=T.join("&");if(b=R[f]){a.setAttribute("jstcache",b);return a.__jstcache=Q[b]}var g={};b=0;for(c=V.length;b<c;++b){d=V[b];e=d[0];var i=d[1];d=S[e];if(d!=null)g[e]=i(d)}b=""+ ++da;a.setAttribute("jstcache",
-b);Q[b]=g;R[f]=b;return a.__jstcache=g}function W(a,b){a.h.push(b);a.k.push(0)}function X(a){return a.c.length?a.c.pop():[]}O.prototype.e=function(a,b){var c=this,e=Y(c,b),d=e.transclude;if(d)if(e=Z(d)){b.parentNode.replaceChild(e,b);b=X(c);b.push(c.e,a,e);W(c,b)}else b.parentNode.removeChild(b);else(e=e.jsselect)?ea(c,a,b,e):c.b(a,b)};
-O.prototype.b=function(a,b){var c=this,e=Y(c,b),d=e.jsdisplay;if(d){if(!A(a,d,b)){t(b);return}s(b)}(d=e.jsvars)&&fa(c,a,b,d);(d=e.jsvalues)&&ga(c,a,b,d);if(d=e.jseval)for(var f=0,g=d.length;f<g;++f)A(a,d[f],b);if(d=e.jsskip)if(A(a,d,b))return;if(e=e.jscontent){a=""+A(a,e,b);if(b.innerHTML!=a){for(;b.firstChild;)b.firstChild.parentNode.removeChild(b.firstChild);c=c.j.createTextNode(a);b.appendChild(c)}}else{e=X(c);for(b=b.firstChild;b;b=b.nextSibling)b.nodeType==1&&e.push(c.e,a,b);e.length&&W(c,e)}};
-function ea(a,b,c,e){e=A(b,e,c);var d=c.getAttribute(L),f=false;if(d)if(d.charAt(0)==M){var g=d.substr(1);d=parseInt(g,10);f=true}else d=parseInt(d,10);var i=e!=null&&typeof e=="object"&&typeof e.length=="number";g=i?e.length:1;var h=i&&g==0;if(i)if(h)if(d)c.parentNode.removeChild(c);else{c.setAttribute(L,"*0");t(c)}else{s(c);if(d===null||d===""||f&&d<g-1){f=X(a);d=d||0;for(i=g-1;d<i;++d){var k=c.cloneNode(true);c.parentNode.insertBefore(k,c);$(k,e,d);h=B(b,e[d],d,g);f.push(a.b,h,k,z,h,null)}$(c,
-e,d);h=B(b,e[d],d,g);f.push(a.b,h,c,z,h,null);W(a,f)}else if(d<g){f=e[d];$(c,e,d);h=B(b,f,d,g);f=X(a);f.push(a.b,h,c,z,h,null);W(a,f)}else c.parentNode.removeChild(c)}else if(e==null)t(c);else{s(c);h=B(b,e,0,1);f=X(a);f.push(a.b,h,c,z,h,null);W(a,f)}}function fa(a,b,c,e){a=0;for(var d=e.length;a<d;a+=2){var f=e[a],g=A(b,e[a+1],c);b.a[f]=g}}
-function ga(a,b,c,e){a=0;for(var d=e.length;a<d;a+=2){var f=e[a],g=A(b,e[a+1],c);if(f.charAt(0)=="$")b.a[f]=g;else if(f.charAt(0)=="."){f=f.substr(1).split(".");for(var i=c,h=f.length,k=0,ha=h-1;k<ha;++k){var D=f[k];i[D]||(i[D]={});i=i[D]}i[f[h-1]]=g}else if(f)if(typeof g=="boolean")g?q(c,f,f):r(c,f);else c.setAttribute(f,""+g)}}function Y(a,b){if(b.__jstcache)return b.__jstcache;if(a=b.getAttribute("jstcache"))return b.__jstcache=Q[a];return U(b)}
-function Z(a,b){var c=document;if(a=b?ia(c,a,b):c.getElementById(a)){P(a);a=a.cloneNode(true);a.removeAttribute(ba);return a}else return null}function ia(a,b,c,e){var d=a.getElementById(b);if(d)return d;c=c();e=e||aa;if(d=a.getElementById(e))d=d;else{d=a.createElement(N);d.id=e;t(d);d.style.position="absolute";a.body.appendChild(d)}e=a.createElement(N);d.appendChild(e);e.innerHTML=c;return d=a.getElementById(b)}function $(a,b,c){c==b.length-1?q(a,L,M+c):q(a,L,""+c)};window.jstGetTemplate=Z;window.JsEvalContext=w;window.jstProcess=ca;
-})() \ No newline at end of file