Skip to content

Commit

Permalink
Decouple MapInstanceManager from window.farmOS.map
Browse files Browse the repository at this point in the history
**Why?** Better support alternative bundling strategies
and scenarios where having mutable state in the global
`window.farmOS.map` is ugly/limiting.

These changes should allow farmOS-map to also be used
as follows;

```sh
npm install @farmos.org/farmos-map@2
```

```js
import MapInstanceManager from '@farmos.org/farmos-map/MapInstanceManager';

const maps = new MapInstanceManager();

const map = maps.create('my-map');
```

Some background can be found in the following issues;

* #113
* #68
  • Loading branch information
symbioquine committed Jun 1, 2021
1 parent a9f1aa1 commit be48ca0
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 57 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove redundant `defaults.behaviors` in favor of existing `farmOS.map.behaviors` mechanism for specifying the default behaviors.
- Make instance behavior methods `async`.
- Lazily load behaviors as separate Webpack chunks.
- Decouple map instance creation/management from `window.farmOS.map`.

### Fixed

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"type": "git",
"url": "https://github.com/farmOS/farmOS-map.git"
},
"main": "src/index.js",
"scripts": {
"lint": "eslint src",
"build": "npm run lint && webpack --config webpack.config.js --mode production",
Expand Down
65 changes: 65 additions & 0 deletions src/MapInstanceManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Import farmOS map instance factory function.
import createInstance from './instance/instance';

// Import farmOS-map CSS.
import './styles.css';

import namedBehaviors from './behavior';


class MapInstanceManager {

constructor() {

// Initialize an array of farmOS map instances.
this.instances = [];

// Behaviors which can be added on-demand by name via `instance.addBehavior`
// These are objects with an attach() method that will be called when a map is
// created. They receive the instance object so that they can perform
// modifications to the map using instance methods.
this.namedBehaviors = { ...namedBehaviors };

// Map behaviors which will be automatically attached to all created map
// instances.
this.behaviors = {
rememberLayer: namedBehaviors.rememberLayer,
};

}

// Create a new farmOS map attached to a target element ID and add it to the
// global instances array.
create(target, options) {
const instance = createInstance({ target, options });

instance.instanceManager = this;

// Add the instance to the array.
this.instances.push(instance);

// Attach behaviors from farmOS.map.behaviors to the instance in order of weight - if any.
instance.defaultBehaviorsAttached = instance.attachBehaviorsByWeight(
Object.values(this.behaviors),
);

// Return the instance.
return instance;
}

// Destroy a farmOS map instance and remove it from the instances array.
destroy(target) {
const i = this.targetIndex(target);
if (i > -1) {
this.instances[i].map.setTarget(null);
this.instances.splice(i, 1);
}
}

// Look up an instance index based on its target element ID.
targetIndex(target) {
return this.instances.findIndex(instance => instance.target === target);
}
}

export default MapInstanceManager;
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* eslint-disable-next-line import/prefer-default-export */
export { default as MapInstanceManager } from './MapInstanceManager';
4 changes: 1 addition & 3 deletions src/instance/methods/behavior.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import namedBehaviors from '../../behavior';

/**
* Add a behavior by name.
*/
export async function addBehavior(name, options = {}) {
return this.attachBehavior(namedBehaviors[name], options);
return this.attachBehavior(this.instanceManager.namedBehaviors[name], options);
}

/**
Expand Down
60 changes: 6 additions & 54 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,14 @@
// Import farmOS map instance factory function.
import createInstance from './instance/instance';

import namedBehaviors from './behavior';

// Import farmOS-map CSS.
import './styles.css';
import MapInstanceManager from './MapInstanceManager';

// Define window.farmOS if it isn't already.
if (typeof window.farmOS === 'undefined') {
window.farmOS = {};
}

// Add a farmOS.map object that is available globaly.
window.farmOS.map = {

// Initialize an array of farmOS map instances.
instances: [],

// Behaviors which can be added on-demand by name via `instance.addBehavior`
// These are objects with an attach() method that will be called when a map is
// created. They receive the instance object so that they can perform
// modifications to the map using instance methods.
namedBehaviors,

// Map behaviors which will be automatically attached to all created map
// instances.
behaviors: {
rememberLayer: namedBehaviors.rememberLayer,
},
const INSTANCE = new MapInstanceManager();

// Create a new farmOS map attached to a target element ID and add it to the
// global instances array.
create(target, options) {
const instance = createInstance({ target, options });

// Add the instance to the array.
this.instances.push(instance);

// Attach behaviors from farmOS.map.behaviors to the instance in order of weight - if any.
instance.defaultBehaviorsAttached = instance.attachBehaviorsByWeight(
Object.values(this.behaviors),
);

// Return the instance.
return instance;
},

// Destroy a farmOS map instance and remove it from the instances array.
destroy(target) {
const i = this.targetIndex(target);
if (i > -1) {
this.instances[i].map.setTarget(null);
this.instances.splice(i, 1);
}
},
// Add a farmOS.map object that is available globaly.
window.farmOS.map = INSTANCE;

// Look up an instance index based on its target element ID.
targetIndex(target) {
return this.instances.findIndex(instance => instance.target === target);
},
};
// Export the default farmOS-map object
export default INSTANCE;

0 comments on commit be48ca0

Please sign in to comment.