All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jfinal.template.stat.ast.Include Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2011-2023, James Zhan 詹波 ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jfinal.template.stat.ast;

import com.jfinal.template.EngineConfig;
import com.jfinal.template.Env;
import com.jfinal.template.expr.ast.Assign;
import com.jfinal.template.expr.ast.Const;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.io.Writer;
import com.jfinal.template.source.ISource;
import com.jfinal.template.stat.Ctrl;
import com.jfinal.template.stat.Location;
import com.jfinal.template.stat.ParseException;
import com.jfinal.template.stat.Parser;
import com.jfinal.template.stat.Scope;

/**
 * Include
 *
 * 1:父模板被缓存时,被 include 的模板会被间接缓存,无需关心缓存问题
 * 2:同一个模板文件被多个父模板 include,所处的背景环境不同,例如各父模板中定义的模板函数不同
 * 各父模板所处的相对路径不同,所以多个父模板不能共用一次 parse 出来的结果,而是在每个被include
 * 的地方重新 parse
 *
 * 
 * 两种用法:
 * 1:只传入一个参数,参数必须是 String 常量,如果希望第一个参数是变量可以使用 #render 指令去实现
 *   #include("_hot.html")
 *
 * 2:传入任意多个参数,除第一个参数以外的所有参数必须是赋值表达式,用于实现参数传递功能
 *   #include("_hot.html", title = "热门新闻", list = newsList)
 *
 *   上例中传递了 title、list 两个参数,可以代替父模板中的 #set 指令传参方式
 *   并且此方式传入的参数只在子模板作用域有效,不会污染父模板作用域
 *
 *   这种传参方式有利于将子模板模块化,例如上例的调用改成如下的参数:
 *   #include("_hot.html", title = "热门项目", list = projectList)
 *   通过这种传参方式在子模板 _hot.html 之中,完全不需要修改对于 title 与 list
 *   这两个变量的处理代码,就实现了对 “热门项目” 数据的渲染
 * 
*/ public class Include extends Stat { private Assign[] assignArray; private Stat stat; public Include(Env env, ExprList exprList, String parentFileName, Location location) { int len = exprList.length(); if (len == 0) { throw new ParseException("The parameter of #include directive can not be blank", location); } // 第一个参数必须为 String 类型 Expr expr = exprList.getExpr(0); if (expr instanceof Const && ((Const)expr).isStr()) { } else { throw new ParseException("The first parameter of #include directive must be String, or use the #render directive", location); } // 其它参数必须为赋值表达式 if (len > 1) { for (int i = 1; i < len; i++) { if (!(exprList.getExpr(i) instanceof Assign)) { throw new ParseException("The " + (i + 1) + "th parameter of #include directive must be an assignment expression", location); } } } parseSubTemplate(env, ((Const)expr).getStr(), parentFileName, location); getAssignExpression(exprList); } private void parseSubTemplate(Env env, String fileName, String parentFileName, Location location) { String subFileName = getSubFileName(fileName, parentFileName); EngineConfig config = env.getEngineConfig(); // FileSource fileSource = new FileSource(config.getBaseTemplatePath(), subFileName, config.getEncoding()); ISource fileSource = config.getSourceFactory().getSource(config.getBaseTemplatePath(), subFileName, config.getEncoding()); try { Parser parser = new Parser(env, fileSource.getContent(), subFileName); if (config.isDevMode()) { env.addSource(fileSource); } this.stat = parser.parse().getActualStat(); } catch (Exception e) { // 文件路径不正确抛出异常时添加 location 信息 throw new ParseException(e.getMessage(), location, e); } } /** * 获取在父模板之下子模板的最终文件名,子模板目录相对于父模板文件目录来确定 * 以 "/" 打头则以 baseTemplatePath 为根,否则以父文件所在路径为根 */ public static String getSubFileName(String fileName, String parentFileName) { if (parentFileName == null) { return fileName; } if (fileName.startsWith("/")) { return fileName; } int index = parentFileName.lastIndexOf('/'); if (index == -1) { return fileName; } return parentFileName.substring(0, index + 1) + fileName; } private void getAssignExpression(ExprList exprList) { int len = exprList.length(); if (len > 1) { assignArray = new Assign[len - 1]; for (int i = 0; i < assignArray.length; i++) { assignArray[i] = (Assign)exprList.getExpr(i + 1); } } else { assignArray = null; } } public void exec(Env env, Scope scope, Writer writer) { scope = new Scope(scope); if (assignArray != null) { evalAssignExpression(scope); } stat.exec(env, scope, writer); scope.getCtrl().setJumpNone(); } private void evalAssignExpression(Scope scope) { Ctrl ctrl = scope.getCtrl(); try { ctrl.setLocalAssignment(); for (Assign assign : assignArray) { assign.eval(scope); } } finally { ctrl.setWisdomAssignment(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy