Java tutorial
/** * 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; } }