001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.console.freemarker;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.io.*;
022import java.util.*;
023
024import freemarker.core.*;
025import freemarker.template.*;
026
027/**
028 * The {@code <@main/>} console FreeMarker directive: the positional placeholder that renders the captured page body
029 * inside exactly one {@code <main class="jc-main">}.
030 *
031 * <p>
032 * {@code <@main/>} is a position marker. Markup authored between {@code <@console>} and {@code <@main/>} becomes the
033 * {@code header.slots.banner} template, and the page's cards render into {@code <main>} in the shell. It is
034 * self-closing &mdash; it takes no body of its own, and it has no attributes.
035 *
036 * @since 10.0.0
037 */
038public final class MainDirectiveModel implements TemplateDirectiveModel {
039
040   /** The shared-variable name this directive registers under. */
041   public static final String NAME = "main";
042
043   static final Set<String> ATTRS = Set.of();
044
045   MainDirectiveModel() {}
046
047   @Override
048   @SuppressWarnings({
049      "unchecked" // FreeMarker's raw params Map is String-keyed by contract.
050   })
051   public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
052         TemplateDirectiveBody body) throws TemplateException, IOException {
053      Map<String, TemplateModel> p = params;
054      if (p.containsKey("format"))
055         throw FtlAttrLists.reject("<@main> has no format= attribute.");
056      FtlAttrLists.rejectUnknown(p, NAME, ATTRS);
057      if (nn(body))
058         throw FtlAttrLists.reject("<@main/> is self-closing; the page body is the main content and takes no nested body.");
059
060      var cap = PageCapture.get(env);
061      if (n(cap) || ! cap.consoleOpen)
062         throw FtlAttrLists.reject(f("<@%s> must be nested inside <@console>.", NAME));
063      cap.markMain();
064   }
065}