Skip to content

Array edits #1403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Feb 24, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/lib/identity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

// Simple helper functions
// none of these need any external deps

module.exports = function identity(d) { return d; };
38 changes: 4 additions & 34 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,13 @@ lib.notifier = require('./notifier');

lib.filterUnique = require('./filter_unique');
lib.filterVisible = require('./filter_visible');

lib.pushUnique = require('./push_unique');

lib.cleanNumber = require('./clean_number');

lib.noop = require('./noop');
lib.identity = require('./identity');

/**
* swap x and y of the same attribute in container cont
* specify attr with a ? in place of x/y
Expand Down Expand Up @@ -136,12 +139,6 @@ lib.bBoxIntersect = function(a, b, pad) {
b.top <= a.bottom + pad);
};

// minor convenience/performance booster for d3...
lib.identity = function(d) { return d; };

// minor convenience helper
lib.noop = function() {};

/*
* simpleMap: alternative to Array.map that only
* passes on the element and up to 2 extra args you
Expand Down Expand Up @@ -338,33 +335,6 @@ lib.noneOrAll = function(containerIn, containerOut, attrList) {
}
};

/**
* Push array with unique items
*
* @param {array} array
* array to be filled
* @param {any} item
* item to be or not to be inserted
* @return {array}
* ref to array (now possibly containing one more item)
*
*/
lib.pushUnique = function(array, item) {
if(item instanceof RegExp) {
var itemStr = item.toString(),
i;
for(i = 0; i < array.length; i++) {
if(array[i] instanceof RegExp && array[i].toString() === itemStr) {
return array;
}
}
array.push(item);
}
else if(item && array.indexOf(item) === -1) array.push(item);

return array;
};

lib.mergeArray = function(traceAttr, cd, cdAttr) {
if(Array.isArray(traceAttr)) {
var imax = Math.min(traceAttr.length, cd.length);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/nested_property.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
var isNumeric = require('fast-isnumeric');
var isArray = require('./is_array');
var isPlainObject = require('./is_plain_object');
var containerArrayMatch = require('../plot_api/manage_arrays').containerArrayMatch;
var containerArrayMatch = require('../plot_api/container_array_match');

/**
* convert a string s (such as 'xaxis.range[0]')
Expand Down
14 changes: 14 additions & 0 deletions src/lib/noop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

// Simple helper functions
// none of these need any external deps

module.exports = function noop() {};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this was about the shortest possible module one could make... but I suppose you could do:

exports.a = 0;

Kind of silly... but needed to de-circularize, short of refactoring Lib (see #236 )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(resisting temptation suggest a noop factory approach)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it's important that noop is a singleton so you can use === noop particularly on the results of Registry.getComponentMethod to see if it was found.

36 changes: 36 additions & 0 deletions src/lib/push_unique.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

/**
* Push array with unique items
*
* @param {array} array
* array to be filled
* @param {any} item
* item to be or not to be inserted
* @return {array}
* ref to array (now possibly containing one more item)
*
*/
module.exports = function pushUnique(array, item) {
if(item instanceof RegExp) {
var itemStr = item.toString(),
i;
for(i = 0; i < array.length; i++) {
if(array[i] instanceof RegExp && array[i].toString() === itemStr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return array;
}
}
array.push(item);
}
else if(item && array.indexOf(item) === -1) array.push(item);

return array;
};
56 changes: 56 additions & 0 deletions src/plot_api/container_array_match.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var Registry = require('../registry');

/*
* containerArrayMatch: does this attribute string point into a
* layout container array?
*
* @param {String} astr: an attribute string, like *annotations[2].text*
*
* @returns {Object | false} Returns false if `astr` doesn't match a container
* array. If it does, returns:
* {array: {String}, index: {Number}, property: {String}}
* ie the attribute string for the array, the index within the array (or ''
* if the whole array) and the property within that (or '' if the whole array
* or the whole object)
*/
module.exports = function containerArrayMatch(astr) {
var rootContainers = Registry.layoutArrayContainers,
regexpContainers = Registry.layoutArrayRegexes,
rootPart = astr.split('[')[0],
arrayStr,
match;

// look for regexp matches first, because they may be nested inside root matches
// eg updatemenus[i].buttons is nested inside updatemenus
for(var i = 0; i < regexpContainers.length; i++) {
match = astr.match(regexpContainers[i]);
if(match && match.index === 0) {
arrayStr = match[0];
break;
}
}

// now look for root matches
if(!arrayStr) arrayStr = rootContainers[rootContainers.indexOf(rootPart)];

if(!arrayStr) return false;

var tail = astr.substr(arrayStr.length);
if(!tail) return {array: arrayStr, index: '', property: ''};

match = tail.match(/^\[(0|[1-9][0-9]*)\](\.(.+))?$/);
if(!match) return false;

return {array: arrayStr, index: Number(match[1]), property: match[3] || ''};
};
71 changes: 16 additions & 55 deletions src/plot_api/manage_arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,23 @@

'use strict';

var Lib = require('../lib');
var nestedProperty = require('../lib/nested_property');
var isPlainObject = require('../lib/is_plain_object');
var noop = require('../lib/noop');
var Loggers = require('../lib/loggers');
var Registry = require('../registry');


exports.containerArrayMatch = require('./container_array_match');

var isAddVal = exports.isAddVal = function isAddVal(val) {
return val === 'add' || Lib.isPlainObject(val);
return val === 'add' || isPlainObject(val);
};

var isRemoveVal = exports.isRemoveVal = function isRemoveVal(val) {
return val === null || val === 'remove';
};

/*
* containerArrayMatch: does this attribute string point into a
* layout container array?
*
* @param {String} astr: an attribute string, like *annotations[2].text*
*
* @returns {Object | false} Returns false if `astr` doesn't match a container
* array. If it does, returns:
* {array: {String}, index: {Number}, property: {String}}
* ie the attribute string for the array, the index within the array (or ''
* if the whole array) and the property within that (or '' if the whole array
* or the whole object)
*/
exports.containerArrayMatch = function containerArrayMatch(astr) {
var rootContainers = Registry.layoutArrayContainers,
regexpContainers = Registry.layoutArrayRegexes,
rootPart = astr.split('[')[0],
arrayStr,
match;

// look for regexp matches first, because they may be nested inside root matches
// eg updatemenus[i].buttons is nested inside updatemenus
for(var i = 0; i < regexpContainers.length; i++) {
match = astr.match(regexpContainers[i]);
if(match && match.index === 0) {
arrayStr = match[0];
break;
}
}

// now look for root matches
if(!arrayStr) arrayStr = rootContainers[rootContainers.indexOf(rootPart)];

if(!arrayStr) return false;

var tail = astr.substr(arrayStr.length);
if(!tail) return {array: arrayStr, index: '', property: ''};

match = tail.match(/^\[(0|[1-9][0-9]*)\](\.(.+))?$/);
if(!match) return false;

return {array: arrayStr, index: Number(match[1]), property: match[3] || ''};
};

/*
* editContainerArray: for managing arrays of layout components in relayout
* handles them all with a consistent interface.
Expand Down Expand Up @@ -113,14 +74,14 @@ exports.editContainerArray = function editContainerArray(gd, np, edits, flags) {
supplyComponentDefaults = Registry.getComponentMethod(componentType, 'supplyLayoutDefaults'),
draw = Registry.getComponentMethod(componentType, 'draw'),
drawOne = Registry.getComponentMethod(componentType, 'drawOne'),
replotLater = flags.replot || flags.recalc || (supplyComponentDefaults === Lib.noop) ||
(draw === Lib.noop),
replotLater = flags.replot || flags.recalc || (supplyComponentDefaults === noop) ||
(draw === noop),
layout = gd.layout,
fullLayout = gd._fullLayout;

if(edits['']) {
if(Object.keys(edits).length > 1) {
Lib.warn('Full array edits are incompatible with other edits',
Loggers.warn('Full array edits are incompatible with other edits',
componentType);
}

Expand All @@ -129,7 +90,7 @@ exports.editContainerArray = function editContainerArray(gd, np, edits, flags) {
if(isRemoveVal(fullVal)) np.set(null);
else if(Array.isArray(fullVal)) np.set(fullVal);
else {
Lib.warn('Unrecognized full array edit value', componentType, fullVal);
Loggers.warn('Unrecognized full array edit value', componentType, fullVal);
return true;
}

Expand Down Expand Up @@ -164,13 +125,13 @@ exports.editContainerArray = function editContainerArray(gd, np, edits, flags) {
adding = isAddVal(objVal);

if(componentNum < 0 || componentNum > componentArray.length - (adding ? 0 : 1)) {
Lib.warn('index out of range', componentType, componentNum);
Loggers.warn('index out of range', componentType, componentNum);
continue;
}

if(objVal !== undefined) {
if(objKeys.length > 1) {
Lib.warn(
Loggers.warn(
'Insertion & removal are incompatible with edits to the same index.',
componentType, componentNum);
}
Expand All @@ -183,15 +144,15 @@ exports.editContainerArray = function editContainerArray(gd, np, edits, flags) {
componentArray.splice(componentNum, 0, objVal);
}
else {
Lib.warn('Unrecognized full object edit value',
Loggers.warn('Unrecognized full object edit value',
componentType, componentNum, objVal);
}

if(firstIndexChange === -1) firstIndexChange = componentNum;
}
else {
for(j = 0; j < objKeys.length; j++) {
Lib.nestedProperty(componentArray[componentNum], objKeys[j]).set(objEdits[objKeys[j]]);
nestedProperty(componentArray[componentNum], objKeys[j]).set(objEdits[objKeys[j]]);
}
}
}
Expand All @@ -210,7 +171,7 @@ exports.editContainerArray = function editContainerArray(gd, np, edits, flags) {

// finally draw all the components we need to
// if we added or removed any, redraw all after it
if(drawOne !== Lib.noop) {
if(drawOne !== noop) {
var indicesToDraw;
if(firstIndexChange === -1) {
// there's no re-indexing to do, so only redraw components that changed
Expand Down
Loading