mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Add plot-abstract component
plot-abstract is the base object for all plots. Size changes on plots are saved to the server on the save button. Add sortable mixin.
This commit is contained in:
parent
15d29d23b2
commit
da09935de1
16 changed files with 240 additions and 59 deletions
|
@ -1,13 +1,16 @@
|
|||
import Ember from 'ember';
|
||||
import Sortable from '../mixins/sortable';
|
||||
|
||||
var { set } = Ember;
|
||||
|
||||
export default Ember.Component.extend({
|
||||
export default Ember.Component.extend(Sortable, {
|
||||
tagName: 'div',
|
||||
classNames: [ 'draggableDropzone plots' ],
|
||||
classNameBindings: [ 'dragClass' ],
|
||||
dragClass: 'deactivated',
|
||||
|
||||
placeholder_sort: 'plot-placeholder',
|
||||
|
||||
dragLeave(event) {
|
||||
event.preventDefault();
|
||||
set(this, 'dragClass', 'deactivated');
|
||||
|
|
33
app/components/plot-abstract.js
Normal file
33
app/components/plot-abstract.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import Ember from 'ember';
|
||||
import Resizable from '../mixins/resizable';
|
||||
|
||||
export default Ember.Component.extend(Resizable, {
|
||||
attributeBindings: [ 'style' ],
|
||||
|
||||
plot: null,
|
||||
|
||||
disabled_resize: false,
|
||||
autoHide_resize: false,
|
||||
|
||||
style: function() {
|
||||
return 'width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px;';
|
||||
}.property('plot'),
|
||||
|
||||
stop_resize(event, ui) {
|
||||
var width = ui.size.width;
|
||||
var height = ui.size.height;
|
||||
|
||||
this.set('plot.width', width);
|
||||
this.set('plot.height', height);
|
||||
},
|
||||
|
||||
_updateUI: function() {
|
||||
if (this.get('editing') === true) {
|
||||
this.set('disabled_resize', false);
|
||||
this.set('autoHide_resize', false);
|
||||
} else {
|
||||
this.set('disabled_resize', true);
|
||||
this.set('autoHide_resize', true);
|
||||
}
|
||||
}.observes('editing').on('init')
|
||||
});
|
|
@ -1,6 +1,9 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: [ 'plot' ],
|
||||
editing: false,
|
||||
|
||||
isTable: function() {
|
||||
var type = this.get('plot.type');
|
||||
return type === 'table';
|
||||
|
|
|
@ -1,20 +1,10 @@
|
|||
import Ember from 'ember';
|
||||
import Resizable from '../mixins/resizable';
|
||||
import PlotAbstract from './plot-abstract';
|
||||
|
||||
export default Ember.Component.extend(Resizable, {
|
||||
export default PlotAbstract.extend({
|
||||
tagName: 'div',
|
||||
attributeBindings: [ 'style' ],
|
||||
classNames: [ 'plotContainer', 'plotTable' ],
|
||||
|
||||
plot: null,
|
||||
editing: false,
|
||||
|
||||
style: function() {
|
||||
return 'width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px;';
|
||||
}.property('plot'),
|
||||
|
||||
stop_resize(event, ui) {
|
||||
this.set('plot.width', this.$().width());
|
||||
this.set('plot.height', this.$().height());
|
||||
}
|
||||
minWidth_resize: 200,
|
||||
minHeight_resize: 60
|
||||
});
|
||||
|
|
|
@ -1,23 +1,10 @@
|
|||
import Ember from 'ember';
|
||||
import Resizable from '../mixins/resizable';
|
||||
import PlotAbstract from './plot-abstract';
|
||||
|
||||
export default Ember.Component.extend(Resizable, {
|
||||
export default PlotAbstract.extend({
|
||||
tagName: 'div',
|
||||
attributeBindings: [ 'style' ],
|
||||
classNames: [ 'plotContainer', 'plotValue' ],
|
||||
|
||||
plot: null,
|
||||
editing: false,
|
||||
|
||||
minWidth_resize: 50,
|
||||
minHeight_resize: 20,
|
||||
|
||||
style: function() {
|
||||
return 'width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px;';
|
||||
}.property('plot'),
|
||||
|
||||
stop_resize(event, ui) {
|
||||
this.set('plot.width', this.$().width());
|
||||
this.set('plot.height', this.$().height());
|
||||
}
|
||||
minHeight_resize: 20
|
||||
});
|
||||
|
|
|
@ -33,6 +33,25 @@ export default Ember.Controller.extend({
|
|||
} else {
|
||||
console.error('Unknown plot type: ' + name);
|
||||
}
|
||||
},
|
||||
|
||||
saveEdit() {
|
||||
// save changes to store
|
||||
var plots = this.get('model.plots');
|
||||
plots.forEach(function(plot) {
|
||||
plot.save();
|
||||
});
|
||||
|
||||
// go back to index
|
||||
var id = this.get('model.id');
|
||||
this.transitionToRoute('/visualization/' + id);
|
||||
},
|
||||
|
||||
cancelEdit() {
|
||||
// TODO: revert changes
|
||||
|
||||
let id = this.get('model.id');
|
||||
this.transitionToRoute('/visualization/' + id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -61,13 +61,15 @@ export default Ember.Mixin.create({
|
|||
_gatherDragEvents(options) {
|
||||
// register callbacks for each event
|
||||
var uiDragEvents = this.get('uiDragEvents') || [];
|
||||
var _this = this;
|
||||
|
||||
uiDragEvents.forEach(function(event) {
|
||||
var callback = this[event];
|
||||
var callback = _this[event];
|
||||
if (callback) {
|
||||
options[event.split('_')[0]] = function(event, ui) {
|
||||
callback.call(this, event, ui);
|
||||
callback.call(_this, event, ui);
|
||||
};
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -60,13 +60,15 @@ export default Ember.Mixin.create({
|
|||
_gatherDropEvents(options) {
|
||||
// register callbacks for each event
|
||||
var uiDropEvents = this.get('uiDropEvents') || [];
|
||||
var _this = this;
|
||||
|
||||
uiDropEvents.forEach(function(event) {
|
||||
var callback = this[event];
|
||||
var callback = _this[event];
|
||||
if (callback) {
|
||||
options[event.split('_')[0]] = function(event, ui) {
|
||||
callback.call(this, event, ui);
|
||||
callback.call(_this, event, ui);
|
||||
};
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
uiResizeOptions: [ 'disable_resize', 'alsoResize_resize', 'animate_resize',
|
||||
uiResizeOptions: [ 'disabled_resize', 'alsoResize_resize', 'animate_resize',
|
||||
'animateDuration_resize', 'animateEasing_resize', 'aspectRatio_resize',
|
||||
'autoHide_resize', 'cancel_resize', 'containment_resize', 'delay_resize',
|
||||
'autoHide_resize', 'cancel_resize', 'containment_resize', 'delay_resize',
|
||||
'distance_resize', 'ghost_resize', 'grid_resize', 'handles_resize', 'helper_resize',
|
||||
'maxHeight_resize', 'maxWidth_resize', 'minHeight_resize', 'minWidth_resize' ],
|
||||
uiResizeEvents: [ 'create_resize', 'start_resize', 'resize_resize', 'stop_resize' ],
|
||||
|
@ -11,12 +11,12 @@ export default Ember.Mixin.create({
|
|||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
// get available options and events
|
||||
var options = this._gatherResizeOptions();
|
||||
|
||||
this._gatherResizeEvents(options);
|
||||
|
||||
// create a new jQuery UI widget
|
||||
var ui = Ember.$.ui['resizable'](options, this.get('element'));
|
||||
|
||||
this.set('ui', ui);
|
||||
},
|
||||
|
||||
|
@ -24,6 +24,7 @@ export default Ember.Mixin.create({
|
|||
var ui = this.get('ui');
|
||||
|
||||
if (ui) {
|
||||
// remove all observers for jQuery UI widget
|
||||
var observers = this._observers;
|
||||
for (var prop in observers) {
|
||||
if (observers.hasOwnProperty(prop)) {
|
||||
|
@ -31,16 +32,20 @@ export default Ember.Mixin.create({
|
|||
}
|
||||
}
|
||||
|
||||
ui._destroy();
|
||||
ui.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
_gatherResizeOptions() {
|
||||
var uiResizeOptions = this.get('uiResizeOptions'), options = {};
|
||||
// parse all options and add observers for them
|
||||
var uiResizeOptions = this.get('uiResizeOptions') || [];
|
||||
var options = {};
|
||||
|
||||
uiResizeOptions.forEach(function(key) {
|
||||
// save the resize option without the postfix
|
||||
options[key.split('_')[0]] = this.get(key);
|
||||
|
||||
// create an observer for this option
|
||||
var observer = function() {
|
||||
var value = this.get(key);
|
||||
console.log(key + ': ' + value);
|
||||
|
@ -49,6 +54,7 @@ export default Ember.Mixin.create({
|
|||
|
||||
this.addObserver(key, observer);
|
||||
|
||||
// save observer to remove it later on
|
||||
this._observers = this._observers || {};
|
||||
this._observers[key] = observer;
|
||||
}, this);
|
||||
|
@ -57,13 +63,15 @@ export default Ember.Mixin.create({
|
|||
},
|
||||
|
||||
_gatherResizeEvents(options) {
|
||||
var uiResizeEvents = this.get('uiResizeEvents') || [], self = this;
|
||||
uiResizeEvents.forEach(function(event) {
|
||||
var callback = self[event];
|
||||
// register callbacks for each event
|
||||
var uiResizeEvents = this.get('uiResizeEvents') || [];
|
||||
var _this = this;
|
||||
|
||||
uiResizeEvents.forEach(function(event) {
|
||||
var callback = _this[event];
|
||||
if (callback) {
|
||||
options[event.split('_')[0]] = function(event, ui) {
|
||||
callback.call(self, event, ui);
|
||||
callback.call(_this, event, ui);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
82
app/mixins/sortable.js
Normal file
82
app/mixins/sortable.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
uiSortOptions: [ 'appendTo_sort', 'axis_sort', 'cancel_sort', 'connectWith_sort',
|
||||
'containment_sort', 'cursor_sort', 'cursorAt_sort', 'delay_sort', 'disabled_sort',
|
||||
'distance_sort', 'dropOnEmpty_sort', 'forceHelperSize_sort', 'forcePlaceholderSize_sort',
|
||||
'grid_sort', 'handle_sort', 'helper_sort', 'items_sort', 'opacity_sort',
|
||||
'placeholder_sort', 'revert_sort', 'scroll_sort', 'scrollSensitivity_sort',
|
||||
'scrollSpeed_sort', 'tolerance_sort', 'zIndex_sort' ],
|
||||
uiSortEvents: [ 'activate_sort', 'beforeStop_sort', 'change_sort', 'create_sort',
|
||||
'deactivate_sort', 'out_sort', 'over_sort', 'receive_sort', 'remove_sort',
|
||||
'sort_sort', 'start_sort', 'stop_sort', 'update_sort' ],
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
// get available options and events
|
||||
var options = this._gatherSortOptions();
|
||||
this._gatherSortEvents(options);
|
||||
|
||||
// create a new jQuery UI widget
|
||||
var ui = Ember.$.ui['sortable'](options, this.get('element'));
|
||||
this.set('ui', ui);
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
var ui = this.get('ui');
|
||||
|
||||
if (ui) {
|
||||
// remove all observers for jQuery UI widget
|
||||
var observers = this._observers;
|
||||
for (var prop in observers) {
|
||||
if (observers.hasOwnProperty(prop)) {
|
||||
this.removeObserver(prop, observers[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
ui.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
_gatherSortOptions() {
|
||||
// parse all options and add observers for them
|
||||
var uiSortOptions = this.get('uiSortOptions') || [];
|
||||
var options = {};
|
||||
|
||||
uiSortOptions.forEach(function(key) {
|
||||
// save the sort option without the postfix
|
||||
options[key.split('_')[0]] = this.get(key);
|
||||
|
||||
// create an observer for this option
|
||||
var observer = function() {
|
||||
var value = this.get(key);
|
||||
console.log(key + ': ' + value);
|
||||
this.get('ui').option(key.split('_')[0], value);
|
||||
};
|
||||
|
||||
this.addObserver(key, observer);
|
||||
|
||||
// save observer to remove it later on
|
||||
this._observers = this._observers || {};
|
||||
this._observers[key] = observer;
|
||||
}, this);
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
_gatherSortEvents(options) {
|
||||
// register callbacks for each event
|
||||
var uiSortEvents = this.get('uiSortEvents') || [];
|
||||
var _this = this;
|
||||
|
||||
uiSortEvents.forEach(function(event) {
|
||||
var callback = _this[event];
|
||||
if (callback) {
|
||||
options[event.split('_')[0]] = function(event, ui) {
|
||||
callback.call(_this, event, ui);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
|
@ -117,8 +117,8 @@ footer {
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.plot-toolbox {
|
||||
margin-top: 20px;
|
||||
.plots > div {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.plot-add-row {
|
||||
|
@ -126,9 +126,22 @@ footer {
|
|||
font-weight: 800;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
margin-top: -25px;
|
||||
.plot-add-row > div {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.plot-toolbox {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.plot-placeholder {
|
||||
border: 1px dotted black;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.draggableDropzone {
|
||||
|
@ -166,7 +179,7 @@ footer {
|
|||
margin: 10px;
|
||||
padding: 5px 10px;
|
||||
|
||||
float: left;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.plotValue {
|
||||
|
|
1
app/templates/components/plot-abstract.hbs
Normal file
1
app/templates/components/plot-abstract.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
{{yield}}
|
|
@ -15,17 +15,19 @@
|
|||
{{/draggable-item}}
|
||||
</div>
|
||||
|
||||
{{#draggable-dropzone dropped='addPlot'}}
|
||||
{{#each model.plots as |plot|}}
|
||||
{{#plot-container plot=plot editing=true}}{{/plot-container}}
|
||||
{{/each}}
|
||||
{{/draggable-dropzone}}
|
||||
<div>
|
||||
{{#draggable-dropzone dropped='addPlot'}}
|
||||
{{#each model.plots as |plot|}}
|
||||
{{#plot-container plot=plot editing=true}}{{/plot-container}}
|
||||
{{/each}}
|
||||
{{/draggable-dropzone}}
|
||||
</div>
|
||||
|
||||
{{#draggable-dropzone dropped='addRowWithPlot'}}
|
||||
<div class="plot-add-row">+</div>
|
||||
{{/draggable-dropzone}}
|
||||
|
||||
<p>
|
||||
<p style="clear: both;">
|
||||
<button {{action 'cancelEdit'}}>Cancel</button>
|
||||
<button {{action 'saveEdit'}}>Save</button>
|
||||
</p>
|
||||
|
|
24
tests/integration/components/plot-abstract-test.js
Normal file
24
tests/integration/components/plot-abstract-test.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('plot-abstract', 'Integration | Component | plot abstract', {
|
||||
integration: true
|
||||
});
|
||||
|
||||
test('it renders', function(assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.on('myAction', function(val) { ... });
|
||||
|
||||
this.render(hbs`{{plot-abstract}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#plot-abstract}}
|
||||
template block text
|
||||
{{/plot-abstract}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
12
tests/unit/mixins/sortable-test.js
Normal file
12
tests/unit/mixins/sortable-test.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import Ember from 'ember';
|
||||
import SortableMixin from 'villasweb-frontend/mixins/sortable';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Mixin | sortable');
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it works', function(assert) {
|
||||
let SortableObject = Ember.Object.extend(SortableMixin);
|
||||
let subject = SortableObject.create();
|
||||
assert.ok(subject);
|
||||
});
|
2
todo.md
2
todo.md
|
@ -6,7 +6,7 @@
|
|||
- Websocket node is working in develop branch
|
||||
- Add API host to config/environment.js
|
||||
- Empty visualization after delete
|
||||
|
||||
- Go into edit mode if visualization is empty
|
||||
|
||||
websocketserverip/config.json
|
||||
websocketserverip/nodes.json
|
||||
|
|
Loading…
Add table
Reference in a new issue