edu.american.student.stonewall.display.html.framework.HTMLElement.java Source code

Java tutorial

Introduction

Here is the source code for edu.american.student.stonewall.display.html.framework.HTMLElement.java

Source

/**
 * Copyright 2013 Cameron Cook<br>
 * <br>
 * Licensed under the Apache License, Version 2.0 (the "License");<br>
 * you may not use this file except in compliance with the License.<br>
 * You may obtain a copy of the License at<br>
 * <br>
 * http://www.apache.org/licenses/LICENSE-2.0<br>
 * <br>
 * Unless required by applicable law or agreed to in writing, software<br>
 * distributed under the License is distributed on an "AS IS" BASIS,<br>
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<br>
 * See the License for the specific language governing permissions and<br>
 * limitations under the License.<br>
 */
package edu.american.student.stonewall.display.html.framework;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.american.student.stonewall.display.behavior.BehaviorType;
import edu.american.student.stonewall.display.behavior.Stone;
import edu.american.student.stonewall.display.css.framework.CSSProperty;
import edu.american.student.stonewall.display.css.framework.CSSSelector;
import edu.american.student.stonewall.display.html.util.Direction;
import edu.american.student.stonewall.display.html.util.Draggable;
import edu.american.student.stonewall.display.html.util.DropZone;
import edu.american.student.stonewall.display.html.util.Language;
import edu.american.student.stonewall.util.Browser;
import edu.american.student.stonewall.util.ResourceFinder;
import edu.american.student.stonewall.util.ResourceType;

/**
 * A abstract class that handles attributes for ANY HTML element
 * 
 * @author cam
 */
public abstract class HTMLElement {
    private Map<String, String> attributes = new HashMap<String, String>();
    private Map<String, List<Browser>> support = new HashMap<String, List<Browser>>();
    private Map<String, List<String>> validation = new HashMap<String, List<String>>();
    private CSSSelector selector;
    private String innerHTML = "";
    private String type;
    private final static Logger log = LoggerFactory.getLogger(HTMLElement.class);

    public HTMLElement(String id, String type) {
        this.type = type;
        selector = new CSSSelector(id.replace("-", "") + this.getClass().getName());
        this.setId(id.replace("-", ""));
    }

    /**
     * <p>
     * Generate the source to this element.<br>
     * <br>
     * Hint: You'll probably want to use getAttributes()
     * 
     * @return elementString
     * @throws ValidationException
     */
    public abstract String makeElement() throws ValidationException;

    protected void clearAttribute(String key) {
        if (attributes.containsKey(key)) {
            attributes.remove(key);
        }
        if (support.containsKey(key)) {
            support.remove(key);
        }
        if (validation.containsKey(key)) {
            validation.remove(key);
        }
    }

    protected void putAttribute(String key, String value) {
        attributes.put(key, value);
        if (support.containsKey(key)) {
            support.remove(key);
        }
    }

    public void addProperty(CSSProperty prop) {
        selector.addProperty(prop);
    }

    public void addProperties(CSSProperty... props) {
        for (CSSProperty prop : props) {
            selector.addProperty(prop);
        }
    }

    protected void putRequrement(String key, String requiredKey) {
        if (validation.containsKey(key)) {
            List<String> toModify = validation.get(key);
            toModify.add(requiredKey);
            validation.remove(key);
            validation.put(key, toModify);
        } else {
            List<String> toPut = new ArrayList<String>();
            toPut.add(requiredKey);
            validation.put(key, toPut);
        }
    }

    protected void putAttribute(String key, String value, Browser... browsers) {
        attributes.put(key, value);
        ArrayList<Browser> b = new ArrayList<Browser>();
        for (Browser browse : browsers) {
            b.add(browse);
        }
        support.put(key, b);
    }

    protected void checkSupport(HTMLElement element) {
        // get conf file to check
        List<Browser> toCheck = getBrowsersToCheck();
        for (Entry<String, String> entry : attributes.entrySet()) {
            String key = entry.getKey();
            List<Browser> supported = support.get(key);
            if (supported != null) {
                for (Browser b : toCheck) {
                    if (!supported.contains(b)) {
                        log.warn(b.getName() + " does not support " + key + " in "
                                + element.getClass().getSimpleName());
                    }
                }
            }
        }
    }

    private List<Browser> getBrowsersToCheck() {
        List<Browser> toReturn = new ArrayList<Browser>();
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("browsers.conf");
        if (is != null) {
            Scanner in = new Scanner(is);
            in.useDelimiter("\n");
            while (in.hasNext()) {
                String line = in.next();
                toReturn.add(Browser.getBrowser(line));
            }
        } else {
            log.warn("Ignoring browser check. browsers.conf not found!");
        }
        return toReturn;
    }

    protected void validate(HTMLElement element) throws ValidationException {
        Set<Entry<String, List<String>>> validationEntries = validation.entrySet();
        for (Entry<String, List<String>> entry : validationEntries) {
            String key = entry.getKey();
            List<String> requiredKeys = entry.getValue();
            for (String reqKey : requiredKeys) {
                if (!attributes.containsKey(reqKey)) {
                    throw new ValidationException("Attribute " + key + " requires attribute " + reqKey
                            + " in element " + element.getClass().getSimpleName());
                }
            }
        }
    }

