Skip to content

Commit 9ce90b6

Browse files
committed
- added components and templates - added functional and unit tests for existing components AtlasOfLivingAustralia/biocollect#1231 - fixed content type for script
1 parent d35ab40 commit 9ce90b6

23 files changed

+836
-346
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//= require_self
2+
//= require compile/ecodata-templates.js
3+
//= require_tree javascript
4+
5+
if (typeof componentService === "undefined") {
6+
componentService = function () {
7+
var cache = {};
8+
function getTemplate(name) {
9+
return cache[name];
10+
};
11+
12+
function setTemplate(name, template) {
13+
cache[name] = template;
14+
};
15+
16+
return {
17+
getTemplate: getTemplate,
18+
setTemplate: setTemplate
19+
};
20+
}();
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (C) 2019 Atlas of Living Australia
3+
* All Rights Reserved.
4+
*
5+
* The contents of this file are subject to the Mozilla Public
6+
* License Version 1.1 (the "License"); you may not use this file
7+
* except in compliance with the License. You may obtain a copy of
8+
* the License at http://www.mozilla.org/MPL/
9+
*
10+
* Software distributed under the License is distributed on an "AS
11+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
12+
* implied. See the License for the specific language governing
13+
* rights and limitations under the License.
14+
*
15+
* Created by Temi on 24/11/19.
16+
*/
17+
ko.components.register('condition-trajectory', {
18+
viewModel: function (params) {
19+
var self = this;
20+
var offsets = ["Very poor", "Poor", "Good", "Very good"];
21+
var trajectories = ["Improving", "Deteriorating", "Stable", "Unclear"];
22+
23+
var width = 75;
24+
var boxWidth = 30;
25+
self.boxPosition = ko.computed(function() {
26+
var condition = ko.utils.unwrapObservable(params.condition);
27+
var index = offsets.indexOf(condition);
28+
return index * width + width/2 - boxWidth/2;
29+
});
30+
self.title = ko.computed(function() {
31+
var condition = ko.utils.unwrapObservable(params.condition);
32+
var trajectory = ko.utils.unwrapObservable(params.trajectory);
33+
return "Condition: "+condition+", Trajectory: " + trajectory;
34+
});
35+
36+
self.trajectoryTemplate = ko.computed(function() {
37+
var trajectory = ko.utils.unwrapObservable(params.trajectory);
38+
if (trajectory) {
39+
return 'template-trajectory-'+trajectory.toLowerCase();
40+
}
41+
return 'template-trajectory-none';
42+
});
43+
44+
},
45+
template:componentService.getTemplate('condition-trajectory')
46+
47+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (C) 2019 Atlas of Living Australia
3+
* All Rights Reserved.
4+
*
5+
* The contents of this file are subject to the Mozilla Public
6+
* License Version 1.1 (the "License"); you may not use this file
7+
* except in compliance with the License. You may obtain a copy of
8+
* the License at http://www.mozilla.org/MPL/
9+
*
10+
* Software distributed under the License is distributed on an "AS
11+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
12+
* implied. See the License for the specific language governing
13+
* rights and limitations under the License.
14+
*
15+
* Created by Temi on 25/11/19.
16+
*/
17+
18+
//= require turf
19+
//= require_self
20+
ko.components.register('feature', {
21+
22+
viewModel: function (params) {
23+
24+
var self = this;
25+
var model = params.feature;
26+
27+
if (!model) {
28+
throw "The model attribute is required for this component";
29+
}
30+
self.model = model;
31+
32+
self.enabled = true;
33+
if (_.isFunction(model.enableConstraint)) {
34+
self.enabled = model.enableConstraint;
35+
}
36+
37+
38+
self.readonly = params.config.readonly;
39+
40+
self.ok = function (map) {
41+
42+
var geoJson = map.getGeoJSON();
43+
44+
_.each(geoJson.features || [], function (feature) {
45+
delete feature.layer;
46+
});
47+
48+
model(geoJson);
49+
};
50+
51+
self.showMap = function() {
52+
53+
var options = {
54+
okCallback:self.ok
55+
};
56+
57+
var map = ecodata.forms.maps.showMapInModal(options);
58+
if (self.model()) {
59+
map.setGeoJSON(self.model(), {zoomToObject:false});
60+
}
61+
};
62+
63+
/** Let the model know it's been deleted so it can deregister from the managed site */
64+
self.dispose = function() {
65+
if (_.isFunction(model.onDispose)) {
66+
model.onDispose();
67+
}
68+
};
69+
70+
71+
},
72+
template: componentService.getTemplate('feature')
73+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
ko.components.register('multi-input', {
2+
viewModel: function(params) {
3+
var self = this;
4+
5+
self.observableValues = ko.observableArray();
6+
7+
// This method updates the values parameter with the contents of the managed array.
8+
function syncValues() {
9+
var rawValues = [];
10+
for (var i=0; i<self.observableValues().length; i++) {
11+
rawValues.push(self.observableValues()[i].val());
12+
}
13+
params.values(rawValues);
14+
}
15+
16+
function newValue(value) {
17+
var observable = ko.observable(value || '');
18+
observable.subscribe(syncValues);
19+
self.observableValues.push({val:observable});
20+
}
21+
22+
self.addValue = function() {
23+
newValue();
24+
};
25+
26+
self.removeValue = function(value) {
27+
self.observableValues.remove(value);
28+
};
29+
30+
if (params.values()) {
31+
for (var i=0; i<params.values().length; i++) {
32+
newValue(params.values()[i]);
33+
}
34+
}
35+
36+
self.observableValues.subscribe(syncValues);
37+
},
38+
template: componentService.getTemplate('multi-input')
39+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<div class="row-fluid">
2+
<div class="span3" style="text-align: center">Very poor</div>
3+
4+
<div class="span3">Poor</div>
5+
6+
<div class="span3">Good</div>
7+
8+
<div class="span3">Very good</div>
9+
</div>
10+
<svg viewBox="0 0 304 40" class="condition-trajectory" aria-labeledby="title" role="diagram">
11+
<svg x="0" y="3">
12+
<g>
13+
<rect class="condition condition-very-poor" x="0" width="75" height="26" y="0"></rect>
14+
<rect class="condition condition-poor" x="75" width="75" height="26" y="0"></rect>
15+
<rect class="condition condition-good" x="150" width="75" height="26" y="0"></rect>
16+
<rect class="condition condition-very-good" x="225" width="75" height="26" y="0"></rect>
17+
</g>
18+
</svg>
19+
<svg data-bind="attr:{x:boxPosition, title:title}" y="0">
20+
<g transform="scale(0.3)">
21+
<rect class="trajectory" x="4" y="5" width="95" height="93"></rect>
22+
<svg class="trajectory-icon" x="10" y="10" width="80" height="80">
23+
<!-- ko if: template() === 'template-trajectory-improving' -->
24+
<svg viewBox="0 0 16 16">
25+
<path fill="#000000"
26+
d="M3.707 13.707l8.293-8.293v3.586c0 0.552 0.448 1 1 1s1-0.448 1-1v-6c0-0.404-0.244-0.769-0.617-0.924-0.124-0.051-0.254-0.076-0.383-0.076v-0.001h-6c-0.552 0-1 0.448-1 1s0.448 1 1 1h3.586l-8.293 8.293c-0.195 0.195-0.293 0.451-0.293 0.707s0.098 0.512 0.293 0.707c0.39 0.391 1.024 0.391 1.414 0z"></path>
27+
</svg>
28+
<!-- /ko -->
29+
<!-- ko if: template() === 'template-trajectory-deteriorating' -->
30+
<svg viewBox="0 0 16 16">
31+
<path d="M2.293 3.707l8.293 8.293h-3.586c-0.552 0-1 0.448-1 1s0.448 1 1 1h6c0.404 0 0.769-0.244 0.924-0.617 0.051-0.124 0.076-0.254 0.076-0.383h0.001v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1v3.586l-8.293-8.293c-0.195-0.195-0.451-0.293-0.707-0.293s-0.512 0.098-0.707 0.293c-0.391 0.39-0.391 1.024 0 1.414z"></path>
32+
</svg>
33+
<!-- /ko -->
34+
<!-- ko if: template() === 'template-trajectory-stable' -->
35+
<svg viewBox="0 0 100 100">
36+
<path d="M12 43 h80 v14 h-80 z"></path>
37+
</svg>
38+
<!-- /ko -->
39+
<!-- ko if: template() === 'template-trajectory-unclear' -->
40+
<svg viewBox="0 0 1792 1792">
41+
<path d="M1088 1256v240q0 16-12 28t-28 12h-240q-16 0-28-12t-12-28v-240q0-16 12-28t28-12h240q16 0 28 12t12 28zm316-600q0 54-15.5 101t-35 76.5-55 59.5-57.5 43.5-61 35.5q-41 23-68.5 65t-27.5 67q0 17-12 32.5t-28 15.5h-240q-15 0-25.5-18.5t-10.5-37.5v-45q0-83 65-156.5t143-108.5q59-27 84-56t25-76q0-42-46.5-74t-107.5-32q-65 0-108 29-35 25-107 115-13 16-31 16-12 0-25-8l-164-125q-13-10-15.5-25t5.5-28q160-266 464-266 80 0 161 31t146 83 106 127.5 41 158.5z"/>
42+
</svg>
43+
<!-- /ko -->
44+
<!-- ko if: template() === 'template-trajectory-none' -->
45+
<!-- /ko -->
46+
47+
</svg>
48+
</g>
49+
</svg>
50+
</svg>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<button class="btn edit-feature" data-bind="visible:!model() && !readonly, click:showMap, enable:enabled"><i class="fa fa-edit"></i></button>
2+
<button class="btn edit-feature" data-bind="visible:model(), click:showMap, enable:enabled"><div class="mini-feature" data-bind="if:model(),geojson2svg:model"></div></button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div data-bind="foreach: observableValues">
2+
<div class="input-append">
3+
<span data-bind="template:{nodes:$componentTemplateNodes}"></span><span class="add-on"
4+
data-bind="click:$parent.removeValue"><i
5+
class="fa fa-remove"></i></span>
6+
</div>
7+
</div>
8+
<i class="fa fa-plus" data-bind="click:addValue"></i>

grails-app/assets/javascripts/feature.js

-58
Original file line numberDiff line numberDiff line change
@@ -615,64 +615,6 @@ ecodata.forms.maps.showMapInModal = function(options) {
615615
return self.featureMapInstance;
616616
};
617617

618-
ko.components.register('feature', {
619-
620-
viewModel: function (params) {
621-
622-
var self = this;
623-
var model = params.feature;
624-
625-
if (!model) {
626-
throw "The model attribute is required for this component";
627-
}
628-
self.model = model;
629-
630-
self.enabled = true;
631-
if (_.isFunction(model.enableConstraint)) {
632-
self.enabled = model.enableConstraint;
633-
}
634-
635-
636-
self.readonly = params.config.readonly;
637-
638-
self.ok = function (map) {
639-
640-
var geoJson = map.getGeoJSON();
641-
642-
_.each(geoJson.features || [], function (feature) {
643-
delete feature.layer;
644-
});
645-
646-
model(geoJson);
647-
};
648-
649-
self.showMap = function() {
650-
651-
var options = {
652-
okCallback:self.ok
653-
};
654-
655-
var map = ecodata.forms.maps.showMapInModal(options);
656-
if (self.model()) {
657-
map.setGeoJSON(self.model(), {zoomToObject:false});
658-
}
659-
};
660-
661-
/** Let the model know it's been deleted so it can deregister from the managed site */
662-
self.dispose = function() {
663-
if (_.isFunction(model.onDispose)) {
664-
model.onDispose();
665-
}
666-
};
667-
668-
669-
},
670-
template: '<button class="btn edit-feature" data-bind="visible:!model() && !readonly, click:showMap, enable:enabled"><i class="fa fa-edit"></i></button>' +
671-
'<button class="btn edit-feature" data-bind="visible:model(), click:showMap, enable:enabled"><div class="mini-feature" data-bind="if:model(),geojson2svg:model"></div></button>'
672-
673-
674-
});
675-
676618
/**
677619
* A FeatureCollection is responsible for managing the lifecycle and data
678620
* of model elements with the dataType of 'feature'.

grails-app/assets/javascripts/forms-knockout-bindings.js

-72
Original file line numberDiff line numberDiff line change
@@ -861,78 +861,6 @@
861861
}
862862
};
863863

864-
ko.components.register('multi-input', {
865-
viewModel: function(params) {
866-
var self = this;
867-
868-
self.observableValues = ko.observableArray();
869-
870-
// This method updates the values parameter with the contents of the managed array.
871-
function syncValues() {
872-
var rawValues = [];
873-
for (var i=0; i<self.observableValues().length; i++) {
874-
rawValues.push(self.observableValues()[i].val());
875-
}
876-
params.values(rawValues);
877-
}
878-
879-
function newValue(value) {
880-
var observable = ko.observable(value || '');
881-
observable.subscribe(syncValues);
882-
self.observableValues.push({val:observable});
883-
}
884-
885-
self.addValue = function() {
886-
newValue();
887-
};
888-
889-
self.removeValue = function(value) {
890-
self.observableValues.remove(value);
891-
};
892-
893-
if (params.values()) {
894-
for (var i=0; i<params.values().length; i++) {
895-
newValue(params.values()[i]);
896-
}
897-
}
898-
899-
self.observableValues.subscribe(syncValues);
900-
},
901-
template: {element:'template-multi-input'}
902-
903-
});
904-
905-
ko.components.register('condition-trajectory', {
906-
viewModel: function (params) {
907-
var self = this;
908-
var offsets = ["Very poor", "Poor", "Good", "Very good"];
909-
var trajectories = ["Improving", "Deteriorating", "Stable", "Unclear"];
910-
911-
var width = 75;
912-
var boxWidth = 30;
913-
self.boxPosition = ko.computed(function() {
914-
var condition = ko.utils.unwrapObservable(params.condition);
915-
var index = offsets.indexOf(condition);
916-
return index * width + width/2 - boxWidth/2;
917-
});
918-
self.title = ko.computed(function() {
919-
var condition = ko.utils.unwrapObservable(ko.trajectory);
920-
return "Condition: "+condition+", Trajectory: "+params.trajectory;
921-
});
922-
923-
self.trajectoryTemplate = ko.computed(function() {
924-
var trajectory = ko.utils.unwrapObservable(params.trajectory);
925-
if (trajectory) {
926-
return 'template-trajectory-'+trajectory.toLowerCase();
927-
}
928-
return 'template-trajectory-none';
929-
});
930-
931-
},
932-
template:{element:'template-condition-trajectory'}
933-
934-
});
935-
936864
/**
937865
* Extends the target as a ecodata.forms.DataModelItem. This is required to support many of the
938866
* dynamic behaviour features, including warnings and conditional validation rules.

0 commit comments

Comments
 (0)