Skip to content

Commit

Permalink
Adding component architecture and rework html editor
Browse files Browse the repository at this point in the history
  • Loading branch information
nurv authored and pedrosan7os committed Dec 10, 2015
1 parent a7363d3 commit 5ca1752
Show file tree
Hide file tree
Showing 24 changed files with 2,256 additions and 185 deletions.
27 changes: 26 additions & 1 deletion bennu-toolkit/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<filtering>false</filtering>
<targetPath>META-INF/resources</targetPath>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/webapp</directory>
<includes>
Expand Down Expand Up @@ -58,6 +61,7 @@
<jsSourceFile>datetime.js</jsSourceFile>
<jsSourceFile>codeEditor.js</jsSourceFile>
<jsSourceFile>spinner.js</jsSourceFile>
<jsSourceFile>browser.js</jsSourceFile>
<jsSourceFile>libs/MutationObserverPolyfill.js</jsSourceFile>
<jsSourceFile>mutations.js</jsSourceFile>
</jsSourceFiles>
Expand Down Expand Up @@ -93,6 +97,7 @@
<jsSourceFile>datetime.js</jsSourceFile>
<jsSourceFile>codeEditor.js</jsSourceFile>
<jsSourceFile>spinner.js</jsSourceFile>
<jsSourceFile>browser.js</jsSourceFile>
<jsSourceFile>bennu-angular.js</jsSourceFile>
</jsSourceFiles>
<webappTargetDir>${project.build.outputDirectory}/META-INF/resources/</webappTargetDir>
Expand All @@ -115,13 +120,33 @@
<groupId>org.fenixedu</groupId>
<artifactId>bennu-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>ace</artifactId>
<version>1.1.9</version>
</dependency>
</dependencies>
<dependency>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>owasp-java-html-sanitizer</artifactId>
<version>r239</version>
<exclusions>
<exclusion>
<artifactId>jsr305</artifactId>
<groupId>com.google.code.findbugs</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<repositories>
<repository>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.fenixedu.bennu.toolkit;

import java.util.Locale;
import java.util.function.Function;

import org.fenixedu.commons.i18n.LocalizedString;
import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;