    /**
     * The accesskey attribute specifies a shortcut key to activate/focus an
     * element.<br>
     * <br>
     * Example: accesskey="h"<br>
     * Implementation: IE, Firefox, Chrome, Safari
     * 
     * @param accessKey
     */
    public void setAccessKey(char accessKey) {
        clearAttribute("accesskey");
        putAttribute("accesskey", accessKey + "", Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.CHROME,
                Browser.SAFARI);
    }

    /**
     * The class attribute specifies one or more classnames for an element.<br>
     * The class attribute is mostly used to point to a class in a style sheet.
     * However, it can also be used by a JavaScript (via the HTML DOM) to make
     * changes to HTML elements with a specified class.<br>
     * <br>
     * Example: class="important"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param className
     */
    public void setClass(String className) {
        clearAttribute("class");
        putAttribute("class", className, Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA, Browser.CHROME,
                Browser.SAFARI);
    }

    /**
     * The contenteditable attribute specifies whether the content of an element
     * is editable or not.<br>
     * <br>
     * Example: contenteditable="true"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param editable
     */
    public void setContentEditable(boolean editable) {
        clearAttribute("contenteditable");
        putAttribute("contenteditable", editable + "", Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA,
                Browser.CHROME, Browser.SAFARI);
    }

    public void setContextMeu(String contextMenuName) {
        clearAttribute("contextmenu");
        putAttribute("contextmenu", contextMenuName);
    }

    /**
     * The dir attribute specifies the text direction of the element's content.<br>
     * <br>
     * Example: dir="rtl"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param direction
     */
    public void setDirection(Direction direction) {
        this.clearAttribute("dir");
        this.putAttribute("dir", direction.toString(), Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA,
                Browser.CHROME, Browser.SAFARI);
    }

    /**
     * The draggable attribute specifies whether an element is draggable or not.<br>
     * Tip: Links and images are draggable by default.<br>
     * Tip: The draggable attribute is often used in drag and drop operations.
     * Read w3c's HTML Drag and Drop tutorial to learn more.<br>
     * <br>
     * Example: draggable="true"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param draggable
     */
    public void setDraggable(Draggable draggable) {
        this.clearAttribute("draggable");
        this.putAttribute("draggable", draggable.toString(), Browser.INTERNET_EXPLORER, Browser.FIREFOX,
                Browser.OPERA, Browser.CHROME, Browser.SAFARI);
    }

    /**
     * The dropzone attribute specifies whether the dragged data is copied,
     * moved, or linked, when it is dropped on an element.<br>
     * <br>
     * Example: dropzone="copy"<br>
     * Implementation: NONE
     * 
     * @param zone
     */
    public void setDropZone(DropZone zone) {
        this.clearAttribute("dropzone");
        this.putAttribute("dropzone", zone.toString(), Browser.NONE);
    }

    /**
     * The hidden attribute is a boolean attribute.<br>
     * When present, it specifies that an element is not yet, or is no longer,
     * relevant.<br>
     * Browsers should not display elements that have the hidden attribute
     * specified.<br>
     * The hidden attribute can also be used to keep a user from seeing an
     * element until some other condition has been met (like selecting a
     * checkbox, etc.). Then, a JavaScript could remove the hidden attribute,
     * and make the element visible.<br>
     * <br>
     * Implementation: Firefox, Opera, Chrome, Safari
     * 
     * @param hidden
     */
    public void isHidden(boolean hidden) {
        this.clearAttribute("_hidden");
        if (hidden) {
            this.putAttribute("_hidden", "hidden", Browser.FIREFOX, Browser.OPERA, Browser.CHROME, Browser.SAFARI);
        }
    }

    /**
     * The id attribute specifies a unique id for an HTML element (the value
     * must be unique within the HTML document).<br>
     * The id attribute is most used to point to a style in a style sheet, and
     * by JavaScript (via the HTML DOM) to manipulate the element with the
     * specific id.<br>
     * <br>
     * Example: id="myHeader"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param id
     */
    public void setId(String id) {
        this.clearAttribute("id");
        this.putAttribute("id", id, Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA, Browser.CHROME,
                Browser.SAFARI);
        selector.setName(id);
    }

    /**
     * The lang attribute specifies the language of the element's content.<br>
     * <br>
     * Example: lang="fr"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param lang
     */
    public void setLanguage(Language lang) {
        this.clearAttribute("lang");
        this.putAttribute("lang", lang.toString(), Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA,
                Browser.CHROME, Browser.SAFARI);
    }

    /**
     * The spellcheck attribute specifies whether the element is to have its
     * spelling and grammar checked or not.<br>
     * The following can be spellchecked: <br>
     * Text values in input elements (not password)<br>
     * Text in textarea elements<br>
     * Text in editable elements<br>
     * <br>
     * Example: spellcheck="true"<br>
     * Implementation: Opera, Chrome, Safari
     * 
     * @param check
     */
    public void canSpellCheck(boolean check) {
        this.clearAttribute("spellcheck");
        this.putAttribute("spellcheck", check + "", Browser.OPERA, Browser.CHROME, Browser.SAFARI);
    }

