From 8b656148271fea2e31d06ff03e102b6e4e376fff Mon Sep 17 00:00:00 2001 From: hns Date: Mon, 6 Apr 2009 05:54:26 +0000 Subject: [PATCH] Implement skin inheritance via <% .extends skinname %>. Lookup code is now incredibly convoluted for what it does and needs some streamlining. --- src/helma/framework/core/Prototype.java | 18 ++++++++++----- src/helma/framework/core/Skin.java | 28 ++++++++++++++++++++--- src/helma/framework/core/SkinManager.java | 22 ++++++++++++++---- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/helma/framework/core/Prototype.java b/src/helma/framework/core/Prototype.java index 17d5994c..5a552df8 100644 --- a/src/helma/framework/core/Prototype.java +++ b/src/helma/framework/core/Prototype.java @@ -341,19 +341,25 @@ public final class Prototype { skin = Skin.getSkin(res, app); if (skin.hasMainskin()) break; + String extendz = skin.getExtends(); + if (extendz != null && extendz != skinName) + return getSkin(extendz, null, null); res = res.getOverloadedResource(); } if (parentName != null) { Skin parentSkin = null; - Resource parent = skinMap.getResource(parentName); - while (parent != null) { - parentSkin = Skin.getSkin(parent, app); + Resource parentResource = skinMap.getResource(parentName); + while (parentResource != null) { + parentSkin = Skin.getSkin(parentResource, app); if (parentSkin.hasSubskin(subName)) break; - parent = parent.getOverloadedResource(); + String extendz = parentSkin.getExtends(); + if (extendz != null && extendz != parentName) + return getSkin(extendz, extendz, subName); + parentResource = parentResource.getOverloadedResource(); } - if (parent != null) { - if (res != null && app.getResourceComparator().compare(res, parent) > 0) + if (parentResource != null) { + if (res != null && app.getResourceComparator().compare(res, parentResource) > 0) return skin; else return parentSkin.getSubskin(subName); diff --git a/src/helma/framework/core/Skin.java b/src/helma/framework/core/Skin.java index 8bef294f..5edc4a00 100644 --- a/src/helma/framework/core/Skin.java +++ b/src/helma/framework/core/Skin.java @@ -42,6 +42,8 @@ public final class Skin { private HashSet sandbox; private HashMap subskins; private Skin parentSkin = this; + private String extendz = null; + private boolean hasContent = false; static private final int PARSE_MACRONAME = 0; static private final int PARSE_PARAM = 1; @@ -157,10 +159,16 @@ public final class Skin { length = i; break; } else { + if (!macro.isCommentMacro) { + hasContent = true; + } partBuffer.add(macro); } i = macro.end - 1; } else { + if (!hasContent && !Character.isWhitespace(source[i])){ + hasContent = true; + } escape = source[i] == '\\' && !escape; } } @@ -181,7 +189,7 @@ public final class Skin { * @return true if this skin contains a main skin */ public boolean hasMainskin() { - return length - offset > 0 || subskins == null; + return hasContent; } /** @@ -212,6 +220,10 @@ public final class Skin { (String[]) subskins.keySet().toArray(new String[0]); } + public String getExtends() { + return extendz; + } + /** * Get the raw source text this skin was parsed from */ @@ -328,8 +340,6 @@ public final class Skin { } } - - class Macro { final int start, end; String name; @@ -389,6 +399,18 @@ public final class Skin { handlerType = HANDLER_PARAM; } } + + if (".extends".equals(name)) { + if (parentSkin != Skin.this) { + throw new RuntimeException("Found .extends in subskin"); + } + if (positionalParams == null || positionalParams.size() < 1 + || !(positionalParams.get(0) instanceof String)) { + throw new RuntimeException(".extends requires an unnamed string parameter"); + } + extendz = (String) positionalParams.get(0); + isCommentMacro = true; // don't render + } } private int parse(int macroOffset, boolean lenient) { diff --git a/src/helma/framework/core/SkinManager.java b/src/helma/framework/core/SkinManager.java index df07b621..47ab5cec 100644 --- a/src/helma/framework/core/SkinManager.java +++ b/src/helma/framework/core/SkinManager.java @@ -51,7 +51,7 @@ public final class SkinManager implements FilenameFilter { Skin skin; Prototype proto = prototype; - // if name contains dot, this might be a substring of some other string + // if name contains #, this may be a subskin of some other skin String parentName = null, subskinName = null; int hash = skinname.indexOf('#'); if (hash > -1) { @@ -65,15 +65,27 @@ public final class SkinManager implements FilenameFilter { if (skinpath != null) { for (int i = 0; i < skinpath.length; i++) { skin = getSkinInPath(skinpath[i], proto.getName(), skinname); - if (skin != null && skin.hasMainskin()) { + if (skin != null) { // check if skin skin contains main skin - return skin; + if (skin.hasMainskin()) { + return skin; + } + String extendz = skin.getExtends(); + if (extendz != null && !extendz.equals(skinname)) { + return getSkin(prototype, extendz, skinpath); + } } else if (parentName != null) { // get parent skin skin = getSkinInPath(skinpath[i], proto.getName(), parentName); // check if it contains subskin - if (skin != null && skin.hasSubskin(subskinName)) { - return skin.getSubskin(subskinName); + if (skin != null) { + if (skin.hasSubskin(subskinName)) { + return skin.getSubskin(subskinName); + } + String extendz = skin.getExtends(); + if (extendz != null && !extendz.equals(skinname)) { + return getSkin(prototype, extendz + "#" + subskinName, skinpath); + } } } }