[IMP] Enable events like Draggable and Resizable

This commit is contained in:
chintanambaliya-flectra 2017-12-01 14:22:43 +05:30 committed by Siddharth Bhalgami
parent d701e7dd58
commit 4c53003dfe
9 changed files with 319 additions and 220 deletions

View File

@ -11,145 +11,127 @@ div.ganttview-vtheader-item-name,
div.ganttview-vtheader-series, div.ganttview-vtheader-series,
div.ganttview-grid, div.ganttview-grid,
div.ganttview-grid-row-cell { div.ganttview-grid-row-cell {
float: left; float: left;
} }
div.ganttview-hzheader-month, div.ganttview-hzheader-month,
div.ganttview-hzheader-day { div.ganttview-hzheader-day {
text-align: center; text-align: center;
} }
div.ganttview-grid-row-cell.last, div.ganttview-grid-row-cell.last,
div.ganttview-hzheader-day.last, div.ganttview-hzheader-day.last,
div.ganttview-hzheader-month.last { div.ganttview-hzheader-month.last {
border-right: none; border-right: none;
} }
div.ganttview { div.ganttview {
border: 1px solid #999; border: 1px solid #999;
} }
/* Horizontal Header */ /* Horizontal Header */
div.ganttview-hzheader-month { div.ganttview-hzheader-month {
width: 60px; width: 60px;
height: 20px; height: 20px;
border-right: 1px solid #d0d0d0; border-right: 1px solid #d0d0d0;
line-height: 20px; line-height: 20px;
} }
div.ganttview-hzheader-day { div.ganttview-hzheader-day {
width: 20px; width: 20px;
height: 20px; height: 20px;
border-right: 1px solid #f0f0f0; border-right: 1px solid #f0f0f0;
border-top: 1px solid #d0d0d0; border-top: 1px solid #d0d0d0;
line-height: 20px; line-height: 20px;
color: #777; color: #777;
} }
/* Vertical Header */ /* Vertical Header */
div.ganttview-vtheader { div.ganttview-vtheader {
margin-top: 41px; margin-top: 41px;
width: auto; width: auto;
overflow: hidden; overflow: hidden;
background-color: #fff; background-color: #fff;
} }
div.ganttview-vtheader-item { div.ganttview-vtheader-item {
overflow: hidden; overflow: hidden;
color: #666; color: #666;
} }
div.ganttview-vtheader-item-name { div.ganttview-vtheader-item-name {
width: 100px; width: 100px;
padding-left: 5px; padding-left: 5px;
border-top: 1px solid #d0d0d0; border-top: 1px solid #d0d0d0;
line-height: 16px; line-height: 16px;
} }
div.ganttview-vtheader-series-name { div.ganttview-vtheader-series-name {
width: 130px; width: 130px;
height: 31px; height: 31px;
border-top: 1px solid #d0d0d0; border-top: 1px solid #d0d0d0;
line-height: 16px; line-height: 16px;
padding-left: 5px; padding-left: 5px;
} }
/* Slider */ /* Slider */
div.ganttview-slide-container { div.ganttview-slide-container {
overflow: auto; overflow: auto;
border-left: 1px solid #999; border-left: 1px solid #999;
} }
/* Grid */ /* Grid */
div.ganttview-grid-row-cell { div.ganttview-grid-row-cell {
width: 20px; width: 20px;
height: 31px; height: 31px;
border-right: 1px solid #f0f0f0; border-right: 1px solid #f0f0f0;
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
} }
div.ganttview-grid-row-cell.ganttview-weekend { div.ganttview-grid-row-cell.ganttview-weekend {
background-color: #fafafa; background-color: #fafafa;
} }
div.ganttview-grid-row-cell.ganttview-today { div.ganttview-grid-row-cell.ganttview-today {
background-color: #F7F9FF !important; background-color: #F7F9FF !important;
} }
/* Blocks */ /* Blocks */
div.ganttview-blocks { div.ganttview-blocks {
margin-top: 40px; margin-top: 40px;
} }
div.ganttview-block-container { div.ganttview-block-container {
height: 31px; height: 31px;
padding-top: 4px; padding-top: 4px;
text-align: left; text-align: left;
} }
div.ganttview-block { div.ganttview-block {
position: relative; position: relative;
height: 25px; height: 25px;
background-color: #E5ECF9; background-color: #E5ECF9;
border: 1px solid #c0c0c0; border: 1px solid #c0c0c0;
border-radius: 3px; border-radius: 3px;
-moz-border-radius: 3px; -moz-border-radius: 3px;
-webkit-border-radius: 3px; -webkit-border-radius: 3px;
} }
div.ganttview-block-text { div.ganttview-block-text {
position: absolute; position: absolute;
height: 12px; height: 12px;
font-size: 0.8em; font-size: 0.8em;
color: #999; color: #999;
padding: 2px 3px; padding: 2px 3px;
} }
/* Adjustments for jQuery UI Styling */ /* Adjustments for jQuery UI Styling */
div.ganttview-block div.ui-resizable-handle.ui-resizable-s { div.ganttview-block div.ui-resizable-handle.ui-resizable-s {
bottom: -0; bottom: -0;
} }
/* bootstrap css fix - begin */
/* Uncomment if bootstrap.js is giving you issues */
/* https://github.com/thegrubbsian/jquery.ganttView/issues/29 */
/*
#ganttChart div,
#ganttChart div:before,
#ganttChart div:after {
-webkit-box-sizing: initial;
-moz-box-sizing: initial;
box-sizing: initial;
}
*/

