/** * Copyright (C) 2010-2017 Structr GmbH * * This file is part of Structr <http://structr.org>. * * Structr is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Structr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Structr. If not, see <http://www.gnu.org/licenses/>. */ package org.structr.web.entity; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import org.structr.common.PropertyView; import org.structr.common.SecurityContext; import org.structr.common.ThreadLocalMatcher; import org.structr.common.error.EmptyPropertyToken; import org.structr.common.error.ErrorBuffer; import org.structr.common.error.FrameworkException; import org.structr.core.entity.AbstractNode; import org.structr.core.property.ConstantBooleanProperty; import org.structr.core.property.EndNodes; import org.structr.core.property.Property; import org.structr.core.property.StringProperty; import org.structr.schema.SchemaService; import org.structr.web.entity.dom.DOMNode; import org.structr.web.entity.dom.Page; import org.structr.web.entity.relation.ImageWidget; import org.structr.web.importer.Importer; import org.structr.web.maintenance.deploy.DeploymentCommentHandler; import org.structr.web.property.UiNotion; /** * * */ public class Widget extends AbstractNode { private static final ThreadLocalMatcher threadLocalTemplateMatcher = new ThreadLocalMatcher("\\[[^\\]]+\\]"); public static final Property<String> source = new StringProperty("source").cmis(); public static final Property<String> description = new StringProperty("description").cmis(); public static final Property<String> configuration = new StringProperty("configuration").cmis(); public static final Property<String> treePath = new StringProperty("treePath").cmis().indexed(); public static final Property<List<Image>> pictures = new EndNodes<>("pictures", ImageWidget.class, new UiNotion()); public static final Property<Boolean> isWidget = new ConstantBooleanProperty("isWidget", true); public static final org.structr.common.View uiView = new org.structr.common.View(Widget.class, PropertyView.Ui, type, name, source, description, configuration, pictures, treePath, isWidget ); public static final org.structr.common.View publicView = new org.structr.common.View(Widget.class, PropertyView.Public, type, name, source, description, configuration, pictures, treePath, isWidget ); // register this type as an overridden builtin type static { SchemaService.registerBuiltinTypeOverride("Widget", Widget.class.getName()); } public static void expandWidget(SecurityContext securityContext, Page page, DOMNode parent, String baseUrl, Map<String, Object> parameters, final boolean processDeploymentInfo) throws FrameworkException { String _source = (String)parameters.get("source"); ErrorBuffer errorBuffer = new ErrorBuffer(); if (_source == null) { errorBuffer.add(new EmptyPropertyToken(Widget.class.getSimpleName(), source)); } else { // check source for mandatory parameters Matcher matcher = threadLocalTemplateMatcher.get(); // initialize with source matcher.reset(_source); while (matcher.find()) { final String group = matcher.group(); final String source = group.substring(1, group.length() - 1); final ReplacementInfo info = new ReplacementInfo(source); String key = info.getKey(); Object value = parameters.get(key); if (value != null) { // replace and restart matching process _source = _source.replace(group, value.toString()); matcher.reset(_source); } } } if (!errorBuffer.hasError()) { Importer importer = new Importer(securityContext, _source, baseUrl, null, false, false); if (processDeploymentInfo) { importer.setIsDeployment(true); importer.setCommentHandler(new DeploymentCommentHandler()); } importer.parse(true); importer.createChildNodes(parent, page, true); } else { // report error to ui throw new FrameworkException(422, "Unable to import the given source code", errorBuffer); } } public static class ReplacementInfo { private ArrayList<String> options = new ArrayList<>(); private String key = null; private boolean hasOptions = false; public ReplacementInfo(final String value) { this.key = value; if (value.contains(":")) { final String[] parts = value.split("[:]+"); this.key = parts[0]; if (parts[1].contains(",")) { final String[] opts = parts[1].split("[,]+"); final int count = opts.length; for (int i=0; i<count; i++) { final String trimmedPart = opts[i].trim(); if (!trimmedPart.isEmpty()) { options.add(trimmedPart); } } hasOptions = true; } } } public String getKey() { return key; } public ArrayList<String> getOptions() { return options; } public boolean hasOptions() { return hasOptions; } } }