Skip to content

Commit d3cc7c5

Browse files
committed
Allow filter to be mutated and set again (#2495)
* Allow filter to be mutated and set again fixes #2486 * Clone StyleDeclaration value
1 parent 0330432 commit d3cc7c5

File tree

5 files changed

+80
-4
lines changed

5 files changed

+80
-4
lines changed

js/style/style.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ Style.prototype = util.inherit(Evented, {
501501
if (this._handleErrors(validateStyle.filter, 'layers.' + layer.id + '.filter', filter)) return this;
502502

503503
if (util.deepEqual(layer.filter, filter)) return this;
504-
layer.filter = filter;
504+
layer.filter = util.clone(filter);
505505

506506
return this._updateLayer(layer);
507507
},

js/style/style_declaration.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
var MapboxGLFunction = require('./style_function');
44
var parseColor = require('./parse_color');
5+
var util = require('../util/util');
56

67
module.exports = StyleDeclaration;
78

89
function StyleDeclaration(reference, value) {
910
this.type = reference.type;
1011
this.transitionable = reference.transition;
11-
this.value = value;
12+
this.value = util.clone(value);
1213
this.isFunction = !!value.stops;
1314

1415
// immutable representation of value. used for comparison

js/util/util.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,23 @@ exports.deepEqual = function deepEqual(a, b) {
435435
return a === b;
436436
};
437437

438+
/**
439+
* Deeply clones two objects.
440+
* @param {Object} obj1
441+
* @param {Object} obj2
442+
* @returns {boolean}
443+
* @private
444+
*/
445+
exports.clone = function deepEqual(input) {
446+
if (Array.isArray(input)) {
447+
return input.map(exports.clone);
448+
} else if (typeof input === 'object') {
449+
return exports.mapObject(input, exports.clone);
450+
} else {
451+
return input;
452+
}
453+
};
454+
438455
/**
439456
* Check if two arrays have at least one common element.
440457
* @param {Array} a

test/js/style/style.test.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,12 +766,34 @@ test('Style#setFilter', function(t) {
766766
style.on('load', function() {
767767
style.dispatcher.broadcast = function(key, value) {
768768
t.equal(key, 'update layers');
769-
t.deepEqual(value.map(function(layer) { return layer.id; }), ['symbol']);
769+
t.deepEqual(value[0].id, 'symbol');
770+
t.deepEqual(value[0].filter, ['==', 'id', 1]);
771+
t.end();
770772
};
771773

772774
style.setFilter('symbol', ['==', 'id', 1]);
773775
t.deepEqual(style.getFilter('symbol'), ['==', 'id', 1]);
774-
t.end();
776+
style.update({}, {}); // trigger dispatcher broadcast
777+
});
778+
});
779+
780+
t.test('sets again mutated filter', function(t) {
781+
var style = createStyle();
782+
783+
style.on('load', function() {
784+
var filter = ['==', 'id', 1];
785+
style.setFilter('symbol', filter);
786+
style.update({}, {}); // flush pending operations
787+
788+
style.dispatcher.broadcast = function(key, value) {
789+
t.equal(key, 'update layers');
790+
t.deepEqual(value[0].id, 'symbol');
791+
t.deepEqual(value[0].filter, ['==', 'id', 2]);
792+
t.end();
793+
};
794+
filter[2] = 2;
795+
style.setFilter('symbol', filter);
796+
style.update({}, {}); // trigger dispatcher broadcast
775797
});
776798
});
777799

test/js/util/util.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,42 @@ test('util', function(t) {
257257
t.end();
258258
});
259259

260+
t.test('clone', function(t) {
261+
t.test('array', function(t) {
262+
var input = [false, 1, 'two'];
263+
var output = util.clone(input);
264+
t.notEqual(input, output);
265+
t.deepEqual(input, output);
266+
t.end();
267+
});
268+
269+
t.test('object', function(t) {
270+
var input = {a: false, b: 1, c: 'two'};
271+
var output = util.clone(input);
272+
t.notEqual(input, output);
273+
t.deepEqual(input, output);
274+
t.end();
275+
});
276+
277+
t.test('deep object', function(t) {
278+
var input = {object: {a: false, b: 1, c: 'two'}};
279+
var output = util.clone(input);
280+
t.notEqual(input.object, output.object);
281+
t.deepEqual(input.object, output.object);
282+
t.end();
283+
});
284+
285+
t.test('deep array', function(t) {
286+
var input = {array: [false, 1, 'two']};
287+
var output = util.clone(input);
288+
t.notEqual(input.array, output.array);
289+
t.deepEqual(input.array, output.array);
290+
t.end();
291+
});
292+
293+
t.end();
294+
});
295+
260296
if (process.browser) {
261297
t.test('timed: no duration', function(t) {
262298
var context = { foo: 'bar' };

0 commit comments

Comments
 (0)