View File

@ -229,11 +229,11 @@ behavior: {
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].series.length; j++) { for (var j = 0; j < data[i].series.length; j++) {
var series = data[i].series[j]; var series = data[i].series[j];
var size = DateUtils.daysBetween(series.start, series.end) ? DateUtils.daysBetween(series.start, series.end) : 1; var size = DateUtils.daysBetween(series.start, series.end) + 1;
var offset = DateUtils.daysBetween(start, series.start) == 0 ? DateUtils.daysBetween(start, series.start) : DateUtils.daysBetween(start, series.start) - 1; var offset = DateUtils.daysBetween(start, series.start);
var block = jQuery("<div>", { var block = jQuery("<div>", {
"class": "ganttview-block", "class": "ganttview-block",
"title": series.name + ", " + size + " days", "title": series.name + ", " + size + " days \n"+ series.start +" to "+ series.end,
"css": { "css": {
"width": ((size * cellWidth) - 7) + "px", "width": ((size * cellWidth) - 7) + "px",
"margin-left": ((offset * cellWidth) + 3) + "px" "margin-left": ((offset * cellWidth) + 3) + "px"

View File

@ -5,24 +5,21 @@ flectra.define('web.GanttController', function (require) {
*---------------------------------------------------------*/ *---------------------------------------------------------*/
var AbstractController = require('web.AbstractController'); var AbstractController = require('web.AbstractController');
var core = require('web.core');
var qweb = core.qweb; return AbstractController.extend({
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
var GanttController = AbstractController.extend({ updateRecord: '_onUpdateRecord',
template: "GanttView", }),
/** _onUpdateRecord: function (record) {
* @override this._rpc({
* @param {Widget} parent model: this.model.modelName,
* @param {GanttModel} model method: 'write',
* @param {AbstractRenderer} renderer args: [record.data.id, {
* @param {Object} params [this.model.data.arch['date_start']]: record.data.start.toString('yyyy-M-d'),
*/ [this.model.data.arch['date_stop']]: record.data.end.toString('yyyy-M-d'),
init: function(parent, model, renderer, params) { }],
this._super.apply(this, arguments); }).then(this.reload.bind(this));
}, },
}); });
return GanttController;
}); });

View File

