Cutelee 6.1.0
extends.cpp
1/*
2 This file is part of the Cutelee template system.
3
4 Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either version
9 2.1 of the Licence, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library. If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21#include "extends.h"
22
23#include "block.h"
24#include "blockcontext.h"
25#include "engine.h"
26#include "exception.h"
27#include "nodebuiltins_p.h"
28#include "parser.h"
29#include "rendercontext.h"
30#include "template.h"
31#include "util.h"
32
33using namespace Cutelee;
34
35ExtendsNodeFactory::ExtendsNodeFactory(QObject *parent)
36 : AbstractNodeFactory(parent)
37{
38}
39
40Node *ExtendsNodeFactory::getNode(const QString &tagContent, Parser *p) const
41{
42 const auto expr = smartSplit(tagContent);
43
44 if (expr.size() != 2)
46 TagSyntaxError,
47 QStringLiteral("Error: Include tag takes only one argument"));
48
49 FilterExpression fe(expr.at(1), p);
50
51 auto n = new ExtendsNode(fe, p);
52
53 auto t = qobject_cast<TemplateImpl *>(p->parent());
54
55 if (!t)
57 TagSyntaxError, QStringLiteral("Extends tag is not in a template."));
58
59 const auto nodeList = p->parse(t);
60 n->setNodeList(nodeList);
61
62 if (t->findChildren<ExtendsNode *>().size() > 1) {
64 TagSyntaxError,
65 QStringLiteral("Extends tag may only appear once in a template."));
66 }
67
68 return n;
69}
70
71ExtendsNode::ExtendsNode(const FilterExpression &fe, QObject *parent)
72 : Node(parent), m_filterExpression(fe)
73{
74}
75
76ExtendsNode::~ExtendsNode() {}
77
78static QHash<QString, BlockNode *> createNodeMap(const QList<BlockNode *> &list)
79{
80 QHash<QString, BlockNode *> map;
81
82 auto it = list.constBegin();
83 const auto end = list.constEnd();
84
85 for (; it != end; ++it) {
86 map.insert((*it)->name(), *it);
87 }
88
89 return map;
90}
91
92void ExtendsNode::setNodeList(const NodeList &list)
93{
94 m_list = list;
95
96 const auto blockList = m_list.findChildren<BlockNode *>();
97 m_blocks = createNodeMap(blockList);
98}
99
100Template ExtendsNode::getParent(Context *c) const
101{
102 const auto parentVar = m_filterExpression.resolve(c);
103 if (parentVar.userType() == qMetaTypeId<Cutelee::Template>()) {
104 return parentVar.value<Template>();
105 }
106
107 QString parentName = getSafeString(parentVar);
108
109 auto ti = containerTemplate();
110
111 const auto t = ti->engine()->loadByName(parentName);
112
113 if (!t)
114 throw Cutelee::Exception(
115 TagSyntaxError,
116 QStringLiteral("Template not found %1").arg(parentName));
117
118 if (t->error())
119 throw Cutelee::Exception(t->error(), t->errorString());
120
121 return t;
122}
123
125{
126 const auto parentTemplate = getParent(c);
127
128 if (!parentTemplate) {
129 throw Cutelee::Exception(TagSyntaxError,
130 QStringLiteral("Cannot load template."));
131 }
132
133 QVariant &variant = c->renderContext()->data(0);
134 auto blockContext = variant.value<BlockContext>();
135 blockContext.addBlocks(m_blocks);
136 variant.setValue(blockContext);
137
138 const auto nodeList = parentTemplate->nodeList();
139
140 const auto parentBlocks
141 = createNodeMap(parentTemplate->findChildren<BlockNode *>());
142
143 for (auto n : nodeList) {
144 auto tn = qobject_cast<TextNode *>(n);
145 if (!tn) {
146 auto en = qobject_cast<ExtendsNode *>(n);
147 if (!en) {
148 blockContext.addBlocks(parentBlocks);
149 variant.setValue(blockContext);
150 }
151 break;
152 }
153 }
154 variant.setValue(blockContext);
155 parentTemplate->nodeList().render(stream, c);
156
157 auto nodes = parentTemplate->findChildren<BlockNode *>();
158 blockContext.remove(nodes);
159 variant.setValue(blockContext);
160}
161
162void ExtendsNode::appendNode(Node *node)
163{
164 m_list.append(node);
165 node->setParent(parent());
166}
Base class for all NodeFactories.
Definition node.h:300
Q_INVOKABLE QStringList smartSplit(const QString &str) const
Definition node.cpp:202
The Context class holds the context to render a Template with.
Definition context.h:119
RenderContext * renderContext() const
Definition context.cpp:214
An exception for use when implementing template tags.
Definition exception.h:85
A FilterExpression object represents a filter expression in a template.
QVariant resolve(OutputStream *stream, Context *c) const
A list of Nodes with some convenience API for rendering them.
Definition node.h:148
QList< T > findChildren()
Definition node.h:190
void append(Cutelee::Node *node)
Definition node.cpp:149
Base class for all nodes.
Definition node.h:78
TemplateImpl * containerTemplate() const
Definition node.cpp:107
The OutputStream class is used to render templates to a QTextStream.
The Parser class processes a string template into a tree of nodes.
Definition parser.h:49
NodeList parse(Node *parent, const QStringList &stopAt={})
Definition parser.cpp:180
QVariant & data(const Node *const scopeNode)
The Template class is a tree of nodes which may be rendered.
Definition template.h:95
Node * getNode(const QString &tagContent, Parser *p) const override
Definition extends.cpp:40
void render(OutputStream *stream, Context *c) const override
Definition extends.cpp:124
The Cutelee namespace holds all public Cutelee API.
Definition Mainpage.dox:8
Cutelee::SafeString getSafeString(const QVariant &input)
Definition util.cpp:108
Utility functions used throughout Cutelee.