public class Sanitization {

private static PolicyFactory TOOLKIT_SANITIZER = new HtmlPolicyBuilder()
.allowStyling()
.allowStandardUrlProtocols()
.allowElements("a", "b", "blockquote", "br", "caption", "cite", "code", "col", "colgroup", "dd", "dl", "dt", "em",
"h1", "h2", "h3", "h4", "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small", "strike", "strong",
"sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", "ul", "div", "font", "span")
.allowAttributes("href")
.onElements("a")
.allowAttributes("title")
.onElements("a")
.allowAttributes("cite")
.onElements("blockquote")
.allowAttributes("span")
.onElements("col")
.allowAttributes("width")
.onElements("col")
.allowAttributes("span")
.onElements("colgroup")
.allowAttributes("width")
.onElements("colgroup")
.allowAttributes("align")
.onElements("img")
.allowAttributes("alt")
.onElements("img")
.allowAttributes("height")
.onElements("img")
.allowAttributes("src")
.onElements("img")
.allowAttributes("title")
.onElements("img")
.allowAttributes("width")
.onElements("img")
.allowAttributes("start")
.onElements("ol")
.allowAttributes("type")
.onElements("ol")
.allowAttributes("cite")
.onElements("q")
.allowAttributes("summary")
.onElements("table")
.allowAttributes("width")
.onElements("table")
.allowAttributes("abbr")
.onElements("td")
.allowAttributes("axis")
.onElements("td")
.allowAttributes("colspan")
.onElements("td")
.allowAttributes("rowspan")
.onElements("td")
.allowAttributes("width")
.onElements("td")
.allowAttributes("abbr")
.onElements("th")
.allowAttributes("axis")
.onElements("th")
.allowAttributes("colspan")
.onElements("th")
.allowAttributes("rowspan")
.onElements("th")
.allowAttributes("scope")
.onElements("th")
.allowAttributes("width")
.onElements("th")
.allowAttributes("type")
.onElements("ul")
.allowAttributes("class", "color")
.globally()
.allowAttributes("bennu-component", "component-resizable", "data-x", "data-y", "data-height", "data-width",
"data-source", "data-metadata")
.onElements("div", "span", "a", "img", "h1", "h2", "h3", "h4", "h5", "h6", "p", "table").allowElements().toFactory();

private static Function<String, String> sanitizer = (origin) -> TOOLKIT_SANITIZER.sanitize(origin);

public static LocalizedString sanitize(LocalizedString origin) {
LocalizedString result = new LocalizedString();

for (Locale l : origin.getLocales()) {
result = result.with(l, sanitize(origin.getContent(l)));
}

return result;
}

public static String sanitize(String original) {
return sanitizer.apply(original);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.fenixedu.bennu.toolkit;

import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

import org.fenixedu.bennu.toolkit.components.Component;
import org.fenixedu.bennu.toolkit.components.ToolkitComponent;

@HandlesTypes({ ToolkitComponent.class })
public class ToolkitInitializer implements ServletContainerInitializer {

@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
if (c != null) {
for (Class<?> type : c) {
if (type.isAnnotationPresent(ToolkitComponent.class)) {
Component.register(type);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.fenixedu.bennu.toolkit.components;

import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

import org.fenixedu.commons.i18n.LocalizedString;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;

public abstract class Component {

private final static Logger LOGGER = LoggerFactory.getLogger(Component.class);

private static Map<String, Component> COMPONENTS = Maps.newHashMap();

public abstract Element process(Element element);

public static Component getComponent(String key) {
return Component.COMPONENTS.get(key);
}

public static Collection<Component> getComponents() {
return COMPONENTS.values();
}

public static String process(String origin) {
Document doc = Jsoup.parse(origin);
Elements components = doc.select("[bennu-component]");

for (Element component : components) {
String key = component.attr("bennu-component");
Optional.ofNullable(COMPONENTS.get(key)).ifPresent(x -> component.replaceWith(x.process(component)));
}

return doc.toString();
}

public static void register(Class<?> type) {
ToolkitComponent annotation = type.getAnnotation(ToolkitComponent.class);

try {
COMPONENTS.put(annotation.key(), (Component) type.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
LOGGER.error("Error while instancing a toolkit component", e);
}
}

public static LocalizedString process(LocalizedString origin) {
return origin.map(Component::process);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.fenixedu.bennu.toolkit.components;

import org.jsoup.nodes.Element;
import org.jsoup.parser.Tag;

@ToolkitComponent(key = "image", name = "Image", description = "Adds images",
editorFiles = { "/bennu-toolkit/js/components/images.js" })
public class ImageComponent extends Component {

@Override
public Element process(Element element) {

Element image = new Element(Tag.valueOf("img"), "");

String width = "";

if (element.hasAttr("data-width") && !element.attr("data-width").equals("")) {
width = element.attr("data-width");
}

String height = "";

if (element.hasAttr("data-height") && !element.attr("data-height").equals("")) {
height = element.attr("data-height");
}

image.attr("width", width);
image.attr("height", height);
image.attr("src", element.attr("data-source"));

return image;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.fenixedu.bennu.toolkit.components;

import org.jsoup.nodes.Element;

@ToolkitComponent(key = "link", name = "Link", description = "Add a link to some place",
editorFiles = { "/bennu-toolkit/js/components/link.js" })
public class LinkComponent extends Component {

@Override
public Element process(Element element) {
element.removeAttr("bennu-component");
return element;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.fenixedu.bennu.toolkit.components;

import org.jsoup.nodes.Element;

@ToolkitComponent(key = "table", name = "Table", description = "Adds a table",
editorFiles = { "/bennu-toolkit/js/components/table.js" })
public class TableComponent extends Component {

@Override
public Element process(Element element) {
return element;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.fenixedu.bennu.toolkit.components;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ToolkitComponent {
String key();

String name();

String description();

String[] editorFiles();

String[] viewerFiles() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.fenixedu.bennu.toolkit.components;

import java.io.IOException;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.fenixedu.bennu.core.rest.BennuRestResource;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

@Path("/bennu-toolkit/")
public class ToolkitResources extends BennuRestResource {

private JsonArray cachedResponse;

@GET
@Path("components")
@Produces({ MediaType.APPLICATION_JSON })
public Response components() throws IOException {
if (cachedResponse == null) {
cachedResponse = new JsonArray();

for (Component component : Component.getComponents()) {
JsonObject obj = new JsonObject();

ToolkitComponent annotation = component.getClass().getAnnotation(ToolkitComponent.class);

obj.addProperty("key", annotation.key());
obj.addProperty("name", annotation.name());
obj.addProperty("description", annotation.description());
JsonArray array2 = new JsonArray();

for (String file : annotation.editorFiles()) {
JsonPrimitive element = new JsonPrimitive(file);
array2.add(element);
}

obj.add("files", array2);
cachedResponse.add(obj);
}

}
return Response.ok(toJson(cachedResponse)).build();
}
}
Loading

0 comments on commit 5ca1752

Please sign in to comment.