[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