@ -6,169 +6,139 @@ flectra.define('web.GanttModel', function (require) {
* server. It basically just do a search_read and format/normalize data. * server. It basically just do a search_read and format/normalize data.
*/ */
var core = require('web.core');
var AbstractModel = require('web.AbstractModel'); var AbstractModel = require('web.AbstractModel');
var _t = core._t;
return AbstractModel.extend({ return AbstractModel.extend({
/** /**
* @override * @override
* @param {Object} params
*/ */
init: function () { init: function () {
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.data = null;
}, },
/** /**
* @override * @override
* @param {any} params * @param {Object} params
* @param {string[]} params.groupedBy a list of valid field names
* @param {Object} params.context
* @param {string[]} params.domain
* @returns {Deferred} * @returns {Deferred}
*/ */
load: function(params) { load: function (params) {
var self = this;
this.modelName = params.modelName; this.modelName = params.modelName;
this.gantt = { this.data = {
data: [], records: [],
domain: params.domain, domain: params.domain,
groupBy: params.groupedBy,
context: params.context, context: params.context,
groupedBy: params.groupedBy || [],
arch: params.arch.attrs, arch: params.arch.attrs,
}; };
return this._loadGantt(); return this._loadData();
}, },
/** /**
* @override * @override
* @param {any} handle ignored!
* @param {Object} params * @param {Object} params
* @param {string[]} [params.domain] * @param {string[]} params.groupedBy a list of valid field names
* @param {string[]} [params.groupBy] * @param {Object} params.context
* @param {string[]} params.domain
* @returns {Deferred} * @returns {Deferred}
*/ */
reload: function(handle, params) { reload: function (handle, params) {
if (params.domain) { if (params.domain) {
this.gantt.domain = params.domain; this.data.domain = params.domain;
}
if (params.context) {
this.data.context = params.context;
} }
if (params.groupBy) { if (params.groupBy) {
this.gantt.groupBy = params.groupBy; this.data.groupedBy = params.groupBy;
} }
return this._loadGantt(); return this._loadData();
}, },
/** /**
* Fetch and process gantt data. It is basically a read_group with correct
* fields.
*
* @returns {Deferred} * @returns {Deferred}
*/ */
_loadGantt: function() { _loadData: function () {
var self = this; var self = this;
this.gantt.data = [];
return this._rpc({ return this._rpc({
model: this.modelName, model: this.modelName,
method: 'search_read', method: 'search_read',
context: this.gantt.context, context: this.data.context,
domain: this.gantt.domain, domain: this.data.domain,
groupBy: this.gantt.groupBy, })
}).then(function(raw_datas) { .then(function (records) {
/** self.data.records = self._processData(records);
* GroupBy is only supported till 1st level ! });
* @todo Flectra: Support Multi level GroupBy },
*/ _processData: function (raw_datas) {
if(self.gantt.groupBy.length) { /**
_.each(raw_datas, function(raw_data) { * GroupBy is only supported till 1st level !
var grpByStr = raw_data[self.gantt.groupBy[0]] ? raw_data[self.gantt.groupBy[0]] : 'Undefined'; * @todo Flectra: Support Multi level GroupBy
if(grpByStr && grpByStr instanceof Array) { */
grpByStr = raw_data[self.gantt.groupBy[0]] ? raw_data[self.gantt.groupBy[0]][1] : 'Undefined'; var self = this;
} var ganttData = [];
var keyCheck = _.findKey(self.gantt.data, {name: grpByStr}); if (self.data.groupedBy.length) {
if(!keyCheck) { _.each(raw_datas, function (raw_data) {
self.gantt.data.push({ var grpByStr = raw_data[self.data.groupedBy[0]] ? raw_data[self.data.groupedBy[0]] : 'Undefined';
name: grpByStr, if (grpByStr && grpByStr instanceof Array) {
series: [], grpByStr = raw_data[self.data.groupedBy[0]] ? raw_data[self.data.groupedBy[0]][1] : 'Undefined';
}); }
} var keyCheck = _.findKey(ganttData, {name: grpByStr});
keyCheck = _.findKey(self.gantt.data, {name: grpByStr}); if (!keyCheck) {
if(self.gantt.data[keyCheck]) { ganttData.push({
if(raw_data[self.gantt.arch['date_stop']]) { name: grpByStr,
self.gantt.data[keyCheck].series.push({ series: [],
id: raw_data['id'], name: raw_data['display_name'], });
start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_stop']] }
}); keyCheck = _.findKey(ganttData, {name: grpByStr});
} else { if (ganttData[keyCheck]) {
self.gantt.data[keyCheck].series.push({ if (raw_data[self.data.arch['date_stop']]) {
id: raw_data['id'], name: raw_data['display_name'], ganttData[keyCheck].series.push({
start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_start']] id: raw_data['id'],
}); name: raw_data['display_name'],
} start: raw_data[self.data.arch['date_start']].split(' ')[0],
} end: raw_data[self.data.arch['date_stop']].split(' ')[0]
});
} else {
_.each(raw_datas, function(raw_data) {
if(raw_data[self.gantt.arch['date_stop']]) {
self.gantt.data.push({
series: [
{id: raw_data['id'], name: raw_data['display_name'],
start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_stop']]},
],
}); });
} else { } else {
self.gantt.data.push({ ganttData[keyCheck].series.push({
series: [ id: raw_data['id'],
{id: raw_data['id'], name: raw_data['display_name'], name: raw_data['display_name'],
start: raw_data[self.gantt.arch['date_start']], end: raw_data[self.gantt.arch['date_start']]}, start: raw_data[self.data.arch['date_start']].split(' ')[0],
], end: raw_data[self.data.arch['date_start']].split(' ')[0]
}); });
} }
}); }
} });
} else {
/** _.each(raw_datas, function (raw_data) {
* Render the Gantt view. if (raw_data[self.data.arch['date_stop']]) {
* ganttData.push({
* Note that This method is synchronous, but the actual rendering is done series: [
* asynchronously (in a setTimeout). {
* id: raw_data['id'],
*/ name: raw_data['display_name'],
setTimeout(function() { start: raw_data[self.data.arch['date_start']].split(' ')[0],
$(".o_gantt_view_container").empty(); end: raw_data[self.data.arch['date_stop']].split(' ')[0]
$(".o_gantt_view_container").ganttView({ },
data: self.gantt.data, ],
slideWidth: 'auto', });
cellWidth: 20, } else {
behavior: { ganttData.push({
clickable: false, series: [
draggable: false, {
resizable: false, id: raw_data['id'],
/** name: raw_data['display_name'],
* @todo Flectra: start: raw_data[self.data.arch['date_start']].split(' ')[0],
* Turn-On below events & related behavior/functions end: raw_data[self.data.arch['date_start']].split(' ')[0]
*/ },
// onClick: function(data) {}, ],
// });
// onResize: function(data) { }
// self.updateRecord(data); });
// }, }
// return ganttData;
// onDrag: function(data) {
// self.updateRecord(data);
// },
}
});
}, 0);
});
}, },
// updateRecord: function(data) {
// var self = this;
// return this._rpc({
// model: self.modelName,
// method: 'write',
// args: [[data.id], {
// [self.gantt.arch['date_start']]: data.start,
// [self.gantt.arch['date_stop']]: data.end,
// }],
// context: self.gantt.context,
// });
// },
}); });
}); });

