diff -r 44cb743c3a5b json/src/main/java/org/netbeans/html/json/impl/Bindings.java --- a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java Fri Dec 12 11:50:20 2014 +0100 +++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java Fri Dec 12 12:32:48 2014 +0100 @@ -42,6 +42,8 @@ */ package org.netbeans.html.json.impl; +import java.util.logging.Level; +import java.util.logging.Logger; import net.java.html.BrwsrCtx; import org.netbeans.html.json.spi.FunctionBinding; import org.netbeans.html.json.spi.PropertyBinding; @@ -53,6 +55,8 @@ * @author Jaroslav Tulach */ public final class Bindings { + private static final Logger LOG = Logger.getLogger(Bindings.class.getName()); + private Data data; private final Technology bp; @@ -105,7 +109,18 @@ } } - public void applyBindings() { + public void applyBindings(String id) { + if (bp instanceof Technology.ApplyId) { + Technology.ApplyId ai = (Technology.ApplyId) bp; + ai.applyBindings(id, data); + return; + } + if (id != null) { + LOG.log(Level.WARNING, + "Technology {0} does not implement ApplyId extension. Can''t apply to {1}. Applying globally.", + new Object[]{bp, id} + ); + } bp.applyBindings(data); } diff -r 44cb743c3a5b json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Fri Dec 12 11:50:20 2014 +0100 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Fri Dec 12 12:32:48 2014 +0100 @@ -504,12 +504,26 @@ + "In case of using Knockout technology, this means to \n" + "bind JSON like data in this model instance with Knockout tags in \n" + "the surrounding HTML page.\n" + + "@return returns this\n" + "*/\n" ); w.write(" public " + className + " applyBindings() {\n"); w.write(" proto.applyBindings();\n"); w.write(" return this;\n"); w.write(" }\n"); + w.write(" /** Activates this model instance in the current {@link \n" + + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n" + + "In case of using Knockout technology, this means to \n" + + "bind JSON like data in this model instance with Knockout tags in \n" + + "the surrounding HTML page.\n" + + "@param id identifies the element to apply the model to\n" + + "@return returns this\n" + + "*/\n" + ); + w.write(" public " + className + " applyBindings(String id) {\n"); + w.write(" proto.applyBindings(id);\n"); + w.write(" return this;\n"); + w.write(" }\n"); w.write(" public boolean equals(Object o) {\n"); w.write(" if (o == this) return true;\n"); w.write(" if (!(o instanceof " + className + ")) return false;\n"); diff -r 44cb743c3a5b json/src/main/java/org/netbeans/html/json/spi/Proto.java --- a/json/src/main/java/org/netbeans/html/json/spi/Proto.java Fri Dec 12 11:50:20 2014 +0100 +++ b/json/src/main/java/org/netbeans/html/json/spi/Proto.java Fri Dec 12 12:32:48 2014 +0100 @@ -193,7 +193,21 @@ * of the current model to the body element of the page. */ public void applyBindings() { - initBindings().applyBindings(); + initBindings().applyBindings(null); + } + + /** Initializes the associated model to the specified element's subtree. + * The technology is taken from the current {@link #getContext() context} and + * in case of knockout.js applies given bindings + * of the current model to the element of the page with 'id' attribute + * set to the specified id value. + * + * @param id the id of element to apply the binding to + * @since 1.1 + * @see Technology.ApplyId + */ + public void applyBindings(String id) { + initBindings().applyBindings(id); } /** Invokes the provided runnable in the {@link #getContext() context} diff -r 44cb743c3a5b json/src/main/java/org/netbeans/html/json/spi/Technology.java --- a/json/src/main/java/org/netbeans/html/json/spi/Technology.java Fri Dec 12 11:50:20 2014 +0100 +++ b/json/src/main/java/org/netbeans/html/json/spi/Technology.java Fri Dec 12 12:32:48 2014 +0100 @@ -173,4 +173,22 @@ */ public void valueHasMutated(D data, String propertyName, Object oldValue, Object newValue); } + + /** Apply technology bindings at selected subtree of the HTML page. + * Can be accessed via {@link Proto#applyBindings(java.lang.String)} or + * via method applyBindings(String) generated when one + * is using the {@link Model} annotation. + * + * @param the internal data for the technology + * @since 1.1 + */ + public static interface ApplyId extends Technology { + /** Applies given data to current context (usually an element on an + * HTML page). + * + * @param id the id of an element to apply the data to + * @param data the data to apply + */ + public void applyBindings(String id, D data); + } } diff -r 44cb743c3a5b json/src/test/java/net/java/html/json/MapModelTest.java --- a/json/src/test/java/net/java/html/json/MapModelTest.java Fri Dec 12 11:50:20 2014 +0100 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java Fri Dec 12 12:32:48 2014 +0100 @@ -76,6 +76,7 @@ @Test public void isThereABinding() throws Exception { Person p = Models.bind(new Person(), c).applyBindings(); + assertNull(t.appliedId, "Applied globally"); p.setFirstName("Jarda"); Map m = (Map)Models.toRaw(p); @@ -94,6 +95,10 @@ assertEquals(o.changes, 2, "Snd change"); } + @Test public void applyLocally() throws Exception { + Person p = Models.bind(new Person(), c).applyBindings("local"); + assertEquals(t.appliedId, "local", "Applied locally"); + } @Test public void dontNotifySameProperty() throws Exception { Person p = Models.bind(new Person(), c); @@ -293,7 +298,9 @@ } static final class MapTechnology - implements Technology>, Transfer { + implements Technology.ApplyId>, Transfer { + private Map appliedData; + private String appliedId; @Override public Map wrapModel(Object model) { @@ -329,6 +336,7 @@ @Override public void applyBindings(Map data) { + throw new UnsupportedOperationException("Never called!"); } @Override @@ -370,5 +378,11 @@ public void runSafe(Runnable r) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + + @Override + public void applyBindings(String id, Map data) { + this.appliedId = id; + this.appliedData = data; + } } } diff -r 44cb743c3a5b ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java --- a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java Fri Dec 12 11:50:20 2014 +0100 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java Fri Dec 12 12:32:48 2014 +0100 @@ -57,7 +57,7 @@ */ @Contexts.Id("ko4j") final class KOTech -implements Technology.BatchInit, Technology.ValueMutated { +implements Technology.BatchInit, Technology.ValueMutated, Technology.ApplyId { private Object[] jsObjects; private int jsIndex; @@ -131,7 +131,11 @@ @Override public void applyBindings(Object data) { - Object ko = Knockout.applyBindings(data); + applyBindings(null, data); + } + @Override + public void applyBindings(String id, Object data) { + Object ko = Knockout.applyBindings(id, data); if (ko instanceof Knockout) { ((Knockout)ko).hold(); } diff -r 44cb743c3a5b ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java Fri Dec 12 11:50:20 2014 +0100 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java Fri Dec 12 12:32:48 2014 +0100 @@ -131,12 +131,14 @@ Object model, String prop, Object oldValue, Object newValue ); - @JavaScriptBody(args = { "bindings" }, body = - "ko['cleanNode'](window['document']['body']);\n" + - "ko['applyBindings'](bindings);\n" + + @JavaScriptBody(args = { "id", "bindings" }, body = + "var d = window['document'];\n" + + "var e = id ? d['getElementById'](id) : d['body'];\n" + + "ko['cleanNode'](e);\n" + + "ko['applyBindings'](bindings, e);\n" + "return bindings['ko4j'];\n" ) - native static Object applyBindings(Object bindings); + native static Object applyBindings(String id, Object bindings); @JavaScriptBody(args = { "cnt" }, body = "var arr = new Array(cnt);\n" + diff -r 44cb743c3a5b src/main/javadoc/overview.html --- a/src/main/javadoc/overview.html Fri Dec 12 11:50:20 2014 +0100 +++ b/src/main/javadoc/overview.html Fri Dec 12 12:32:48 2014 +0100 @@ -93,7 +93,13 @@ module registers its {@link org.netbeans.html.json.spi.Transfer Java based JSON} and {@link org.netbeans.html.json.spi.WSTransfer WebSocket} implementations - under the name tyrus. + under the name tyrus. Also the particular DOM subtree + that a knockout.js model gets + applied can now be selected by using + {@link org.netbeans.html.json.spi.Proto#applyBindings(java.lang.String) + applyBindings(id)} with an id of an HTML element. +

+

Memory model when using Knockout bindings has been improved (required additions of two new methods: {@link org.netbeans.html.json.spi.PropertyBinding#weak()} and