mm_tpl 2.7.2 → 2.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,10 @@
1
1
  const engine = require('art-template');
2
2
  const {
3
3
  Base
4
- } = require('mm_expand');
4
+ } = require('./base.js');
5
+ const {
6
+ FileUtil
7
+ } = require('./file.js');
5
8
  const Hook = require('./hook.js');
6
9
  const {
7
10
  nativeRule,
@@ -26,9 +29,7 @@ const {
26
29
  const {
27
30
  Lang
28
31
  } = require('./lang.js');
29
- const {
30
- Memory
31
- } = require('./memory.js');
32
+ const Memory = require('./memory.js');
32
33
 
33
34
  /**
34
35
  * 模板引擎类
@@ -36,15 +37,16 @@ const {
36
37
  * 渲染结果不做页面级缓存,页面缓存交由 web 中间件按完整请求上下文负责
37
38
  * @class
38
39
  */
39
- class Engine extends Base {
40
+ class Tpl extends Base {
40
41
  /**
41
42
  * 配置参数
42
43
  */
43
44
  static config = {
44
45
  /**
45
46
  * 应用根目录,目录结构见 doc/目录结构.md
47
+ * 默认为运行根目录,宿主应用建议显式传入自身根目录
46
48
  */
47
- root: $.run_path + '',
49
+ root: FileUtil.getRunPath(),
48
50
  /**
49
51
  * 主题目录,相对应用根目录
50
52
  */
@@ -116,7 +118,7 @@ class Engine extends Base {
116
118
  rules: [nativeRule, artRule, htmlRule, jsRule, pyRule, pyRule2],
117
119
  /**
118
120
  * 复数规则,键为语言代码,语言代码统一用小写下划线(如 zh_cn、en_us)
119
- * mm_expand 的 Lang 已内置 zh_cn、en 规则,其他语言代码需在此登记才能按语言取复数形式
121
+ * 内置 BaseLang 已含 zh_cn、en 规则,其他语言代码需在此登记才能按语言取复数形式
120
122
  */
121
123
  plural_rules: {
122
124
  'en_us': function (count) {
@@ -127,12 +129,33 @@ class Engine extends Base {
127
129
  * 变换字符串
128
130
  */
129
131
  change_str: ['\\#', '\\<', '\\${', '\\*', '\\"""'],
132
+ /**
133
+ * 日志对象,需含 warn / error 等方法,留空则用 console
134
+ * 实例的 this.log 与实例级钩子的错误输出都走该对象
135
+ */
136
+ logger: null,
130
137
  };
131
138
  /**
132
139
  * 语言包文件缓存
133
140
  * 按语言包目录组缓存,形如 {目录组: {fingerprint, dict}},文件未变化时复用解析结果
134
141
  */
135
142
  static lang_cache = {};
143
+ /**
144
+ * 全局钩子实例
145
+ * 所有引擎实例共享,与实例级 this.hook 一起参与执行,全局先执行、实例级后执行
146
+ * 宿主应用注册跨实例钩子时使用,如 Tpl.global_hook.addFunc(...)
147
+ */
148
+ static global_hook = new Hook();
149
+ /**
150
+ * 全局数据袋
151
+ * 渲染时注入模型的 globalBag 字段,供模板跨实例共享数据
152
+ */
153
+ static global_bag = {};
154
+ /**
155
+ * 全局语言包字典
156
+ * 实例未配置任何语言包时的回退字典,形如 { 语言代码: 词条对象 }
157
+ */
158
+ static global_dict = {};
136
159
  /**
137
160
  * 创建引擎实例
138
161
  * @param {Object} config - 配置选项
@@ -216,9 +239,9 @@ class Engine extends Base {
216
239
  this.funcs = {};
217
240
 
218
241
  /**
219
- * 实例级钩子,仅作用于当前实例;与全局 $.hook 一起参与执行,全局先执行、实例级后执行
242
+ * 实例级钩子,仅作用于当前实例;与全局钩子 Tpl.global_hook 一起参与执行,全局先执行、实例级后执行
220
243
  */
221
- this.hook = new Hook();
244
+ this.hook = new Hook(this.config.logger);
222
245
 
223
246
  /**
224
247
  * 初始化
@@ -230,7 +253,7 @@ class Engine extends Base {
230
253
  /**
231
254
  * 初始化模板
232
255
  */
233
- Engine.prototype._initTpl = function () {
256
+ Tpl.prototype._initTpl = function () {
234
257
  var cg = this.config;
235
258
  // 引擎默认值为全局配置,仅主实例写入,避免多实例互相覆盖
236
259
  if (!cg.is_fork) {
@@ -245,7 +268,7 @@ Engine.prototype._initTpl = function () {
245
268
  * 支持 config.js 的 { defaults: { theme, style, lang } } 写法
246
269
  * @param {Object} config - 配置参数
247
270
  */
248
- Engine.prototype._setConfig = function (config) {
271
+ Tpl.prototype._setConfig = function (config) {
249
272
  if (!config) {
250
273
  return;
251
274
  }
@@ -259,7 +282,7 @@ Engine.prototype._setConfig = function (config) {
259
282
  * @param {Object} config - 配置参数
260
283
  * @returns {Object} 规范化后的配置
261
284
  */
262
- Engine.prototype._normalizeConfig = function (config) {
285
+ Tpl.prototype._normalizeConfig = function (config) {
263
286
  if (!config || typeof (config.defaults) !== 'object' || !config.defaults) {
264
287
  return config;
265
288
  }
@@ -283,9 +306,9 @@ Engine.prototype._normalizeConfig = function (config) {
283
306
  * @param {string} theme - 主题名称
284
307
  * @returns {string} 主题根目录全路径
285
308
  */
286
- Engine.prototype.getThemeDir = function (theme) {
309
+ Tpl.prototype.getThemeDir = function (theme) {
287
310
  var cg = this.config;
288
- return theme.fullname(cg.theme_dir.fullname(this.dir));
311
+ return FileUtil.fullname(theme, FileUtil.fullname(cg.theme_dir, this.dir));
289
312
  };
290
313
 
291
314
  /**
@@ -294,12 +317,12 @@ Engine.prototype.getThemeDir = function (theme) {
294
317
  * @param {string} style - 风格名称,为空时取主题下的风格目录本身
295
318
  * @returns {string} 风格目录全路径
296
319
  */
297
- Engine.prototype.getStyleDir = function (theme, style) {
298
- var dir = this.config.style_dir.fullname(this.getThemeDir(theme));
320
+ Tpl.prototype.getStyleDir = function (theme, style) {
321
+ var dir = FileUtil.fullname(this.config.style_dir, this.getThemeDir(theme));
299
322
  if (!style) {
300
323
  return dir;
301
324
  }
302
- return style.fullname(dir);
325
+ return FileUtil.fullname(style, dir);
303
326
  };
304
327
 
305
328
  /**
@@ -310,12 +333,12 @@ Engine.prototype.getStyleDir = function (theme, style) {
310
333
  * @param {string} theme - 主题名称,不传时取当前主题
311
334
  * @returns {Array<string>} 模板目录列表
312
335
  */
313
- Engine.prototype.getTemplateDirs = function (theme) {
336
+ Tpl.prototype.getTemplateDirs = function (theme) {
314
337
  var cg = this.config;
315
338
  var cur_theme = theme || this.current_theme;
316
339
  var dirs = [];
317
340
  if (cg.diy_dir) {
318
- dirs.push(cg.diy_dir.fullname(this.dir));
341
+ dirs.push(FileUtil.fullname(cg.diy_dir, this.dir));
319
342
  }
320
343
  if (cur_theme) {
321
344
  dirs.push(this.getThemeDir(cur_theme));
@@ -333,7 +356,7 @@ Engine.prototype.getTemplateDirs = function (theme) {
333
356
  * @param {string} theme - 主题名称,不传时取当前主题
334
357
  * @returns {Array<string>} 组件目录列表
335
358
  */
336
- Engine.prototype.getComponentDirs = function (theme) {
359
+ Tpl.prototype.getComponentDirs = function (theme) {
337
360
  var cg = this.config;
338
361
  if (!cg.component_dir) {
339
362
  return [];
@@ -341,13 +364,13 @@ Engine.prototype.getComponentDirs = function (theme) {
341
364
  var cur_theme = theme || this.current_theme;
342
365
  var dirs = [];
343
366
  if (cg.diy_dir) {
344
- dirs.push(cg.component_dir.fullname(cg.diy_dir.fullname(this.dir)));
367
+ dirs.push(FileUtil.fullname(cg.component_dir, FileUtil.fullname(cg.diy_dir, this.dir)));
345
368
  }
346
369
  if (cur_theme) {
347
- dirs.push(cg.component_dir.fullname(this.getThemeDir(cur_theme)));
370
+ dirs.push(FileUtil.fullname(cg.component_dir, this.getThemeDir(cur_theme)));
348
371
  }
349
372
  if (cg.default_theme && cg.default_theme !== cur_theme) {
350
- dirs.push(cg.component_dir.fullname(this.getThemeDir(cg.default_theme)));
373
+ dirs.push(FileUtil.fullname(cg.component_dir, this.getThemeDir(cg.default_theme)));
351
374
  }
352
375
  return dirs;
353
376
  };
@@ -361,7 +384,7 @@ Engine.prototype.getComponentDirs = function (theme) {
361
384
  * @param {string} style - 风格名称,不传时取当前风格;显式传空字符串表示用主题下的风格目录本身
362
385
  * @returns {Array<string>} 样式目录列表
363
386
  */
364
- Engine.prototype.getStyleDirs = function (theme, style) {
387
+ Tpl.prototype.getStyleDirs = function (theme, style) {
365
388
  var cg = this.config;
366
389
  var cur_theme = theme || this.current_theme;
367
390
  // 风格取自入参或当前值,为空时以默认风格兜底,不做跨风格回退
@@ -377,7 +400,7 @@ Engine.prototype.getStyleDirs = function (theme, style) {
377
400
  var base = cg.base_style || '';
378
401
  var dirs = [];
379
402
  if (cg.diy_dir) {
380
- dirs.push(cg.diy_dir.fullname(this.dir));
403
+ dirs.push(FileUtil.fullname(cg.diy_dir, this.dir));
381
404
  }
382
405
  for (var i = 0; i < themes.length; i++) {
383
406
  dirs.push(this.getStyleDir(themes[i], cur_style));
@@ -395,21 +418,21 @@ Engine.prototype.getStyleDirs = function (theme, style) {
395
418
  * @param {string} theme - 主题名称,不传时取当前主题
396
419
  * @returns {Array<string>} 脚本目录列表
397
420
  */
398
- Engine.prototype.getJsDirs = function (theme) {
421
+ Tpl.prototype.getJsDirs = function (theme) {
399
422
  var cg = this.config;
400
423
  var cur_theme = theme || this.current_theme;
401
424
  var dirs = [];
402
425
  if (cg.diy_dir) {
403
- dirs.push(cg.diy_dir.fullname(this.dir));
426
+ dirs.push(FileUtil.fullname(cg.diy_dir, this.dir));
404
427
  }
405
428
  if (cur_theme && cg.theme_js_dir) {
406
- dirs.push(cg.theme_js_dir.fullname(this.getThemeDir(cur_theme)));
429
+ dirs.push(FileUtil.fullname(cg.theme_js_dir, this.getThemeDir(cur_theme)));
407
430
  }
408
431
  if (cg.default_theme && cg.default_theme !== cur_theme && cg.theme_js_dir) {
409
- dirs.push(cg.theme_js_dir.fullname(this.getThemeDir(cg.default_theme)));
432
+ dirs.push(FileUtil.fullname(cg.theme_js_dir, this.getThemeDir(cg.default_theme)));
410
433
  }
411
434
  if (cg.js_dir) {
412
- dirs.push(cg.js_dir.fullname(this.dir));
435
+ dirs.push(FileUtil.fullname(cg.js_dir, this.dir));
413
436
  }
414
437
  return dirs;
415
438
  };
@@ -418,7 +441,7 @@ Engine.prototype.getJsDirs = function (theme) {
418
441
  * 预设值
419
442
  * @param {boolean} force - 是否跳过语言包缓存强制重新加载
420
443
  */
421
- Engine.prototype._preset = function (force) {
444
+ Tpl.prototype._preset = function (force) {
422
445
  // 基类构造期间会触发一次预设,此时加载器尚未就绪
423
446
  if (!this.lang_loader) {
424
447
  return;
@@ -430,7 +453,7 @@ Engine.prototype._preset = function (force) {
430
453
  * 获取当前语言
431
454
  * @returns {string} 语言代码
432
455
  */
433
- Engine.prototype.getLang = function () {
456
+ Tpl.prototype.getLang = function () {
434
457
  if (this.lang) {
435
458
  return this.lang.now;
436
459
  }
@@ -442,7 +465,7 @@ Engine.prototype.getLang = function () {
442
465
  * @param {string} lang - 语言代码
443
466
  * @returns {string} 设置后的语言代码
444
467
  */
445
- Engine.prototype.setLang = function (lang) {
468
+ Tpl.prototype.setLang = function (lang) {
446
469
  if (typeof (lang) !== 'string' || !lang) {
447
470
  this.log('warn', '语言参数无效,保持当前语言:' + this.getLang());
448
471
  return this.getLang();
@@ -458,7 +481,7 @@ Engine.prototype.setLang = function (lang) {
458
481
  * @param {...any} args - 替换参数,对象按命名占位符,其余按位置占位符
459
482
  * @returns {string} 翻译后的文本
460
483
  */
461
- Engine.prototype.t = function (key, ...args) {
484
+ Tpl.prototype.t = function (key, ...args) {
462
485
  return this._translate(key, args);
463
486
  };
464
487
 
@@ -468,7 +491,7 @@ Engine.prototype.t = function (key, ...args) {
468
491
  * @param {Array<any>} args - 替换参数
469
492
  * @returns {string} 翻译后的文本
470
493
  */
471
- Engine.prototype._translate = function (key, args) {
494
+ Tpl.prototype._translate = function (key, args) {
472
495
  var val = this.lang.get(key);
473
496
  if (typeof (val) !== 'string' || !args.length) {
474
497
  return val;
@@ -488,7 +511,7 @@ Engine.prototype._translate = function (key, args) {
488
511
  * @param {Object} data - 键值对
489
512
  * @returns {string} 填充后的文本
490
513
  */
491
- Engine.prototype._fillNamed = function (text, data) {
514
+ Tpl.prototype._fillNamed = function (text, data) {
492
515
  for (var key in data) {
493
516
  var val = data[key];
494
517
  if (val === undefined || val === null) {
@@ -508,7 +531,7 @@ Engine.prototype._fillNamed = function (text, data) {
508
531
  * @param {...any} args - 额外替换参数,依次替换 {1}、{2} 等占位符
509
532
  * @returns {string} 翻译后的文本
510
533
  */
511
- Engine.prototype.tc = function (key, count, ...args) {
534
+ Tpl.prototype.tc = function (key, count, ...args) {
512
535
  return this.lang.tc(key, count, ...args);
513
536
  };
514
537
 
@@ -517,7 +540,7 @@ Engine.prototype.tc = function (key, count, ...args) {
517
540
  * 过滤掉无词条的语言,Lang 内置的 zh_cn、en 空字典不计入
518
541
  * @returns {Array<string>} 语言代码数组
519
542
  */
520
- Engine.prototype.getLangs = function () {
543
+ Tpl.prototype.getLangs = function () {
521
544
  if (!this.lang) {
522
545
  return [];
523
546
  }
@@ -539,7 +562,7 @@ Engine.prototype.getLangs = function () {
539
562
  * @param {boolean} force - 是否跳过缓存强制重新读取语言包文件
540
563
  * @returns {Array<string>} 重新加载后的语言列表
541
564
  */
542
- Engine.prototype.reloadLangs = function (force) {
565
+ Tpl.prototype.reloadLangs = function (force) {
543
566
  var lang = this.getLang();
544
567
  this._preset(force);
545
568
  this.setLang(lang);
@@ -551,7 +574,7 @@ Engine.prototype.reloadLangs = function (force) {
551
574
  * @param {string} lang - 语言代码
552
575
  * @returns {Object|null} 语言包对象,不存在时返回null
553
576
  */
554
- Engine.prototype.loadLang = function (lang) {
577
+ Tpl.prototype.loadLang = function (lang) {
555
578
  if (typeof (lang) !== 'string' || !lang) {
556
579
  this.log('warn', '语言参数无效:' + lang);
557
580
  return null;
@@ -570,9 +593,9 @@ Engine.prototype.loadLang = function (lang) {
570
593
  * 传入对象需实现 getUser / setUser / delUser / hasUser / listUsers / clear 六个同步方法
571
594
  * 留空或接口不完整时回退为内置内存存储(Memory)
572
595
  * @param {Object} store - 存储对象
573
- * @returns {Engine} 当前实例
596
+ * @returns {Tpl} 当前实例
574
597
  */
575
- Engine.prototype.setStore = function (store) {
598
+ Tpl.prototype.setStore = function (store) {
576
599
  if (!store || !this._isStore(store)) {
577
600
  if (store) {
578
601
  this.log('warn', 'user_store 接口不完整,回退为内置内存存储');
@@ -589,7 +612,7 @@ Engine.prototype.setStore = function (store) {
589
612
  * 派生实例复用该对象即可共享同一份用户偏好
590
613
  * @returns {Object} 存储对象
591
614
  */
592
- Engine.prototype.getStore = function () {
615
+ Tpl.prototype.getStore = function () {
593
616
  return this.store;
594
617
  };
595
618
 
@@ -598,7 +621,7 @@ Engine.prototype.getStore = function () {
598
621
  * @param {Object} store - 存储对象
599
622
  * @returns {boolean} 六个同步方法是否齐备
600
623
  */
601
- Engine.prototype._isStore = function (store) {
624
+ Tpl.prototype._isStore = function (store) {
602
625
  var methods = ['getUser', 'setUser', 'delUser', 'hasUser', 'listUsers', 'clear'];
603
626
  for (var i = 0; i < methods.length; i++) {
604
627
  if (typeof (store[methods[i]]) !== 'function') {
@@ -614,7 +637,7 @@ Engine.prototype._isStore = function (store) {
614
637
  * @param {Object} prefs - 用户偏好,形如 { style, lang }
615
638
  * @returns {Object} 规范化后的偏好
616
639
  */
617
- Engine.prototype._prefs = function (prefs) {
640
+ Tpl.prototype._prefs = function (prefs) {
618
641
  if (!prefs || typeof (prefs) !== 'object') {
619
642
  throw new TypeError('用户偏好必须是对象');
620
643
  }
@@ -641,7 +664,7 @@ Engine.prototype._prefs = function (prefs) {
641
664
  * @param {Object} prefs - 用户偏好,形如 { style, lang },只取这两个字段
642
665
  * @returns {Object} 保存后的用户偏好
643
666
  */
644
- Engine.prototype.setUser = function (user_id, prefs) {
667
+ Tpl.prototype.setUser = function (user_id, prefs) {
645
668
  return this.store.setUser(user_id, this._prefs(prefs));
646
669
  };
647
670
 
@@ -650,7 +673,7 @@ Engine.prototype.setUser = function (user_id, prefs) {
650
673
  * @param {string|number} user_id - 用户标识
651
674
  * @returns {Object|null} 用户偏好,未登记时返回 null
652
675
  */
653
- Engine.prototype.getUser = function (user_id) {
676
+ Tpl.prototype.getUser = function (user_id) {
654
677
  return this.store.getUser(user_id);
655
678
  };
656
679
 
@@ -659,7 +682,7 @@ Engine.prototype.getUser = function (user_id) {
659
682
  * @param {string|number} user_id - 用户标识
660
683
  * @returns {boolean} 是否删除成功
661
684
  */
662
- Engine.prototype.removeUser = function (user_id) {
685
+ Tpl.prototype.removeUser = function (user_id) {
663
686
  return this.store.delUser(user_id);
664
687
  };
665
688
 
@@ -667,7 +690,7 @@ Engine.prototype.removeUser = function (user_id) {
667
690
  * 获取已登记的用户标识列表
668
691
  * @returns {Array<string>} 用户标识数组
669
692
  */
670
- Engine.prototype.getUsers = function () {
693
+ Tpl.prototype.getUsers = function () {
671
694
  return this.store.listUsers();
672
695
  };
673
696
 
@@ -679,7 +702,7 @@ Engine.prototype.getUsers = function () {
679
702
  * @param {Object} options - 其他渲染参数,可省略
680
703
  * @returns {Object} 渲染参数,含 style 与 lang
681
704
  */
682
- Engine.prototype.userOptions = function (user_id, options) {
705
+ Tpl.prototype.userOptions = function (user_id, options) {
683
706
  var opt = Object.assign({}, options);
684
707
  var record = this.store.getUser(user_id);
685
708
  opt.style = (record && record.style !== undefined) ? record.style : this.current_style;
@@ -695,8 +718,8 @@ Engine.prototype.userOptions = function (user_id, options) {
695
718
  * @param {...any} args - 附加参数
696
719
  * @returns {Promise<any>} 执行结果
697
720
  */
698
- Engine.prototype.runFunc = async function (name, req, ...args) {
699
- var ret = await $.hook.runFunc(name, this.viewBag, req, ...args);
721
+ Tpl.prototype.runFunc = async function (name, req, ...args) {
722
+ var ret = await Tpl.global_hook.runFunc(name, this.viewBag, req, ...args);
700
723
  var ret_inst = await this.hook.runFunc(name, this.viewBag, req, ...args);
701
724
  return ret_inst || ret;
702
725
  };
@@ -708,19 +731,19 @@ Engine.prototype.runFunc = async function (name, req, ...args) {
708
731
  * @param {...any} args - 附加参数
709
732
  * @returns {Promise<any>} 执行结果
710
733
  */
711
- Engine.prototype.runHook = Engine.prototype.runFunc;
734
+ Tpl.prototype.runHook = Tpl.prototype.runFunc;
712
735
 
713
736
  /**
714
737
  * 初始化前处理
715
738
  * @param {Object} config - 配置参数
716
739
  */
717
- Engine.prototype._initBefore = function (config) { };
740
+ Tpl.prototype._initBefore = function (config) { };
718
741
 
719
742
  /**
720
743
  * 初始化主处理
721
744
  * @param {Object} config - 配置参数
722
745
  */
723
- Engine.prototype._initMain = function (config) {
746
+ Tpl.prototype._initMain = function (config) {
724
747
  this.setConfig(config);
725
748
  this._initTpl();
726
749
  };
@@ -730,7 +753,7 @@ Engine.prototype._initMain = function (config) {
730
753
  * 构建字符转义规则,供渲染前后转义与还原使用
731
754
  * @param {Object} config - 配置参数
732
755
  */
733
- Engine.prototype._initAfter = function (config) {
756
+ Tpl.prototype._initAfter = function (config) {
734
757
  this.escape_rule = TplUtil.buildEscapeRule(this.config.change_str);
735
758
  };
736
759
 
@@ -738,7 +761,7 @@ Engine.prototype._initAfter = function (config) {
738
761
  * 初始化模板
739
762
  * @param {Object} config - 配置参数
740
763
  */
741
- Engine.prototype._init = function (config) {
764
+ Tpl.prototype._init = function (config) {
742
765
  this._initBefore(config);
743
766
  this._initMain(config);
744
767
  this._initAfter(config);
@@ -748,7 +771,7 @@ Engine.prototype._init = function (config) {
748
771
  * 获取当前主题
749
772
  * @returns {string} 主题名称
750
773
  */
751
- Engine.prototype.getTheme = function () {
774
+ Tpl.prototype.getTheme = function () {
752
775
  return this.current_theme;
753
776
  };
754
777
 
@@ -760,7 +783,7 @@ Engine.prototype.getTheme = function () {
760
783
  * @param {boolean} force - 是否跳过目录校验
761
784
  * @returns {string} 设置后的主题名称
762
785
  */
763
- Engine.prototype.setTheme = function (theme, force) {
786
+ Tpl.prototype.setTheme = function (theme, force) {
764
787
  if (typeof (theme) !== 'string' || !theme) {
765
788
  this.log('warn', '主题参数无效,保持当前主题:' + this.current_theme);
766
789
  return this.current_theme;
@@ -782,7 +805,7 @@ Engine.prototype.setTheme = function (theme, force) {
782
805
  * 获取当前风格
783
806
  * @returns {string} 风格名称,未设置时返回空字符串
784
807
  */
785
- Engine.prototype.getStyle = function () {
808
+ Tpl.prototype.getStyle = function () {
786
809
  return this.current_style;
787
810
  };
788
811
 
@@ -792,7 +815,7 @@ Engine.prototype.getStyle = function () {
792
815
  * @param {boolean} force - 是否跳过目录校验
793
816
  * @returns {string} 设置后的风格名称
794
817
  */
795
- Engine.prototype.setStyle = function (style, force) {
818
+ Tpl.prototype.setStyle = function (style, force) {
796
819
  if (typeof (style) !== 'string') {
797
820
  this.log('warn', '风格参数无效,保持当前风格:' + this.current_style);
798
821
  return this.current_style;
@@ -811,7 +834,7 @@ Engine.prototype.setStyle = function (style, force) {
811
834
  * @param {boolean} restore 是否还原转义字符
812
835
  * @returns {string} 转义后的字符串
813
836
  */
814
- Engine.prototype.escape = function (body, restore) {
837
+ Tpl.prototype.escape = function (body, restore) {
815
838
  return TplUtil.escape(body, this.escape_rule, restore);
816
839
  };
817
840
 
@@ -820,7 +843,7 @@ Engine.prototype.escape = function (body, restore) {
820
843
  * @param {Object} m - 模型对象
821
844
  * @returns {Object} 处理后的模型
822
845
  */
823
- Engine.prototype._loadFuncBefore = function (m) {
846
+ Tpl.prototype._loadFuncBefore = function (m) {
824
847
  // m.$i18n = function(key) {
825
848
  // return $.i18n(key);
826
849
  // }
@@ -832,7 +855,7 @@ Engine.prototype._loadFuncBefore = function (m) {
832
855
  * @param {Object} m 模型对象
833
856
  * @returns {Object} 处理后的模型
834
857
  */
835
- Engine.prototype.loadFunc = function (m) {
858
+ Tpl.prototype.loadFunc = function (m) {
836
859
  this._loadFuncBefore(m);
837
860
  var _this = this;
838
861
  m.view = function (file, model, options) {
@@ -856,13 +879,13 @@ Engine.prototype.loadFunc = function (m) {
856
879
  };
857
880
  m.hookAction = function (name, ...args) {
858
881
  // 全局动作钩子先输出,实例级动作钩子后输出
859
- return $.hook.runAction(name, m, ...args) + _this.hook.runAction(name, m, ...args);
882
+ return Tpl.global_hook.runAction(name, m, ...args) + _this.hook.runAction(name, m, ...args);
860
883
  };
861
884
  m.hookFilter = function (name, content, ...args) {
862
885
  if (!content) {
863
886
  content = '';
864
887
  }
865
- var ret = $.hook.runFilter(name, m, content, ...args);
888
+ var ret = Tpl.global_hook.runFilter(name, m, content, ...args);
866
889
  return _this.hook.runFilter(name, m, ret, ...args);
867
890
  };
868
891
  if (this.lang) {
@@ -887,7 +910,7 @@ Engine.prototype.loadFunc = function (m) {
887
910
  * @param {Function} func - 函数
888
911
  * @returns {boolean} 是否设置成功
889
912
  */
890
- Engine.prototype.setFunc = function (name, func) {
913
+ Tpl.prototype.setFunc = function (name, func) {
891
914
  if (typeof (name) !== 'string' || !name) {
892
915
  this.log('warn', '模板函数名无效:' + name);
893
916
  return false;
@@ -905,7 +928,7 @@ Engine.prototype.setFunc = function (name, func) {
905
928
  * @param {string} name - 函数名
906
929
  * @returns {boolean} 是否存在并删除成功
907
930
  */
908
- Engine.prototype.removeFunc = function (name) {
931
+ Tpl.prototype.removeFunc = function (name) {
909
932
  if (this.funcs[name] === undefined) {
910
933
  return false;
911
934
  }
@@ -917,7 +940,7 @@ Engine.prototype.removeFunc = function (name) {
917
940
  * 获取模板函数表
918
941
  * @returns {Object} 模板函数表
919
942
  */
920
- Engine.prototype.getFuncs = function () {
943
+ Tpl.prototype.getFuncs = function () {
921
944
  return this.funcs;
922
945
  };
923
946
 
@@ -928,12 +951,12 @@ Engine.prototype.getFuncs = function () {
928
951
  * @param {Object} options - 配置参数
929
952
  * @returns {string} 渲染结果
930
953
  */
931
- Engine.prototype._renderMain = function (body, model, options) {
954
+ Tpl.prototype._renderMain = function (body, model, options) {
932
955
  var ret = '';
933
956
  if (body) {
934
957
  var m = Object.assign({}, {
935
958
  viewBag: this.viewBag,
936
- globalBag: $.globalBag
959
+ globalBag: Tpl.global_bag
937
960
  }, model);
938
961
  this.loadFunc(m);
939
962
  ret = this.engine.render(body, m, options);
@@ -948,7 +971,7 @@ Engine.prototype._renderMain = function (body, model, options) {
948
971
  * @param {Object} options - 渲染参数
949
972
  * @returns {Object|null} 原风格与原语言,未涉及临时选项时返回 null
950
973
  */
951
- Engine.prototype._applyTempOptions = function (options) {
974
+ Tpl.prototype._applyTempOptions = function (options) {
952
975
  if (!options) {
953
976
  return null;
954
977
  }
@@ -974,7 +997,7 @@ Engine.prototype._applyTempOptions = function (options) {
974
997
  * 恢复临时选项
975
998
  * @param {Object|null} prev - _applyTempOptions 返回的原值
976
999
  */
977
- Engine.prototype._restoreTempOptions = function (prev) {
1000
+ Tpl.prototype._restoreTempOptions = function (prev) {
978
1001
  if (!prev) {
979
1002
  return;
980
1003
  }
@@ -992,7 +1015,7 @@ Engine.prototype._restoreTempOptions = function (prev) {
992
1015
  * @param {Object} options - 配置参数
993
1016
  * @returns {string} 渲染结果
994
1017
  */
995
- Engine.prototype.render = function (body, model, options) {
1018
+ Tpl.prototype.render = function (body, model, options) {
996
1019
  var prev = this._applyTempOptions(options);
997
1020
  try {
998
1021
  body = this.escape(body);
@@ -1009,7 +1032,7 @@ Engine.prototype.render = function (body, model, options) {
1009
1032
  * @param {Object} options - 配置参数
1010
1033
  * @returns {Function} 渲染函数
1011
1034
  */
1012
- Engine.prototype.compile = function (body, options) {
1035
+ Tpl.prototype.compile = function (body, options) {
1013
1036
  return this.engine.compile(body, options);
1014
1037
  };
1015
1038
 
@@ -1019,7 +1042,7 @@ Engine.prototype.compile = function (body, options) {
1019
1042
  * @param {Object} options - 配置参数,dir 为指定的查找目录
1020
1043
  * @returns {string} 模板文件路径
1021
1044
  */
1022
- Engine.prototype.getFile = function (file, options) {
1045
+ Tpl.prototype.getFile = function (file, options) {
1023
1046
  return this.template.getFile(file, options);
1024
1047
  };
1025
1048
 
@@ -1029,7 +1052,7 @@ Engine.prototype.getFile = function (file, options) {
1029
1052
  * 结果按优先级升序排列:基础风格在前打底,当前风格与自定义目录在后覆盖
1030
1053
  * @returns {Array<string>} 样式文件全路径列表
1031
1054
  */
1032
- Engine.prototype.getCssFiles = function () {
1055
+ Tpl.prototype.getCssFiles = function () {
1033
1056
  return this.css.getFiles();
1034
1057
  };
1035
1058
 
@@ -1041,7 +1064,7 @@ Engine.prototype.getCssFiles = function () {
1041
1064
  * @param {string} style - 风格名称,不传时取当前风格
1042
1065
  * @returns {Array<string>} 命中的样式文件全路径列表,顺序即引用顺序
1043
1066
  */
1044
- Engine.prototype.matchCssFiles = function (pattern, theme, style) {
1067
+ Tpl.prototype.matchCssFiles = function (pattern, theme, style) {
1045
1068
  return this.css.matchFiles(pattern, theme, style);
1046
1069
  };
1047
1070
 
@@ -1054,7 +1077,7 @@ Engine.prototype.matchCssFiles = function (pattern, theme, style) {
1054
1077
  * @param {string} style - 风格名称,不传时取当前风格
1055
1078
  * @returns {string|Array<string>|null} 样式文件全路径;无通配符且不存在时返回 null
1056
1079
  */
1057
- Engine.prototype.getCssFile = function (name, theme, style) {
1080
+ Tpl.prototype.getCssFile = function (name, theme, style) {
1058
1081
  if (!name || typeof (name) !== 'string') {
1059
1082
  return null;
1060
1083
  }
@@ -1072,7 +1095,7 @@ Engine.prototype.getCssFile = function (name, theme, style) {
1072
1095
  * @param {string} theme - 主题名称,不传时取当前主题
1073
1096
  * @returns {Array<string>} 命中的脚本文件全路径列表,顺序即执行顺序
1074
1097
  */
1075
- Engine.prototype.matchJsFiles = function (pattern, theme) {
1098
+ Tpl.prototype.matchJsFiles = function (pattern, theme) {
1076
1099
  return this.js.matchFiles(pattern, theme);
1077
1100
  };
1078
1101
 
@@ -1082,7 +1105,7 @@ Engine.prototype.matchJsFiles = function (pattern, theme) {
1082
1105
  * 结果按优先级升序排列:应用级公共脚本在前,主题脚本与自定义目录在后
1083
1106
  * @returns {Array<string>} 脚本文件全路径列表
1084
1107
  */
1085
- Engine.prototype.getJsFiles = function () {
1108
+ Tpl.prototype.getJsFiles = function () {
1086
1109
  return this.js.getFiles();
1087
1110
  };
1088
1111
 
@@ -1094,7 +1117,7 @@ Engine.prototype.getJsFiles = function () {
1094
1117
  * @param {string} theme - 主题名称,不传时取当前主题
1095
1118
  * @returns {string|Array<string>|null} 脚本文件全路径;无通配符且不存在时返回 null
1096
1119
  */
1097
- Engine.prototype.getJsFile = function (name, theme) {
1120
+ Tpl.prototype.getJsFile = function (name, theme) {
1098
1121
  if (!name || typeof (name) !== 'string') {
1099
1122
  return null;
1100
1123
  }
@@ -1112,7 +1135,7 @@ Engine.prototype.getJsFile = function (name, theme) {
1112
1135
  * @param {Object} options - 配置参数,dir 为指定的查找目录
1113
1136
  * @returns {string} 组件文件路径
1114
1137
  */
1115
- Engine.prototype.getComponentFile = function (name, options) {
1138
+ Tpl.prototype.getComponentFile = function (name, options) {
1116
1139
  return this.template.getComponent(name, options);
1117
1140
  };
1118
1141
 
@@ -1125,7 +1148,7 @@ Engine.prototype.getComponentFile = function (name, options) {
1125
1148
  * @param {Object} options - 配置参数
1126
1149
  * @returns {string} 渲染结果
1127
1150
  */
1128
- Engine.prototype.component = function (name, model, options) {
1151
+ Tpl.prototype.component = function (name, model, options) {
1129
1152
  var dirs = this.getComponentDirs();
1130
1153
  if (!dirs.length) {
1131
1154
  this.error = {
@@ -1135,14 +1158,14 @@ Engine.prototype.component = function (name, model, options) {
1135
1158
  return '';
1136
1159
  }
1137
1160
  var f = this.getComponentFile(name, options);
1138
- if (!f.hasFile()) {
1161
+ if (!FileUtil.hasFile(f)) {
1139
1162
  this.error = {
1140
1163
  code: 10000,
1141
1164
  message: f + '组件不存在!'
1142
1165
  };
1143
1166
  return '';
1144
1167
  }
1145
- var body = f.loadText();
1168
+ var body = FileUtil.loadText(f);
1146
1169
  if (!body) {
1147
1170
  return '';
1148
1171
  }
@@ -1160,18 +1183,18 @@ Engine.prototype.component = function (name, model, options) {
1160
1183
  * @param {Object} options - 配置参数
1161
1184
  * @returns {string} 渲染结果
1162
1185
  */
1163
- Engine.prototype.view = function (file, model, options) {
1186
+ Tpl.prototype.view = function (file, model, options) {
1164
1187
  var prev = this._applyTempOptions(options);
1165
1188
  try {
1166
1189
  var f = this.getFile(file, options);
1167
- if (!f.hasFile()) {
1190
+ if (!FileUtil.hasFile(f)) {
1168
1191
  this.error = {
1169
1192
  code: 10000,
1170
1193
  message: f + '文件不存在!'
1171
1194
  };
1172
1195
  }
1173
1196
  else {
1174
- var body = f.loadText();
1197
+ var body = FileUtil.loadText(f);
1175
1198
  if (body) {
1176
1199
  body = this.escape(body);
1177
1200
  body = this._renderMain(body, model, options);
@@ -1189,15 +1212,15 @@ Engine.prototype.view = function (file, model, options) {
1189
1212
  * 设置视图数据
1190
1213
  * @param {Object} obj - 要设置的数据对象
1191
1214
  */
1192
- Engine.prototype.set = function (obj) {
1193
- $.push(this.viewBag, obj, true);
1215
+ Tpl.prototype.set = function (obj) {
1216
+ TplUtil.mergeDeep(this.viewBag, obj, true);
1194
1217
  };
1195
1218
 
1196
1219
  /**
1197
1220
  * 删除视图数据
1198
1221
  * @param {Array|string} keys - 要删除的键或键数组
1199
1222
  */
1200
- Engine.prototype.del = function (keys) {
1223
+ Tpl.prototype.del = function (keys) {
1201
1224
  if (typeof (keys) == 'string') {
1202
1225
  delete this.viewBag[keys];
1203
1226
  } else {
@@ -1212,7 +1235,7 @@ Engine.prototype.del = function (keys) {
1212
1235
  * @param {string} key - 数据键名
1213
1236
  * @returns {any} 数据值
1214
1237
  */
1215
- Engine.prototype.get = function (key) {
1238
+ Tpl.prototype.get = function (key) {
1216
1239
  return this.viewBag[key];
1217
1240
  };
1218
1241
 
@@ -1224,9 +1247,9 @@ Engine.prototype.get = function (key) {
1224
1247
  * @param {string} config.theme - 主题名称
1225
1248
  * @param {string} config.style - 风格名称
1226
1249
  * @param {string} config.lang - 语言代码
1227
- * @returns {Engine} 派生出的引擎实例
1250
+ * @returns {Tpl} 派生出的引擎实例
1228
1251
  */
1229
- Engine.prototype.fork = function (config) {
1252
+ Tpl.prototype.fork = function (config) {
1230
1253
  var cg = config || {};
1231
1254
  var lang = (cg.lang && this.lang.isSupported(cg.lang)) ? cg.lang : this.getLang();
1232
1255
  var cfg = Object.assign({}, this.config, {
@@ -1237,7 +1260,7 @@ Engine.prototype.fork = function (config) {
1237
1260
  // 用户偏好属于用户而非实例,派生实例复用同一份存储
1238
1261
  user_store: this.getStore()
1239
1262
  });
1240
- var tpl = new Engine(cfg);
1263
+ var tpl = new Tpl(cfg);
1241
1264
  tpl.dir = this.dir;
1242
1265
  if (cg.theme) {
1243
1266
  tpl.setTheme(cg.theme);
@@ -1245,12 +1268,12 @@ Engine.prototype.fork = function (config) {
1245
1268
  if (cg.style) {
1246
1269
  tpl.setStyle(cg.style);
1247
1270
  }
1248
- $.push(tpl.viewBag, this.viewBag, true);
1271
+ TplUtil.mergeDeep(tpl.viewBag, this.viewBag, true);
1249
1272
  // 模板函数属于站点级扩展,派生实例继承同一份
1250
1273
  tpl.funcs = Object.assign({}, this.funcs);
1251
1274
  return tpl;
1252
1275
  };
1253
1276
 
1254
1277
  module.exports = {
1255
- Engine
1278
+ Tpl
1256
1279
  };