1 | "use strict";
|
2 |
|
3 | const path = require('path');
|
4 | const os = require('os');
|
5 | const fs = require('fs');
|
6 | const jsmart = require('jsmart');
|
7 | const logger = require('jdf-log');
|
8 | const escapeStringRegexp = require('escape-string-regexp');
|
9 | const stripJsonComments = require('strip-json-comments');
|
10 |
|
11 |
|
12 | const jdfUtils = require('jdf-utils');
|
13 | const $ = jdfUtils.base;
|
14 | const f = jdfUtils.file;
|
15 | const jdf = require('./jdf');
|
16 | const Vm = require("./vm");
|
17 | const VFS = require('./VFS/VirtualFileSystem');
|
18 | const widgetParser = require('./buildWidget');
|
19 | const pluginCore = require('./pluginCore')
|
20 |
|
21 | let buildHTML = module.exports = {};
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | buildHTML.init = function () {
|
35 | buildHTML.VFS = VFS;
|
36 | logger.profile('parse widget');
|
37 | return VFS.go()
|
38 | .then(() => {
|
39 | return VFS.travel((vfile, done) => {
|
40 |
|
41 | if (!$.is.html(vfile.originPath)) {
|
42 | return;
|
43 | }
|
44 |
|
45 | logger.verbose(`reset vfile.targetContent to be vfile.originContent: ${vfile.originPath}`);
|
46 |
|
47 | vfile.targetContent = vfile.originContent;
|
48 |
|
49 | logger.verbose(`step1: parse widgetTree roots`)
|
50 | let widgetRoots = widgetParser.parseWidget(vfile.originContent);
|
51 |
|
52 |
|
53 | let jsMap = new Map();
|
54 | let cssMap = new Map();
|
55 |
|
56 | let rootTrees = [];
|
57 | widgetRoots.forEach(rootWidgetInfo => {
|
58 | logger.verbose(`step2: generate widget tree,page:${path.basename(vfile.originPath)},widget:${rootWidgetInfo.name}`);
|
59 | let WidgetTree = widgetParser.generateWidgetTree(rootWidgetInfo);
|
60 | rootTrees.push(WidgetTree);
|
61 |
|
62 | logger.verbose(`step 3: 自底向上遍历widget tree, 生成vmcontent, jsMap, cssMap`);
|
63 | let container = vfile.targetContent;
|
64 | container = buildHTML.renderTemplateToContainer(WidgetTree, container, jsMap, cssMap);
|
65 |
|
66 | logger.verbose(`step 4: 插入vm到html中`);
|
67 | vfile.targetContent = container;
|
68 | });
|
69 |
|
70 | logger.verbose(`step 5: 清除widget标签,因为有些只引入js或css,从而不会被vm替换`);
|
71 | rootTrees.forEach(WidgetTree => {
|
72 | vfile.targetContent = this.cleanWidgetLabel(WidgetTree, vfile.targetContent);
|
73 | })
|
74 |
|
75 | logger.verbose(`step 6: 插入js、css到html中`);
|
76 | for (let key of jsMap.keys()) {
|
77 | let jsPath = path.resolve(VFS.targetDir, jdf.config.widgetDir, key, key + '.js');
|
78 | let jsVfile = VFS.queryFile(jsPath, 'target');
|
79 | if (jsVfile) {
|
80 | this.insertJS(vfile, jsVfile, jdf.config.build.jsPlace);
|
81 | }
|
82 | }
|
83 | for (let key of cssMap.keys()) {
|
84 | let cssPath = path.resolve(VFS.targetDir, jdf.config.widgetDir, key, key + '.css');
|
85 | let cssVfile = VFS.queryFile(cssPath, 'target');
|
86 | if (cssVfile) {
|
87 | this.insertCSS(vfile, cssVfile);
|
88 | }
|
89 | }
|
90 | });
|
91 | }).then(() => {
|
92 | logger.profile('parse widget');
|
93 | }).catch(err => {
|
94 | logger.error(err);
|
95 | });
|
96 |
|
97 | }
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | buildHTML.renderTemplateToContainer = function (node, container, jsMap, cssMap) {
|
103 | let widgetInfo = node.widgetInfo;
|
104 |
|
105 | let buildTag = widgetInfo.buildTag;
|
106 |
|
107 | if (buildTag.js) {
|
108 | jsMap.set(widgetInfo.name, true);
|
109 | }
|
110 | if (buildTag.css) {
|
111 | cssMap.set(widgetInfo.name, true);
|
112 | }
|
113 |
|
114 |
|
115 | if (!(widgetInfo.buildTag.vm || widgetInfo.buildTag.tpl || widgetInfo.buildTag.smarty)) {
|
116 | return container;
|
117 | }
|
118 |
|
119 |
|
120 | let vmVfile = widgetParser.findvmVfile(widgetInfo);
|
121 | if (!vmVfile) {
|
122 | return container;
|
123 | }
|
124 |
|
125 | let renderedResult = '';
|
126 | if (widgetInfo.buildTag.vm || widgetInfo.buildTag.tpl) {
|
127 | renderedResult = this.renderVM(widgetInfo, jsMap, cssMap);;
|
128 | } else if (widgetInfo.buildTag.smarty) {
|
129 | renderedResult = this.renderSmarty(widgetInfo, jsMap, cssMap);;
|
130 | }
|
131 |
|
132 |
|
133 | if (node.children.length > 0) {
|
134 |
|
135 | let childContainer = renderedResult;
|
136 |
|
137 |
|
138 | node.children.forEach(child => {
|
139 | childContainer = this.renderTemplateToContainer(child, childContainer, jsMap, cssMap);
|
140 |
|
141 | });
|
142 | renderedResult = childContainer;
|
143 | }
|
144 |
|
145 | if (jdf.config.widgetLabel && renderedResult) {
|
146 |
|
147 |
|
148 |
|
149 | renderedResult = `${os.EOL}<!-- widget ${widgetInfo.name} begin -->`
|
150 | + `${renderedResult}`
|
151 | + `${os.EOL}<!-- widget ${widgetInfo.name} end -->`;
|
152 | }
|
153 |
|
154 | container = container.replace(widgetInfo.text, renderedResult);
|
155 |
|
156 | return container;
|
157 | }
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 | buildHTML.renderVM = function (widgetInfo, jsMap, cssMap) {
|
164 | widgetInfo.type = 'vm';
|
165 |
|
166 | let replaceStr = '';
|
167 |
|
168 |
|
169 | let vmVfile = widgetParser.findvmVfile(widgetInfo);
|
170 | if (!vmVfile) {
|
171 | return replaceStr;
|
172 | }
|
173 |
|
174 | let tpl = vmVfile.targetContent;
|
175 |
|
176 |
|
177 | tpl = pluginCore.excuteBeforeTplRender(tpl, widgetInfo);
|
178 |
|
179 |
|
180 | let vmdata = widgetParser.getWidgetData(widgetInfo);
|
181 | if (!tpl) {
|
182 | replaceStr = '';
|
183 | } else {
|
184 | try {
|
185 | let result = Vm.render(tpl, {
|
186 | dataObj: vmdata,
|
187 | dirname: widgetInfo.dirname,
|
188 | existMap: {jsMap: jsMap, cssMap: cssMap}
|
189 | });
|
190 | replaceStr = os.EOL + result;
|
191 | logger.verbose(`have vm content and render success`);
|
192 | } catch (err) {
|
193 | logger.error('velocityjs compile failed.');
|
194 | logger.error(err);
|
195 | }
|
196 | }
|
197 | if (replaceStr === '') {
|
198 | logger.verbose(`vm parsed, and result to empty string`);
|
199 | }
|
200 |
|
201 |
|
202 | replaceStr = pluginCore.excuteBeforeTplInsert(replaceStr, widgetInfo);
|
203 |
|
204 | return replaceStr;
|
205 | }
|
206 |
|
207 |
|
208 |
|
209 |
|
210 | buildHTML.renderSmarty = function (widgetInfo) {
|
211 | widgetInfo.type = 'smarty';
|
212 |
|
213 |
|
214 | let vmVfile = widgetParser.findvmVfile(widgetInfo);
|
215 | if (!vmVfile) {
|
216 | return replaceStr;
|
217 | }
|
218 |
|
219 | let tpl = vmVfile.targetContent;
|
220 |
|
221 |
|
222 | tpl = pluginCore.excuteBeforeTplRender(tpl, widgetInfo);
|
223 |
|
224 | let smdata = widgetParser.getWidgetData(widgetInfo);
|
225 |
|
226 | let smartyCompiled = new jSmart(tpl);
|
227 |
|
228 | let replaceStr = '';
|
229 | if(smartyCompiled){
|
230 | replaceStr = smartyCompiled.fetch(smdata);
|
231 | }
|
232 |
|
233 |
|
234 | replaceStr = pluginCore.excuteBeforeTplInsert(replaceStr, widgetInfo);
|
235 |
|
236 | return replaceStr;
|
237 | }
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 | buildHTML.insertJS = function (htmlVfile, jsVfile, place) {
|
247 | let insertFn;
|
248 | if (place !== 'insertBody') {
|
249 | insertFn = $.placeholder.insertHead;
|
250 | } else {
|
251 | insertFn = $.placeholder.insertBody;
|
252 | }
|
253 |
|
254 | let htmlFileDir = path.dirname(htmlVfile.originPath);
|
255 |
|
256 | let scriptPath = path.join(path.dirname(jsVfile.originPath), path.basename(jsVfile.targetPath));
|
257 | scriptPath = path.relative(htmlFileDir, scriptPath);
|
258 | scriptPath = f.pathFormat(scriptPath);
|
259 |
|
260 | if (!htmlVfile.targetContent) {
|
261 | htmlVfile.targetContent = htmlVfile.originContent;
|
262 | }
|
263 | htmlVfile.targetContent = insertFn(htmlVfile.targetContent, $.placeholder.jsLink(scriptPath));
|
264 | }
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 | buildHTML.insertCSS = function (htmlVfile, cssVfile) {
|
273 | let insertFn = $.placeholder.insertHead;
|
274 |
|
275 | let htmlFileDir = path.dirname(htmlVfile.originPath);
|
276 |
|
277 | let linkPath = path.join(path.dirname(cssVfile.originPath), path.basename(cssVfile.targetPath));
|
278 | linkPath = path.relative(htmlFileDir, linkPath);
|
279 | linkPath = f.pathFormat(linkPath);
|
280 |
|
281 | if (!htmlVfile.targetContent) {
|
282 | htmlVfile.targetContent = htmlVfile.originContent;
|
283 | }
|
284 | htmlVfile.targetContent = insertFn(htmlVfile.targetContent, $.placeholder.cssLink(linkPath));
|
285 | }
|
286 |
|
287 | buildHTML.cleanWidgetLabel = function (node, content) {
|
288 | content = content.replace(new RegExp(escapeStringRegexp(node.widgetInfo.text), 'g'), os.EOL);
|
289 | node.children.forEach(child => {
|
290 | content = this.cleanWidgetLabel(child, content);
|
291 | });
|
292 | return content;
|
293 | } |
\ | No newline at end of file |