xapi.ui.html.impl.StyleServiceDefault Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xapi-dev Show documentation
Show all versions of xapi-dev Show documentation
Everything needed to run a comprehensive dev environment.
Just type X_ and pick a service from autocomplete;
new dev modules will be added as they are built.
The only dev service not included in the uber jar is xapi-dev-maven,
as it includes all runtime dependencies of maven, adding ~4 seconds to build time,
and 6 megabytes to the final output jar size (without xapi-dev-maven, it's ~1MB).
The newest version!
/**
*
*/
package xapi.ui.html.impl;
import static xapi.collect.X_Collect.newStringMap;
import java.util.Arrays;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import elemental.client.Browser;
import elemental.dom.Node;
import elemental.html.StyleElement;
import xapi.annotation.inject.SingletonDefault;
import xapi.collect.api.StringTo;
import xapi.ui.api.StyleService;
/**
* @author "James X. Nelson ([email protected])"
*
*/
@SuppressWarnings("rawtypes")
@SingletonDefault(
implFor = StyleService.class)
public class StyleServiceDefault implements
StyleService {
private ScheduledCommand printPendingCss;
private final StringTo pendingCss = newStringMap(String.class);
private final StringTo liveCss = newStringMap(StyleElement.class);
@Override
@SuppressWarnings("unchecked")
public T addCss(final String css, final int priority) {
if (printPendingCss == null) {
css(css);
}
final String key = Integer.toString(priority);
final String was = pendingCss.get(key);
if (was == null) {
pendingCss.put(key, css);
} else {
pendingCss.put(key, was + "\n" + css);
}
return (T) this;
}
protected void css(final String css) {
printPendingCss = new ScheduledCommand() {
@Override
public void execute() {
flushCss();
}
};
Scheduler.get().scheduleFinally(printPendingCss);
}
@Override
public void flushCss() {
printPendingCss = null;
final StringTo pending = pendingCss;
synchronized (pendingCss) {
final String[] keys = pending.keyArray();
Arrays.sort(keys);
for (final String key : keys) {
final String css = pending.get(key);
final StyleElement style = getStyleElement(key);
appendStyle(style, css);
}
}
pendingCss.clear();
}
private native void appendStyle(StyleElement style, String css)
/*-{
if (style.styleSheet) {// IE
style.styleSheet.cssText = style.styleSheet.cssText + css;
} else {
style.appendChild($doc.createTextNode(css));
}
}-*/;
private StyleElement getStyleElement(final String priority) {
StyleElement style = liveCss.get(priority);
if (style == null) {
final Node head = Browser.getDocument().getElementsByTagName("head")
.item(0);
assert head != null : "The host HTML page does not have a element"
+ " which is required by CssService";
style = Browser.getDocument().createStyleElement();
style.setAttribute("language", "text/css");
// need to insert a new element
final String[] keys = liveCss.keyArray();
try {
if (keys.length == 0) {
head.appendChild(style);
} else {
Arrays.sort(keys);
final String largest = keys[keys.length - 1];
final int distanceFromEnd = largest.compareTo(priority);
if (distanceFromEnd < 0) {
head.appendChild(style);
} else {
// Find the tag ahead of our priority so we can insert before it
String current = keys[0];
final int distanceFromBeginning = priority.compareTo(current);
if (distanceFromBeginning < 0) {
head.insertBefore(style, liveCss.get(current));
} else {
// iterative search
if (distanceFromBeginning > distanceFromEnd) {
// search backwards
current = largest;
for (int i = keys.length; --i > 0;) {
final String next = keys[i];
if (next.compareTo(priority) < 0) {
final StyleElement winner = liveCss.get(current);
head.insertBefore(style, winner);
return style;
}
current = next;
}
throw new RuntimeException(
"Failed to inject stylesheet @ priority " + priority
+ " into " + liveCss);
} else {
// search forwards
for (int i = 1, m = keys.length; i < m; ++i) {
current = keys[i];
if (current.compareTo(priority) > 0) {
final StyleElement winner = liveCss.get(current);
head.insertBefore(style, winner);
return style;
}
}
throw new RuntimeException(
"Failed to inject stylesheet @ priority " + priority
+ " into " + liveCss);
}
}
}
}
} finally {
liveCss.put(priority, style);
}
}
return style;
}
}