[Commits] r2130 - in core/trunk/geoext: lib/GeoExt/data tests/lib/GeoExt/data
commits at geoext.org
commits at geoext.org
Tue Apr 27 12:00:01 CEST 2010
Author: pgiraud
Date: 2010-04-27 12:00:01 +0200 (Tue, 27 Apr 2010)
New Revision: 2130
Modified:
core/trunk/geoext/lib/GeoExt/data/AttributeReader.js
core/trunk/geoext/lib/GeoExt/data/AttributeStore.js
core/trunk/geoext/tests/lib/GeoExt/data/AttributeReader.html
core/trunk/geoext/tests/lib/GeoExt/data/AttributeStore.html
Log:
make AttributeReader and AttributeStore work with a feature, patches from elemoine and me, r=elemoine,me (Closes #254)
Modified: core/trunk/geoext/lib/GeoExt/data/AttributeReader.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/data/AttributeReader.js 2010-04-27 09:25:28 UTC (rev 2129)
+++ core/trunk/geoext/lib/GeoExt/data/AttributeReader.js 2010-04-27 10:00:01 UTC (rev 2130)
@@ -29,6 +29,9 @@
* an ``OpenLayers.Format.WFSDescribeFeatureType`` parser.
* * ignore - ``Object`` Properties of the ignore object should be field names.
* Values are either arrays or regular expressions.
+ * * feature - ``OpenLayers.Feature.Vector`` A vector feature. If provided
+ * records created by the reader will include a field named "value"
+ * referencing the attribute value as set in the feature.
*/
GeoExt.data.AttributeReader = function(meta, recordType) {
meta = meta || {};
@@ -38,6 +41,9 @@
GeoExt.data.AttributeReader.superclass.constructor.call(
this, meta, recordType || meta.fields
);
+ if(meta.feature) {
+ this.recordType.prototype.fields.add(new Ext.data.Field("value"));
+ }
};
Ext.extend(GeoExt.data.AttributeReader, Ext.data.DataReader, {
@@ -77,10 +83,11 @@
// only works with one featureType in the doc
attributes = this.meta.format.read(data).featureTypes[0].properties;
}
+ var feature = this.meta.feature;
var recordType = this.recordType;
var fields = recordType.prototype.fields;
var numFields = fields.length;
- var attr, values, name, record, ignore, matches, value, records = [];
+ var attr, values, name, record, ignore, value, records = [];
for(var i=0, len=attributes.length; i<len; ++i) {
ignore = false;
attr = attributes[i];
@@ -88,20 +95,21 @@
for(var j=0; j<numFields; ++j) {
name = fields.items[j].name;
value = attr[name];
- if(this.meta.ignore && this.meta.ignore[name]) {
- matches = this.meta.ignore[name];
- if(typeof matches == "string") {
- ignore = (matches === value);
- } else if(matches instanceof Array) {
- ignore = (matches.indexOf(value) > -1);
- } else if(matches instanceof RegExp) {
- ignore = (matches.test(value));
+ if(this.ignoreAttribute(name, value)) {
+ ignore = true;
+ break;
+ }
+ values[name] = value;
+ }
+ if(feature) {
+ value = feature.attributes[values["name"]];
+ if(value !== undefined) {
+ if(this.ignoreAttribute("value", value)) {
+ ignore = true;
+ } else {
+ values["value"] = value;
}
- if(ignore) {
- break;
- }
}
- values[name] = attr[name];
}
if(!ignore) {
records[records.length] = new recordType(values);
@@ -113,7 +121,26 @@
records: records,
totalRecords: records.length
};
+ },
+ /** private: method[ignoreAttribute]
+ * :arg name: ``String`` The field name.
+ * :arg value: ``String`` The field value.
+ *
+ * :return: ``Boolean`` true if the attribute should be ignored.
+ */
+ ignoreAttribute: function(name, value) {
+ var ignore = false;
+ if(this.meta.ignore && this.meta.ignore[name]) {
+ var matches = this.meta.ignore[name];
+ if(typeof matches == "string") {
+ ignore = (matches === value);
+ } else if(matches instanceof Array) {
+ ignore = (matches.indexOf(value) > -1);
+ } else if(matches instanceof RegExp) {
+ ignore = (matches.test(value));
+ }
+ }
+ return ignore;
}
-
});
Modified: core/trunk/geoext/lib/GeoExt/data/AttributeStore.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/data/AttributeStore.js 2010-04-27 09:25:28 UTC (rev 2129)
+++ core/trunk/geoext/lib/GeoExt/data/AttributeStore.js 2010-04-27 10:00:01 UTC (rev 2130)
@@ -1,6 +1,6 @@
/**
* Copyright (c) 2008-2010 The Open Source Geospatial Foundation
- *
+ *
* Published under the BSD license.
* See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
* of the license.
@@ -52,13 +52,98 @@
)
})
);
+ if(this.feature) {
+ this.bind(this.feature);
+ }
+ },
+
+ /** private: method[bind]
+ * :param feature: ``OpenLayers.Feature.Vector``
+ */
+ bind: function(feature) {
+ this.on({
+ "update": this.onUpdate,
+ "load": this.onLoad,
+ "add": this.onAdd,
+ scope: this
+ });
+ },
+
+ /** private: method[onUpdate]
+ * :param store: ``Ext.data.Store``
+ * :param record: ``Ext.data.Record``
+ * :param operation: ``String``
+ *
+ * Handler for store update event.
+ */
+ onUpdate: function(store, record, operation) {
+ this.updateFeature([record]);
+ },
+
+ /** private: method[onLoad]
+ * :param store: ``Ext.data.Store``
+ * :param records: ``Array(Ext.data.Record)``
+ * :param options: ``Object``
+ *
+ * Handler for store load event
+ */
+ onLoad: function(store, records, options) {
+ // if options.add is true an "add" event was already
+ // triggered, and onAdd already did the work of
+ // adding the features to the layer.
+ if(!options || options.add !== true) {
+ this.updateFeature(records);
+ }
+ },
+
+ /** private: method[onAdd]
+ * :param store: ``Ext.data.Store``
+ * :param records: ``Array(Ext.data.Record)``
+ * :param index: ``Number``
+ *
+ * Handler for store add event
+ */
+ onAdd: function(store, records, index) {
+ this.updateFeature(records);
+ },
+
+ /** private: method[updateFeature]
+ * :param records: ``Array(Ext.data.Record)``
+ *
+ * Update feature from records.
+ */
+ updateFeature: function(records) {
+ var feature = this.feature, layer = feature.layer;
+ var record, name, value, oldValue, cont;
+ for(var i=0,len=records.length; i<len; i++) {
+ record = records[i];
+ name = record.get("name");
+ value = record.get("value");
+ oldValue = feature.attributes[name];
+ if(oldValue !== value) {
+ cont = true;
+ if(layer && layer.events) {
+ cont = layer.events.triggerEvent(
+ "beforefeaturemodified", {feature: feature});
+ }
+ if(cont !== false) {
+ feature.attributes[name] = value;
+ if(layer && layer.events) {
+ layer.events.triggerEvent(
+ "featuremodified", {feature: feature});
+ layer.drawFeature(feature);
+ }
+ }
+ }
+ }
}
+
};
};
/** api: constructor
* .. class:: AttributeStore(config)
- *
+ *
* Small helper class to make creating stores for remotely-loaded attributes
* data easier. AttributeStore is pre-configured with a built-in
* ``Ext.data.HttpProxy`` and :class:`GeoExt.data.AttributeReader`. The
@@ -81,6 +166,16 @@
* ``Ext.data.Record.create``, or a record constructor created using
* ``Ext.data.Record.create``. Defaults to ``["name", "type", "restriction"]``.
*/
+
+/** api: config[feature]
+ * ``OpenLayers.Feature.Vector``
+ * A vector feature. If provided, and if the reader is a
+ * :class:`GeoExt.data.AttributeReader` (the default), then records
+ * of this store will include a field named "value" referencing the
+ * corresponding attribute value in the feature. And if the "value"
+ * field of a record is updated the update will propagate to the
+ * corresponding feature attribute. Optional.
+ */
GeoExt.data.AttributeStore = Ext.extend(
Ext.data.Store,
GeoExt.data.AttributeStoreMixin()
Modified: core/trunk/geoext/tests/lib/GeoExt/data/AttributeReader.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/data/AttributeReader.html 2010-04-27 09:25:28 UTC (rev 2129)
+++ core/trunk/geoext/tests/lib/GeoExt/data/AttributeReader.html 2010-04-27 10:00:01 UTC (rev 2130)
@@ -32,6 +32,38 @@
t.eq(record.get("restriction").maxLength, "2", "[3] correct attribute restriction");
}
+ function test_read_feature(t) {
+ t.plan(3);
+
+ // set up
+
+ var feature, reader, records, record;
+
+ feature = new OpenLayers.Feature.Vector(null, {
+ "STATE_FIPS": "foo"
+ });
+
+ // test
+
+ reader = new GeoExt.data.AttributeReader({
+ feature: feature
+ }, ["name", "type"]);
+ records = reader.read({responseXML : doc});
+ record = records.records[2];
+ t.eq(record.get("value"), "foo", "[1] correct attribute value");
+ record = records.records[1];
+ t.eq(record.get("value"), undefined, "[2] correct attribute value");
+
+ // test with a reader whose record type doesn't include
+ // a field named "name"
+ reader = new GeoExt.data.AttributeReader({
+ feature: feature
+ }, ["type"]);
+ records = reader.read({responseXML : doc});
+ record = records.records[2];
+ t.eq(record.get("value"), undefined, "[3] correct attribute value");
+ }
+
function test_ignoreString(t) {
t.plan(1);
Modified: core/trunk/geoext/tests/lib/GeoExt/data/AttributeStore.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/data/AttributeStore.html 2010-04-27 09:25:28 UTC (rev 2129)
+++ core/trunk/geoext/tests/lib/GeoExt/data/AttributeStore.html 2010-04-27 10:00:01 UTC (rev 2130)
@@ -38,6 +38,159 @@
"ctor creates an Ext.data.GroupingStore");
}
+ function test_feature(t) {
+ t.plan(34);
+
+ // set up
+
+ var layer, feature, data, store, record
+ var onLoadLog, onAddLog;
+ var onBeforefeaturemodifiedLog, onFeaturemodifiedLog;
+
+ layer = new OpenLayers.Layer.Vector("vector", {
+ eventListeners: {
+ "beforefeaturemodified": function(e) {
+ onBeforefeaturemodifiedLog.push({feature: e.feature});
+ },
+ "featuremodified": function(e) {
+ onFeaturemodifiedLog.push({feature: e.feature});
+ }
+ }
+ });
+
+ feature = new OpenLayers.Feature.Vector(null, {
+ "foo0": "bar0",
+ "foo1": "bar1",
+ "foo2": "bar2",
+ "foo3": "bar3",
+ "foo4": null,
+ "foo5": undefined
+ });
+ layer.addFeatures(feature);
+
+ data = [{
+ "name": "foo0"
+ }, {
+ "name": "foo1"
+ }];
+
+ store = new GeoExt.data.AttributeStore({
+ feature: feature,
+ onLoad: function(store, records, index) {
+ onLoadLog.push({records: records});
+ GeoExt.data.AttributeStore.prototype.onLoad.apply(this, arguments);
+ },
+ onAdd: function(store, records, index) {
+ onAddLog.push({records: records});
+ GeoExt.data.AttributeStore.prototype.onAdd.apply(this, arguments);
+ }
+ });
+
+ // test
+
+ t.ok(store.feature === feature,
+ "feature is set in the store");
+ t.ok(store.reader.meta.feature === feature,
+ "feature is set in the reader's meta property");
+
+ onLoadLog = [], onBeforefeaturemodifiedLog = [], onFeaturemodifiedLog = [];
+ store.loadData(data);
+ record = store.getAt(0);
+ t.eq(onLoadLog.length, 1,
+ "onLoad called once on loadData");
+ t.eq(onLoadLog[0].records.length, 2,
+ "onLoad receiced expected number of records");
+ t.eq(onBeforefeaturemodifiedLog.length, 0,
+ "beforefeaturemodified not triggered");
+ t.eq(onFeaturemodifiedLog.length, 0,
+ "featuremodified not triggered");
+ t.eq(record.get("name"), "foo0",
+ "[0] record name is correct");
+ t.eq(record.get("value"), "bar0",
+ "[0] record value is correct");
+ record = store.getAt(1);
+ t.eq(record.get("name"), "foo1",
+ "[1] record name is correct");
+ t.eq(record.get("value"), "bar1",
+ "[1] record value is correct");
+
+ onBeforefeaturemodifiedLog = [], onFeaturemodifiedLog = [];
+ record = store.getAt(0);
+ record.set("value", "bar00");
+ t.eq(onBeforefeaturemodifiedLog.length, 1,
+ "beforefeaturemodified triggered once");
+ t.eq(onFeaturemodifiedLog.length, 1,
+ "featuremodified triggered once");
+ t.eq(feature.attributes.foo0, "bar00",
+ "feature attribute foo0 updated");
+ t.eq(feature.attributes.foo1, "bar1",
+ "feature attribute foo1 not updated");
+
+ onAddLog = [];
+ store.loadData([{"name": "foo2"}], true);
+ t.eq(onAddLog.length, 1,
+ "onAdd called once on loadData");
+ t.eq(onAddLog[0].records.length, 1,
+ "onAdd received expected number of records");
+ record = store.getAt(2);
+ t.eq(record.get("name"), "foo2",
+ "[2] record name is correct");
+ t.eq(record.get("value"), "bar2",
+ "[2] record value is correct");
+
+ // attribute with value in feature (should be kept)
+ onBeforefeaturemodifiedLog = [], onFeaturemodifiedLog = [];
+ store.loadData([{"name": "foo3", "value": "bar30"}], true);
+ t.eq(onBeforefeaturemodifiedLog.length, 0,
+ "beforefeaturemodified not triggered");
+ t.eq(onFeaturemodifiedLog.length, 0,
+ "featuremodified not triggered");
+ record = store.getAt(3);
+ t.eq(record.get("value"), "bar3",
+ "record value is correct, read from feature");
+ t.eq(feature.attributes.foo3, "bar3",
+ "feature attribute foo3 not updated, initial value kept");
+
+ // attribute with null value in feature (should be kept)
+ store.loadData([{"name": "foo4", "value": "bar4"}], true);
+ t.eq(onBeforefeaturemodifiedLog.length, 0,
+ "beforefeaturemodified not triggered");
+ t.eq(onFeaturemodifiedLog.length, 0,
+ "featuremodified not triggered");
+ record = store.getAt(4);
+ t.ok(record.get("value") === null,
+ "record value is correct, read from feature");
+ t.ok(feature.attributes.foo4 === null,
+ "feature attribute foo4 not updated, initial value kept");
+
+ // attribute with undefined value in feature (should be overridden)
+ store.loadData([{"name": "foo5", "value": "bar5"}], true);
+ t.eq(onBeforefeaturemodifiedLog.length, 1,
+ "beforefeaturemodified triggered");
+ t.eq(onFeaturemodifiedLog.length, 1,
+ "featuremodified triggered");
+ record = store.getAt(5);
+ t.eq(record.get("value"), "bar5",
+ "record value is correct, read from data");
+ t.eq(feature.attributes.foo5, "bar5",
+ "feature attribute foo5 updated");
+
+ // attribute missing in feature
+ onBeforefeaturemodifiedLog = [], onFeaturemodifiedLog = [];
+ store.loadData([{"name": "foo6", "value": "bar6"}], true);
+ t.eq(onBeforefeaturemodifiedLog.length, 1,
+ "beforefeaturemodified triggered");
+ t.eq(onFeaturemodifiedLog.length, 1,
+ "featuremodified triggered");
+ record = store.getAt(6);
+ t.eq(record.get("value"), "bar6",
+ "record value is correct, read from data");
+ t.eq(feature.attributes.foo6, "bar6",
+ "feature attribute foo6 added, with correct value");
+
+ // tear down
+ }
+
</script>
<body>
<div id="map"></div>
More information about the Commits
mailing list