View File

@ -0,0 +1,122 @@
flectra.define('web.GanttRenderer', function (require) {
"use strict";
/**
* The graph renderer turns the data from the graph model into a nice looking
* svg chart. This code uses the nvd3 library.
*
* Note that we use a custom build for the nvd3, with only the model we actually
* use.
*/
var core = require('web.core');
var AbstractRenderer = require('web.AbstractRenderer');
var Dialog = require('web.Dialog');
var _t = core._t;
var QWeb = core.qweb;
return AbstractRenderer.extend({
template: "GanttView",
/**
* @override
* @param {Widget} parent
* @param {Object} state
* @param {Object} params
* @param {boolean} params.stacked
*/
init: function (parent, state, params) {
this.parent = parent;
this._super.apply(this, arguments);
},
/**
* Render the chart.
*
* Note that This method is synchronous, but the actual rendering is done
* asynchronously (in a setTimeout). The reason for that is that nvd3/d3
* needs to be in the DOM to correctly render itself. So, we trick Flectra by
* returning immediately, then wait a tiny interval before actually
* displaying the data.
*
* @returns {Deferred} The _super deferred is actually resolved immediately
*/
_render: function () {
this.data = this.parent.active_view.controller.model.data;
this._loadGanttView();
return $.when();
},
_loadGanttView: function () {
var self = this;
this.$el.empty().ganttView({
data: self.data.records,
slideWidth: 'auto',
cellWidth: 20,
behavior: {
onClick: function (data) {
var dialog = new Dialog(self, {
title: _t(data.name),
$content: $(QWeb.render('GanttViewWizard')),
size: 'small',
buttons: [
{text: _t("Save"), classes: 'btn-success', click: _.bind(_callSave, self)},
{text: _t("Cancel"), classes: 'btn-danger', close: true}
]
}).open();
dialog.opened().then(function () {
var datepickers_options = {
keepOpen: true,
minDate: moment({y: 1900}),
maxDate: moment().add(200, "y"),
calendarWeeks: true,
icons: {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
next: 'fa fa-chevron-right',
previous: 'fa fa-chevron-left',
up: 'fa fa-chevron-up',
down: 'fa fa-chevron-down',
},
locale: moment.locale(),
format: "YYYY-MM-DD",
ignoreReadonly: true
};
dialog.$el.find('input#start_date').val(data.start);
dialog.$el.find('input#end_date').val(data.end);
dialog.$el.find('input#start_date, input#end_date').datetimepicker(datepickers_options);
});
function _callSave(event) {
var newData = {
start: dialog.$el.find('input#start_date').val().toString(),
end: dialog.$el.find('input#end_date').val().toString(),
id: data.id
};
if (data.start !== newData.start || data.end !== newData.end) {
var start_data = new Date(dialog.$el.find('input#start_date').val().toString()).getTime();
var end_data = new Date(dialog.$el.find('input#end_date').val().toString()).getTime();
if(start_data <= end_data){
self.trigger_up('updateRecord', newData);
dialog.close();
}else {
self.do_warn(_t("Warning"), _t("Start date should be less than or equal to End date"));
}
}
}
},
onResize: function (data) {
self.trigger_up('updateRecord', data);
},
onDrag: function (data) {
self.trigger_up('updateRecord', data);
},
}
});
this.$el.removeAttr('style');
},
});
});

