1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// A helper function for using JsTemplate. See jstemplate_builder.h for more
6// info.
7
8#include "ui/base/webui/jstemplate_builder.h"
9
10#include "base/json/json_file_value_serializer.h"
11#include "base/json/json_string_value_serializer.h"
12#include "base/logging.h"
13#include "base/strings/string_util.h"
14#include "ui/base/layout.h"
15#include "ui/base/resource/resource_bundle.h"
16#include "ui/resources/grit/webui_resources.h"
17
18namespace {
19
20// Non-zero when building version 2 templates. See UseVersion2 class.
21int g_version2 = 0;
22
23}  // namespace
24
25namespace webui {
26
27UseVersion2::UseVersion2() {
28  g_version2++;
29}
30
31UseVersion2::~UseVersion2() {
32  g_version2--;
33}
34
35std::string GetTemplateHtml(const base::StringPiece& html_template,
36                            const base::DictionaryValue* json,
37                            const base::StringPiece& template_id) {
38  std::string output(html_template.data(), html_template.size());
39  AppendJsonHtml(json, &output);
40  AppendJsTemplateSourceHtml(&output);
41  AppendJsTemplateProcessHtml(template_id, &output);
42  return output;
43}
44
45std::string GetI18nTemplateHtml(const base::StringPiece& html_template,
46                                const base::DictionaryValue* json) {
47  std::string output(html_template.data(), html_template.size());
48  AppendJsonHtml(json, &output);
49  AppendI18nTemplateSourceHtml(&output);
50  AppendI18nTemplateProcessHtml(&output);
51  return output;
52}
53
54std::string GetTemplatesHtml(const base::StringPiece& html_template,
55                             const base::DictionaryValue* json,
56                             const base::StringPiece& template_id) {
57  std::string output(html_template.data(), html_template.size());
58  AppendI18nTemplateSourceHtml(&output);
59  AppendJsTemplateSourceHtml(&output);
60  AppendJsonHtml(json, &output);
61  AppendI18nTemplateProcessHtml(&output);
62  AppendJsTemplateProcessHtml(template_id, &output);
63  return output;
64}
65
66void AppendJsonHtml(const base::DictionaryValue* json, std::string* output) {
67  std::string javascript_string;
68  AppendJsonJS(json, &javascript_string);
69
70  // </ confuses the HTML parser because it could be a </script> tag.  So we
71  // replace </ with <\/.  The extra \ will be ignored by the JS engine.
72  ReplaceSubstringsAfterOffset(&javascript_string, 0, "</", "<\\/");
73
74  output->append("<script>");
75  output->append(javascript_string);
76  output->append("</script>");
77}
78
79void AppendJsonJS(const base::DictionaryValue* json, std::string* output) {
80  // Convert the template data to a json string.
81  DCHECK(json) << "must include json data structure";
82
83  std::string jstext;
84  JSONStringValueSerializer serializer(&jstext);
85  serializer.Serialize(*json);
86  output->append(g_version2 ? "loadTimeData.data = " : "var templateData = ");
87  output->append(jstext);
88  output->append(";");
89}
90
91void AppendJsTemplateSourceHtml(std::string* output) {
92  // fetch and cache the pointer of the jstemplate resource source text.
93  static const base::StringPiece jstemplate_src(
94      ResourceBundle::GetSharedInstance().GetRawDataResource(
95          IDR_WEBUI_JSTEMPLATE_JS));
96
97  if (jstemplate_src.empty()) {
98    NOTREACHED() << "Unable to get jstemplate src";
99    return;
100  }
101
102  output->append("<script>");
103  output->append(jstemplate_src.data(), jstemplate_src.size());
104  output->append("</script>");
105}
106
107void AppendJsTemplateProcessHtml(const base::StringPiece& template_id,
108                                 std::string* output) {
109  output->append("<script>");
110  output->append("var tp = document.getElementById('");
111  output->append(template_id.data(), template_id.size());
112  output->append("');");
113  output->append("jstProcess(new JsEvalContext(templateData), tp);");
114  output->append("</script>");
115}
116
117void AppendI18nTemplateSourceHtml(std::string* output) {
118  // fetch and cache the pointer of the jstemplate resource source text.
119  static const base::StringPiece i18n_template_src(
120      ResourceBundle::GetSharedInstance().GetRawDataResource(
121          IDR_WEBUI_I18N_TEMPLATE_JS));
122  static const base::StringPiece i18n_template2_src(
123      ResourceBundle::GetSharedInstance().GetRawDataResource(
124          IDR_WEBUI_I18N_TEMPLATE2_JS));
125  const base::StringPiece* template_src = g_version2 ?
126      &i18n_template2_src : &i18n_template_src;
127
128  if (template_src->empty()) {
129    NOTREACHED() << "Unable to get i18n template src";
130    return;
131  }
132
133  output->append("<script>");
134  output->append(template_src->data(), template_src->size());
135  output->append("</script>");
136}
137
138void AppendI18nTemplateProcessHtml(std::string* output) {
139  if (g_version2)
140    return;
141
142  static const base::StringPiece i18n_process_src(
143      ResourceBundle::GetSharedInstance().GetRawDataResource(
144          IDR_WEBUI_I18N_PROCESS_JS));
145
146  if (i18n_process_src.empty()) {
147    NOTREACHED() << "Unable to get i18n process src";
148    return;
149  }
150
151  output->append("<script>");
152  output->append(i18n_process_src.data(), i18n_process_src.size());
153  output->append("</script>");
154}
155
156}  // namespace webui
157