    /**
     * The style attribute specifies an inline style for an element.<br>
     * The style attribute will override any style set globally, e.g. styles
     * specified in the style tag or in an external style sheet.<br>
     * <br>
     * Example: style="color: green"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param cssResource
     */
    public void setStyle(ResourceFinder cssResource) {
        this.clearAttribute("style");
        this.putAttribute("style", cssResource.toString(), Browser.INTERNET_EXPLORER, Browser.FIREFOX,
                Browser.OPERA, Browser.CHROME, Browser.SAFARI);
    }

    /**
     * The tabindex attribute specifies the tab order of an element (when the
     * "tab" button is used for navigating).<br>
     * <br>
     * Example: tabindex="1"<br>
     * Implementation: IE, Firefox, Opera, Chrome
     * 
     * @param index
     */
    public void setTabIndex(int index) {
        this.clearAttribute("tabindex");
        this.putAttribute("tabindex", index + "", Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA,
                Browser.CHROME);
    }

    /**
     * The title attribute specifies extra information about an element.<br>
     * The information is most often shown as a tooltip text when the mouse
     * moves over the element.<br>
     * <br>
     * Example: title="World Health Organization"<br>
     * Implementation: IE, Firefox, Opera, Chrome, Safari
     * 
     * @param title
     */
    public void setElementTitle(String title) {
        this.clearAttribute("title");
        this.putAttribute("title", title, Browser.INTERNET_EXPLORER, Browser.FIREFOX, Browser.OPERA, Browser.CHROME,
                Browser.SAFARI);
    }

    public void addBehavior(BehaviorType type, Stone s, HTMLElement ranFrom) {
        this.clearAttribute(type.toString());
        s.saveResource();
        this.putAttribute(type.toString(), ranFrom.getAttribute("id") + "()", type.getSupportedBrowsers());
    }

    /**
     * Returns a String of attributes delimited by a space<br>
     * A header space is included<br>
     * Tip: Use this when implementing makeElement()
     * 
     * @return a string of attributes delimited by a space
     */
    public String getAttributes() {
        try {
            if (!selector.isEmpty()) {
                selector.setName(this.getAttribute("id"));
                ResourceFinder cssResource = saveResource(selector.makeSelector());
                this.setStyle(cssResource);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        StringBuilder sb = new StringBuilder();
        Set<Entry<String, String>> set = attributes.entrySet();
        for (Entry<String, String> entry : set) {
            String key = entry.getKey();
            if (key.startsWith("_")) {
                sb.append(" " + key.replace("_", "") + " ");
            } else {
                String value = entry.getValue();
                sb.append(" " + key + "=\"" + value + "\" ");
            }
        }
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - 1);
        } else {
            return sb.toString();
        }
    }

    public Set<Entry<String, String>> getAttributesMap() {
        return attributes.entrySet();
    }

    private ResourceFinder saveResource(String selectionSource) throws IOException, URISyntaxException {
        File resFile = new File("src/main/resources/res/");
        File cssDir = new File(resFile.getAbsolutePath() + File.separator + "css");
        if (!cssDir.exists()) {
            cssDir.mkdirs();
        }
        File toSave = new File(cssDir.getAbsolutePath() + File.separator + this.getAttribute("id") + ".css");
        FileUtils.writeStringToFile(toSave, selectionSource);
        return new ResourceFinder(this.getAttribute("id") + ".css", ResourceType.CSS);
    }

    public String getAttribute(String attr) {
        return this.attributes.get(attr);
    }

    public List<CSSProperty> getLinkProperties() {
        return selector.getLinkProperties();
    }

    public List<CSSProperty> getVisitedProperties() {
        return selector.getVisitedProperties();
    }

    public List<CSSProperty> getActiveProperties() {
        return selector.getActiveProperties();
    }

    public List<CSSProperty> getHoverProperties() {
        return selector.getHoverProperties();
    }

    public List<CSSProperty> getFocusProperties() {
        return selector.getFocusProperties();
    }

    public List<CSSProperty> getFirstLetterProperties() {
        return selector.getFirstLetterProperties();
    }

    public List<CSSProperty> getFirstLineProperties() {
        return selector.getFirstLineProperties();
    }

    public List<CSSProperty> getFirstChildProperties() {
        return selector.getFirstChildProperties();
    }

    public List<CSSProperty> getBeforeProperties() {
        return selector.getBeforeProperties();
    }

    public List<CSSProperty> getAfterProperties() {
        return selector.getActiveProperties();
    }

    public List<CSSProperty> getGenericProperties() {
        return selector.getGenericProperties();
    }

    public String getInnerHTML() {
        return innerHTML;
    }

    public void setInnerHTML(String html) {
        this.innerHTML = html;
    }

    public String getHTMLType() {
        return this.type;
    }

    public CSSSelector getSelector() {
        return selector;
    }
}