View File

@ -4,10 +4,9 @@ flectra.define('web.GanttView', function (require) {
var AbstractView = require('web.AbstractView'); var AbstractView = require('web.AbstractView');
var core = require('web.core'); var core = require('web.core');
var GanttModel = require('web.GanttModel'); var GanttModel = require('web.GanttModel');
var GanttRenderer = require('web.GanttRenderer');
var Controller = require('web.GanttController'); var Controller = require('web.GanttController');
var AbstractRenderer = require('web.AbstractRenderer');
var _t = core._t;
var _lt = core._lt; var _lt = core._lt;
var GanttView = AbstractView.extend({ var GanttView = AbstractView.extend({
@ -16,7 +15,7 @@ var GanttView = AbstractView.extend({
config: { config: {
Model: GanttModel, Model: GanttModel,
Controller: Controller, Controller: Controller,
Renderer: AbstractRenderer, Renderer: GanttRenderer,
}, },
/** /**
* @override * @override
@ -24,7 +23,6 @@ var GanttView = AbstractView.extend({
init: function(viewInfo) { init: function(viewInfo) {
this._super.apply(this, arguments); this._super.apply(this, arguments);
var arch = viewInfo.arch; var arch = viewInfo.arch;
var fields = viewInfo.fields;
this.loadParams.arch = arch; this.loadParams.arch = arch;
}, },
}); });

View File

@ -532,6 +532,35 @@
<div class="o_gantt_view_container"/> <div class="o_gantt_view_container"/>
</t> </t>
<t t-name="GanttViewWizard">
<table class="o_group o_inner_group" style="width: 100%;">
<tbody>
<tr>
<td class="o_td_label" style="padding: 10px 10px 10px 20px;">
<label class="o_form_label" for="start_date">Start Date</label>
</td>
<td style="width: 65%; padding: 10px 10px 10px 20px;">
<div class="o_datepicker o_field_date o_field_widget" name="date_from">
<input class="o_datepicker_input o_input"
type="text" name="date_from" id="start_date"/>
</div>
</td>
</tr>
<tr>
<td class="o_td_label" style="padding: 10px 10px 10px 20px;">
<label class="o_form_label" for="end_date">End Date</label>
</td>
<td style="width: 65%; padding: 10px 10px 10px 20px;">
<div class="o_datepicker o_field_date o_field_widget" name="date_to">
<input class="o_datepicker_input o_input"
type="text" name="date_to" id="end_date"/>
</div>
</td>
</tr>
</tbody>
</table>
</t>
<div t-name="PivotView" class="o_pivot"> <div t-name="PivotView" class="o_pivot">
<div class="o_field_selection"/> <div class="o_field_selection"/>
</div> </div>

View File

@ -242,9 +242,10 @@
<link rel="stylesheet" type="text/css" href="/web/static/lib/jquery.ganttView/jquery.ganttView.css"/> <link rel="stylesheet" type="text/css" href="/web/static/lib/jquery.ganttView/jquery.ganttView.css"/>
<script type="text/javascript" src="/web/static/lib/jquery.ganttView/jquery.ganttView.js"/> <script type="text/javascript" src="/web/static/lib/jquery.ganttView/jquery.ganttView.js"/>
<script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_controller.js"/>
<script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_view.js"/>
<script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_model.js"/> <script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_model.js"/>
<script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_controller.js"/>
<script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_renderer.js"/>
<script type="text/javascript" src="/web/static/src/js/views/gantt/gantt_view.js"/>
<!-- @Flectra: Gantt View Assets ::: End --> <!-- @Flectra: Gantt View Assets ::: End -->
</template> </template>