Browse Source

Gantt #1932 (#2073)

* [wip] added frappe/gantt

* frappe/gantt

[gantt] added view modes

[gantt] added vertical grid, view modes fixed

[gantt] fix bar_onclick

[gantt] fix view_mode rendering

[gantt] drag, resize gantt bar

[gantt] fixed month view

[gantt] separate styling

[gantt] save on datechange, progress field added

[gantt] fixed drag to snap on week/month
version-14
Faris Ansari 8 years ago
committed by Rushabh Mehta
parent
commit
1ee9ee886e
25 changed files with 1294 additions and 2985 deletions
  1. +1
    -1
      frappe/desk/page/chat/chat.js
  2. +3
    -4
      frappe/public/build.json
  3. +77
    -37
      frappe/public/css/gantt.css
  4. +134
    -11
      frappe/public/js/frappe/list/doclistview.js
  5. +6
    -4
      frappe/public/js/frappe/list/list_sidebar.html
  6. +28
    -31
      frappe/public/js/frappe/list/list_sidebar.js
  7. +4
    -9
      frappe/public/js/frappe/list/listview.js
  8. +24
    -24
      frappe/public/js/frappe/ui/filters/filters.js
  9. +4
    -4
      frappe/public/js/frappe/ui/listing.html
  10. +29
    -41
      frappe/public/js/frappe/ui/listing.js
  11. +3
    -3
      frappe/public/js/frappe/ui/tags.js
  12. +4
    -4
      frappe/public/js/frappe/ui/tree.js
  13. +864
    -0
      frappe/public/js/frappe/views/gantt.js
  14. +3
    -3
      frappe/public/js/frappe/views/reports/reportview.js
  15. +0
    -23
      frappe/public/js/lib/jQuery.Gantt/README.md
  16. +0
    -428
      frappe/public/js/lib/jQuery.Gantt/css/style.css
  17. BIN
      frappe/public/js/lib/jQuery.Gantt/img/grid.png
  18. BIN
      frappe/public/js/lib/jQuery.Gantt/img/icon_sprite.png
  19. BIN
      frappe/public/js/lib/jQuery.Gantt/img/slider_handle.png
  20. +0
    -551
      frappe/public/js/lib/jQuery.Gantt/index.html
  21. +0
    -1758
      frappe/public/js/lib/jQuery.Gantt/js/jquery.fn.gantt.js
  22. +0
    -20
      frappe/public/js/lib/jQuery.Gantt/js/jquery.fn.gantt.min.js
  23. +21
    -0
      frappe/public/js/lib/snap.svg-min.js
  24. +88
    -29
      frappe/public/less/gantt.less
  25. +1
    -0
      patches.txt

+ 1
- 1
frappe/desk/page/chat/chat.js View File

@@ -61,7 +61,7 @@ frappe.Chat = Class.extend({
var $row = $('<div class="list-row"/>');
frappe.pages.chat.chat.list.data.unshift(comment);
frappe.pages.chat.chat.list.render_row($row, comment);
frappe.pages.chat.chat.list.$w.prepend($row);
frappe.pages.chat.chat.list.wrapper.prepend($row);
},

make_sidebar: function() {


+ 3
- 4
frappe/public/build.json View File

@@ -193,8 +193,7 @@
"css/list.min.css": [
"public/css/list.css",
"public/css/tag-it.css",
"public/css/calendar.css",
"public/css/gantt.css"
"public/css/calendar.css"
],
"js/list.min.js": [
"public/js/frappe/ui/listing.html",
@@ -219,13 +218,13 @@
"public/js/frappe/list/listview.js",
"public/js/frappe/views/calendar_base.js",
"public/js/frappe/views/calendar.js",
"public/js/frappe/views/ganttview.js",
"public/js/frappe/list/blueimp-gallery.html",
"public/js/frappe/list/image_view_item_row.html",
"public/js/frappe/list/image_view_item_main_head.html",
"public/js/frappe/list/header_select_all_like_filter.html",
"public/js/frappe/list/item_assigned_to_comment_count.html",
"public/js/frappe/views/treeview.js"
"public/js/frappe/views/treeview.js",
"public/js/frappe/views/gantt.js"
],
"css/report.min.css": [
"public/css/report.css",


+ 77
- 37
frappe/public/css/gantt.css View File

@@ -1,38 +1,78 @@
.gantt,
.gantt2 {
border: none !important;
border-radius: none !important;
margin: 0px auto !important;
}
.gantt *,
.gantt2 * {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.fn-gantt .leftPanel,
.fn-gantt .leftPanel .row0,
.fn-gantt .leftPanel .name,
.fn-gantt .leftPanel .desc,
.fn-gantt .dataPanel,
.fn-gantt .day,
.fn-gantt .date,
.fn-gantt .rightPanel .month,
.fn-gantt .rightPanel .year {
border-color: #d1d8dd !important;
}
.fn-gantt .navigate {
border: none !important;
}
.fn-gantt .leftPanel .name,
.fn-gantt .leftPanel .desc,
.fn-gantt .spacer,
.fn-gantt .wd,
.fn-gantt .rightPanel .month,
.fn-gantt .rightPanel .year,
.fn-gantt .bottom {
background-color: #F7FAFC !important;
}
.fn-gantt .today {
background-color: #D9F6FF !important;
.gantt #grid .grid-background {
fill: none;
}
.gantt #grid .grid-header {
fill: #fff;
stroke: #e0e0e0;
stroke-width: 1.4;
}
.gantt #grid .row-odd {
fill: #ffffff;
}
.gantt #grid .row-even {
fill: #f5f5f5;
}
.gantt #grid .row-line {
stroke: #EBEFF2;
}
.gantt #grid .tick {
stroke: #aaa;
stroke-width: 0.2;
}
.gantt #grid .tick.thick {
stroke-width: 0.4;
}
.gantt #arrow {
fill: none;
stroke: #333;
stroke-width: 1.4;
}
.gantt .bar {
fill: #b8c2cc;
stroke: #8D99A6;
stroke-width: 0;
transition: stroke-width 0.3s ease;
}
.gantt .bar-label {
fill: #fff;
dominant-baseline: central;
text-anchor: middle;
font-size: 12px;
font-weight: lighter;
letter-spacing: 0.8px;
}
.gantt .bar-label.big {
fill: #555;
text-anchor: start;
}
.gantt .handle {
fill: #ddd;
cursor: ew-resize;
opacity: 0;
visibility: hidden;
transition: opacity .3s ease;
}
.gantt .bar-wrapper {
cursor: pointer;
}
.gantt .bar-wrapper:hover .bar {
stroke-width: 2;
}
.gantt .bar-wrapper:hover .handle {
visibility: visible;
opacity: 1;
}
.gantt .bar-wrapper.active .bar {
stroke-width: 2;
}
.gantt .primary-text,
.gantt .secondary-text {
font-size: 12px;
text-anchor: middle;
}
.gantt .primary-text {
fill: #999;
}
.gantt .secondary-text {
fill: #555;
}

+ 134
- 11
frappe/public/js/frappe/list/doclistview.js View File

@@ -130,14 +130,13 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
this.init_listview();
this.setup_filterable();
this.init_filters();
this.init_headers();
this.init_sort_selector();
this.init_like();
this.init_select_all();
},

init_headers: function() {
this.header = this.meta.image_view == 0? "list_item_main_head": "image_view_item_main_head";
this.page.main.find(".list-headers").empty();

this.header = this.current_view === 'List' ? "list_item_main_head": "image_view_item_main_head";
var main = frappe.render_template(this.header, {
columns: this.listview.columns,
right_column: this.listview.settings.right_column,
@@ -147,6 +146,9 @@ frappe.views.DocListView = frappe.ui.Listing.extend({

this.list_header = $(frappe.render_template("list_item_row_head", { main:main, list:this.listview }))
.appendTo(this.page.main.find(".list-headers"));

this.init_like();
this.init_select_all();
},

init_listview: function() {
@@ -303,7 +305,14 @@ frappe.views.DocListView = frappe.ui.Listing.extend({

refresh: function(dirty) {
if(dirty!==undefined) this.dirty = dirty;
this.init_stats();
this.refresh_sidebar();

// if view has changed, re-render header
if(this.current_view != this.list_sidebar.current_view) {
this.current_view = this.list_sidebar.current_view;
this.init_headers();
this.dirty = true;
}

if(this.listview.settings.refresh) {
this.listview.settings.refresh(this);
@@ -354,8 +363,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({

if(!this.listview.settings.use_route) {
var route = frappe.get_route();
var me = this;
if(route[2]) {
if(route[2] && !in_list(['Image', 'Gantt'], route[2])) {
$.each(frappe.utils.get_args_dict_from_url(route[2]), function(key, val) {
me.set_filter(key, val, true);
});
@@ -401,16 +409,131 @@ frappe.views.DocListView = frappe.ui.Listing.extend({

return no_result_message;
},

render_rows: function(values) {
this['render_rows_' + this.current_view](values);
},

render_rows_Image: function(values) {
var cols = values.slice();
while (cols.length) {
row = this.add_row(cols[0]);
$("<div class='row image-view-marker'></div>").appendTo(row);
$(row).addClass('no-hover');
this.render_image_view_row(row, cols.splice(0, 4));
}

this.render_image_gallery();
},

render_rows_List: function(values) {
var m = Math.min(values.length, this.page_length);
for(var i=0; i < m; i++) {
this.render_row(this.add_row(values[i]), values[i], this, i);
}
},

render_rows_Gantt: function(values) {
var gantt_area = $('<svg height="400" width="6000"></svg>')
.appendTo(this.wrapper.find('.result-list').css("overflow", "scroll"));
var id = frappe.dom.set_unique_id(gantt_area);
var me = this;
var field_map = frappe.views.calendar[this.doctype].field_map;

var view_modes;
frappe.require(["assets/frappe/js/lib/snap.svg-min.js", "assets/frappe/css/gantt.css"], function() {
me.gantt = new Gantt({
parent_selector: '#' + id,
bar: {
height: 20,
color: "#b8c2cc",
progress_color: "#a3a3ff",
hover_color: "#8D99A6",
hover_progress_color: "#7575ff"
},
events: {
bar_on_click: function (task) {
frappe.set_route('Form', task.doctype, task.id);
},
bar_on_datechange: function(task, start, end) {
update_date(task.id, field_map.start, start.format("YYYY-MM-DD"), function() {
update_date(task.id, field_map.end, end.format("YYYY-MM-DD"), function() {
show_alert("Saved", 1);
});
});
},
on_viewmode_change: function(mode) {
me.list_settings.view_mode = mode;
}
}
});

view_modes = me.gantt.opts.valid_view_modes || [];
values.forEach(function(item) {
me.gantt.add_task({
start: item[field_map.start],
end: item[field_map.end],
name: item[field_map.title],
id: item[field_map.id],
doctype: me.doctype,
progress: item.progress
});
})
me.gantt.render();

var dropdown = "<div class='dropdown pull-right'>" +
"<a class='text-muted dropdown-toggle' data-toggle='dropdown'>" +
"<span class='dropdown-text'>Day</span><i class='caret'></i></a>" +
"<ul class='dropdown-menu'></ul>" +
"</div>";

var dropdown_list = "";
view_modes.forEach(function(view_mode) {
dropdown_list += "<li>" +
"<a class='option' data-value='"+view_mode+"'>" +
view_mode + "</a></li>";
})
var $dropdown = $(dropdown)
$dropdown.find(".dropdown-menu")
.append(dropdown_list);

me.$page.find(".list-row-right").css("margin-top", 0).html($dropdown)

$dropdown.on("click", ".option", function() {
var mode = $(this).data('value');
me.gantt.set_view_mode(mode)
$dropdown.find(".dropdown-text").text(mode);
})
});

function update_date(id, fieldname, value, callback) {
frappe.call({
method: "frappe.client.set_value",
args: {
doctype: me.doctype,
name: id,
fieldname: fieldname,
value: value
},
callback: function(r) {
callback();
}
});
}
},

render_row: function(row, data) {
data.doctype = this.doctype;
this.listview.render(row, data, this);
},

render_image_view_row: function(row, data) {
for (var i = 0; i < data.length; i++) {
data[i].doctype = this.doctype;
this.listview.render(row, data[i], this)
}
},

get_args: function() {
var args = {
doctype: this.doctype,
@@ -644,7 +767,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
});

// after delete, hide delete button
this.$w.on("render-complete", function() {
this.wrapper.on("render-complete", function() {
me.toggle_delete();
});
}
@@ -675,7 +798,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
get_checked_items: function() {
var me = this;
return $.map(this.$page.find('.list-delete:checked'), function(e) {
if(me.meta.image_view == 0){
if(me.current_view==='List'){
return $(e).parents(".list-row:first").data('data');
}
else{
@@ -711,9 +834,9 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
}
);
},
init_stats: function() {
refresh_sidebar: function() {
var me = this;
this.sidebar_stats = new frappe.views.ListSidebar({
this.list_sidebar = new frappe.views.ListSidebar({
doctype: this.doctype,
stats: this.listview.stats,
parent: this.$page.find('.layout-side-section'),


+ 6
- 4
frappe/public/js/frappe/list/list_sidebar.html View File

@@ -14,15 +14,17 @@
</div>
</li>
<li class="divider"></li>
<li class="hide list-link" data-view="List">
<a href="#List/{%= doctype %}">{%= __("List") %}</a></li>
<li class="hide list-link" data-view="Image">
<a href="#List/{%= doctype %}/Image">{%= __("Images") %}</a></li>
<li class="hide list-link" data-view="Gantt">
<a href="#List/{%= doctype %}/Gantt">{%= __("Gantt") %}</a></li>
<li class="hide tree-link"><a href="#Tree/{%= doctype %}">{%= __("Tree") %}</a></li>
<li class="hide calendar-link"><a href="#Calendar/{%= doctype %}">{%= __("Calendar") %}</a></li>
<li class="hide gantt-link"><a href="#Gantt/{%= doctype %}">{%= __("Gantt") %}</a></li>
<li class="assigned-to-me">
<a>{%= __("Assigned To Me") %}</a>
</li>
<li class="hide switch-list-view">
<a>{%= __("Show Images") %}</a>
</li>
{% if(frappe.help.has_help(doctype)) { %}
<li><a class="help-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li>
{% } %}


+ 28
- 31
frappe/public/js/frappe/list/list_sidebar.js View File

@@ -24,15 +24,41 @@ frappe.views.ListSidebar = Class.extend({

this.setup_reports();
this.setup_assigned_to_me();
this.setup_list_view_switching();
this.setup_views();

},
setup_views: function() {
var show_list_link = false;

if(frappe.views.calendar[this.doctype]) {
this.sidebar.find(".calendar-link, .gantt-link").removeClass("hide");
this.sidebar.find(".calendar-link").removeClass("hide");
this.sidebar.find('.list-link[data-view="Gantt"]').removeClass('hide');
show_list_link = true;
}

if(frappe.treeview_settings[this.doctype]) {
this.sidebar.find(".tree-link").removeClass("hide");
}

this.current_view = 'List';
var route = frappe.get_route();
if(route.length > 2 && (route[2]==='Gantt' || route[2]==='Image')) {
this.current_view = route[2];
}

// disable link for current view
this.sidebar.find('.list-link[data-view="'+ this.current_view +'"] a')
.attr('disabled', 'disabled').addClass('disabled');

// show image link if image_view
if(this.doclistview.meta.image_field) {
this.sidebar.find('.list-link[data-view="Image"]').removeClass('hide');
show_list_link = true;
}

if(show_list_link) {
this.sidebar.find('.list-link[data-view="List"]').removeClass('hide');
}
},
setup_reports: function() {
// add reports linked to this doctype to the dropdown
@@ -78,35 +104,6 @@ frappe.views.ListSidebar = Class.extend({
me.doclistview.assigned_to_me();
});
},
setup_list_view_switching: function() {
var me = this;
if(this.doclistview.meta.image_field) {
this.page.sidebar.find(".switch-list-view").removeClass("hide");

var label = this.doclistview.meta.image_view ? __("Show List"): __("Show Images");
this.page.sidebar.find(".switch-list-view a").html(label)

var switch_list_view = function(view) {
var image_view = 0
if(view == __("Show Images"))
image_view = 1

me.doclistview.meta.image_view = image_view;

// clear and render the headers again while switching
me.doclistview.page.main.find(".list-headers").empty();
me.doclistview.init_headers();
me.doclistview.init_like();
me.doclistview.init_select_all();

me.doclistview.refresh(true);
};

this.page.sidebar.find(".switch-list-view a").on("click", function() {
switch_list_view(label)
});
}
},
get_stats: function() {
var me = this
return frappe.call({


+ 4
- 9
frappe/public/js/frappe/list/listview.js View File

@@ -214,12 +214,7 @@ frappe.views.ListView = Class.extend({
this.id_list.push(data.name);
}

if(this.meta && this.meta.image_view == 0){
this.render_list_row(row, data);
}
else{
this.render_list_image(row, data);
}
this['render_row_' + this.doclistview.current_view](row, data);

if(this.settings.post_render_item) {
this.settings.post_render_item(this, row, data);
@@ -228,7 +223,7 @@ frappe.views.ListView = Class.extend({
this.render_tags(row, data);

},
render_list_row: function(row, data) {
render_row_List: function(row, data) {
var main = frappe.render_template("list_item_main", {
data: data,
columns: this.columns,
@@ -244,7 +239,7 @@ frappe.views.ListView = Class.extend({
right_column: this.settings.right_column
})).appendTo(row);
},
render_list_image: function(row, data) {
render_row_Image: function(row, data) {
this.allowed_type = [
"Check", "Currency", "Data", "Date",
"Datetime", "Float", "Int", "Link",
@@ -290,7 +285,7 @@ frappe.views.ListView = Class.extend({
//me.render_timestamp_and_comments(row, data);
}
});
tag_editor.$w.on("click", ".tagit-label", function() {
tag_editor.wrapper.on("click", ".tagit-label", function() {
me.doclistview.set_filter("_user_tags",
$(this).text());
});


+ 24
- 24
frappe/public/js/frappe/ui/filters/filters.js View File

@@ -5,22 +5,22 @@ frappe.ui.FilterList = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.filters = [];
this.$w = this.$parent;
this.wrapper = this.$parent;
this.set_events();
},
set_events: function() {
var me = this;
// show filters
this.$w.find('.new-filter').bind('click', function() {
this.wrapper.find('.new-filter').bind('click', function() {
me.add_filter(me.doctype, 'name');
});
},

show_filters: function() {
this.$w.find('.show_filters').toggle();
this.wrapper.find('.show_filters').toggle();
if(!this.filters.length) {
this.add_filter(this.doctype, 'name');
this.filters[0].$w.find(".filter_field input").focus();
this.filters[0].wrapper.find(".filter_field input").focus();
}
},

@@ -42,10 +42,10 @@ frappe.ui.FilterList = Class.extend({
}


this.$w.find('.show_filters').toggle(true);
this.wrapper.find('.show_filters').toggle(true);
var is_new_filter = arguments.length===0;

if (is_new_filter && this.$w.find(".is-new-filter:visible").length) {
if (is_new_filter && this.wrapper.find(".is-new-filter:visible").length) {
// only allow 1 new filter at a time!
return;
}
@@ -53,7 +53,7 @@ frappe.ui.FilterList = Class.extend({
var filter = this.push_new_filter(doctype, fieldname, condition, value);

if (filter && is_new_filter) {
filter.$w.addClass("is-new-filter");
filter.wrapper.addClass("is-new-filter");
}

if (filter && hidden) {
@@ -131,12 +131,12 @@ frappe.ui.Filter = Class.extend({
this.set_events();
},
make: function() {
this.$w = $(frappe.render_template("edit_filter", {})).appendTo(this.flist.$w.find('.filter_area'));
this.wrapper = $(frappe.render_template("edit_filter", {})).appendTo(this.flist.wrapper.find('.filter_area'));
},
make_select: function() {
var me = this;
this.fieldselect = new frappe.ui.FieldSelect({
parent: this.$w.find('.fieldname_select_area'),
parent: this.wrapper.find('.fieldname_select_area'),
doctype: this.doctype,
filter_fields: this.filter_fields,
select: function(doctype, fieldname) {
@@ -150,17 +150,17 @@ frappe.ui.Filter = Class.extend({
set_events: function() {
var me = this;

this.$w.find("a.remove-filter").on("click", function() {
this.wrapper.find("a.remove-filter").on("click", function() {
me.remove();
});

this.$w.find(".set-filter-and-run").on("click", function() {
me.$w.removeClass("is-new-filter");
this.wrapper.find(".set-filter-and-run").on("click", function() {
me.wrapper.removeClass("is-new-filter");
me.flist.listobj.run();
});

// add help for "in" codition
me.$w.find('.condition').change(function() {
me.wrapper.find('.condition').change(function() {
if(!me.field) return;
var condition = $(this).val();
if(in_list(["in", "like", "not in", "not like"], condition)) {
@@ -188,7 +188,7 @@ frappe.ui.Filter = Class.extend({
},

remove: function(dont_run) {
this.$w.remove();
this.wrapper.remove();
this.$btn_group && this.$btn_group.remove();
this.field = null;
this.flist.update_filters();
@@ -202,7 +202,7 @@ frappe.ui.Filter = Class.extend({
set_values: function(doctype, fieldname, condition, value) {
// presents given (could be via tags!)
this.set_field(doctype, fieldname);
if(condition) this.$w.find('.condition').val(condition).change();
if(condition) this.wrapper.find('.condition').val(condition).change();
if(value!=null) this.field.set_input(value);
},

@@ -247,7 +247,7 @@ frappe.ui.Filter = Class.extend({
old_text = me.field.get_parsed_value();
}

var field_area = me.$w.find('.filter_field').empty().get(0);
var field_area = me.wrapper.find('.filter_field').empty().get(0);
var f = frappe.ui.form.make_control({
df: df,
parent: field_area,
@@ -301,7 +301,7 @@ frappe.ui.Filter = Class.extend({
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments',
'Dynamic Link','Read Only','Assign'].indexOf(df.fieldtype)!=-1) {
df.fieldtype = 'Data';
} else if(df.fieldtype=='Link' && this.$w.find('.condition').val()!="=") {
} else if(df.fieldtype=='Link' && this.wrapper.find('.condition').val()!="=") {
df.fieldtype = 'Data';
}
if(df.fieldtype==="Data" && (df.options || "").toLowerCase()==="email") {
@@ -313,9 +313,9 @@ frappe.ui.Filter = Class.extend({
if(!fieldtype) {
// set as "like" for data fields
if(df.fieldtype=='Data') {
this.$w.find('.condition').val('like');
this.wrapper.find('.condition').val('like');
} else {
this.$w.find('.condition').val('=');
this.wrapper.find('.condition').val('=');
}
}
},
@@ -356,14 +356,14 @@ frappe.ui.Filter = Class.extend({
},

get_condition: function() {
return this.$w.find('.condition').val();
return this.wrapper.find('.condition').val();
},

freeze: function() {
if(this.$btn_group) {
// already made, just hide the condition setter
this.set_filter_button_text();
this.$w.toggle(false);
this.wrapper.toggle(false);
return;
}

@@ -379,7 +379,7 @@ frappe.ui.Filter = Class.extend({
title="'+__("Remove Filter")+'">\
<i class="icon-remove text-muted"></i>\
</button></div>')
.insertAfter(this.flist.$w.find(".set-filters .new-filter"));
.insertAfter(this.flist.wrapper.find(".set-filters .new-filter"));

this.set_filter_button_text();

@@ -388,9 +388,9 @@ frappe.ui.Filter = Class.extend({
});

this.$btn_group.find(".toggle-filter").on("click", function() {
me.$w.toggle();
me.wrapper.toggle();
})
this.$w.toggle(false);
this.wrapper.toggle(false);
},

set_filter_button_text: function() {


+ 4
- 4
frappe/public/js/frappe/ui/listing.html View File

@@ -27,15 +27,15 @@
<div class="list-paging-area">
<div class="row">
<div class="col-xs-6">
<button class="btn btn-default btn-more btn-sm">{%= _more %}...</button>
</div>
<div class="col-xs-6">
<div class="btn-group pull-right btn-group-paging">
<div class="btn-group btn-group-paging">
<button type="button" class="btn btn-default btn-sm btn-info" data-value="20">20</button>
<button type="button" class="btn btn-default btn-sm" data-value="100">100</button>
<button type="button" class="btn btn-default btn-sm" data-value="500">500</button>
</div>
</div>
<div class="col-xs-6 text-right">
<button class="btn btn-default btn-more btn-sm">{%= _more %}...</button>
</div>
</div>
</div>
</div>

+ 29
- 41
frappe/public/js/frappe/ui/listing.js View File

@@ -64,11 +64,11 @@ frappe.ui.Listing = Class.extend({
$.extend(this, this.opts);

$(this.parent).html(frappe.render_template("listing", this.opts));
this.$w = $(this.parent).find('.frappe-list');
this.wrapper = $(this.parent).find('.frappe-list');
this.set_events();

if(this.page) {
this.$w.find('.list-toolbar-wrapper').toggle(false);
this.wrapper.find('.list-toolbar-wrapper').toggle(false);
}

if(this.show_filters) {
@@ -79,9 +79,9 @@ frappe.ui.Listing = Class.extend({
if(this.page) {
return this.page.add_menu_item(label, click, icon)
} else {
this.$w.find('.list-toolbar-wrapper').removeClass("hide");
this.wrapper.find('.list-toolbar-wrapper').removeClass("hide");
$button = $('<button class="btn btn-default"></button>')
.appendTo(this.$w.find('.list-toolbar'))
.appendTo(this.wrapper.find('.list-toolbar'))
.html((icon ? ("<i class='"+icon+"'></i> ") : "") + label)
.click(click);
return $button
@@ -91,13 +91,13 @@ frappe.ui.Listing = Class.extend({
var me = this;

// next page
this.$w.find('.btn-more').click(function() {
this.wrapper.find('.btn-more').click(function() {
me.run(true);
});

this.$w.find(".btn-group-paging .btn").click(function() {
this.wrapper.find(".btn-group-paging .btn").click(function() {
me.page_length = cint($(this).attr("data-value"));
me.$w.find(".btn-group-paging .btn-info").removeClass("btn-info");
me.wrapper.find(".btn-group-paging .btn-info").removeClass("btn-info");
$(this).addClass("btn-info");

// always reset when changing list page length
@@ -106,20 +106,20 @@ frappe.ui.Listing = Class.extend({

// select the correct page length
if(this.opts.page_length != 20) {
this.$w.find(".btn-group-paging .btn-info").removeClass("btn-info");
this.$w.find(".btn-group-paging .btn[data-value='"+ this.opts.page_length +"']").addClass('btn-info');
this.wrapper.find(".btn-group-paging .btn-info").removeClass("btn-info");
this.wrapper.find(".btn-group-paging .btn[data-value='"+ this.opts.page_length +"']").addClass('btn-info');
}

// title
if(this.title) {
this.$w.find('h3').html(this.title).toggle(true);
this.wrapper.find('h3').html(this.title).toggle(true);
}

// new
this.set_primary_action();

if(me.no_toolbar || me.hide_toolbar) {
me.$w.find('.list-toolbar-wrapper').toggle(false);
me.wrapper.find('.list-toolbar-wrapper').toggle(false);
}
},

@@ -159,7 +159,7 @@ frappe.ui.Listing = Class.extend({
make_filters: function() {
this.filter_list = new frappe.ui.FilterList({
listobj: this,
$parent: this.$w.find('.list-filters').toggle(true),
$parent: this.wrapper.find('.list-filters').toggle(true),
doctype: this.doctype,
filter_fields: this.filter_fields
});
@@ -170,9 +170,9 @@ frappe.ui.Listing = Class.extend({

clear: function() {
this.data = [];
this.$w.find('.result-list').empty();
this.$w.find('.result').toggle(true);
this.$w.find('.no-result').toggle(false);
this.wrapper.find('.result-list').empty();
this.wrapper.find('.result').toggle(true);
this.wrapper.find('.no-result').toggle(false);
this.start = 0;
},

@@ -274,7 +274,7 @@ frappe.ui.Listing = Class.extend({
}
},
set_working: function(flag) {
this.$w.find('.img-load').toggle(flag);
this.wrapper.find('.img-load').toggle(flag);
},
get_call_args: function() {
// load query
@@ -305,7 +305,7 @@ frappe.ui.Listing = Class.extend({
render_results: function(r) {
if(this.start===0) this.clear();

this.$w.find('.btn-more, .list-loading').toggle(false);
this.wrapper.find('.btn-more, .list-loading').toggle(false);

if(r.message) {
r.values = this.get_values_from_response(r.message);
@@ -317,7 +317,7 @@ frappe.ui.Listing = Class.extend({
this.update_paging(r.values);
} else {
if(this.start===0) {
this.$w.find('.result').toggle(false);
this.wrapper.find('.result').toggle(false);

var msg = this.get_no_result_message
? this.get_no_result_message()
@@ -325,7 +325,7 @@ frappe.ui.Listing = Class.extend({
? this.no_result_message
: __("Nothing to show"));

this.$w.find('.no-result')
this.wrapper.find('.no-result')
.html(msg)
.toggle(true);
}
@@ -334,7 +334,7 @@ frappe.ui.Listing = Class.extend({
// callbacks
if(this.onrun) this.onrun();
if(this.callback) this.callback(r);
this.$w.trigger("render-complete");
this.wrapper.trigger("render-complete");
},

get_values_from_response: function(data) {
@@ -356,21 +356,9 @@ frappe.ui.Listing = Class.extend({
},
render_rows: function(values) {
// render the rows
if(this.meta && this.meta.image_view){
var cols = values.slice();
while (cols.length) {
row = this.add_row(cols[0]);
$("<div class='row image-view-marker'></div>").appendTo(row);
$(row).addClass('no-hover');
this.render_image_view_row(row, cols.splice(0, 4), this, i);
}

this.render_image_gallery();
} else {
var m = Math.min(values.length, this.page_length);
for(var i=0; i < m; i++) {
this.render_row(this.add_row(values[i]), values[i], this, i);
}
var m = Math.min(values.length, this.page_length);
for(var i=0; i < m; i++) {
this.render_row(this.add_row(values[i]), values[i], this, i);
}
},
render_image_gallery: function(){
@@ -384,17 +372,17 @@ frappe.ui.Listing = Class.extend({
"assets/frappe/js/lib/gallery/css/blueimp-gallery-indicator.css"
], function(){
// remove previous gallery container
me.$w.find(".blueimp-gallery").remove();
me.wrapper.find(".blueimp-gallery").remove();
// append gallery div
var gallery = frappe.render_template("blueimp-gallery", {});
$(gallery).appendTo(me.$w);
$(gallery).appendTo(me.wrapper);

me.$w.find(".zoom-view").click(function(event){
me.wrapper.find(".zoom-view").click(function(event){
event.preventDefault();
opts = {
doctype: me.doctype,
docname: $(this).parent().attr('data-name'),
container: me.$w
container: me.wrapper
};
new frappe.views.ImageView(opts);
});
@@ -402,14 +390,14 @@ frappe.ui.Listing = Class.extend({
},
update_paging: function(values) {
if(values.length >= this.page_length) {
this.$w.find('.btn-more').toggle(true);
this.wrapper.find('.btn-more').toggle(true);
this.start += this.page_length;
}
},
add_row: function(row) {
return $('<div class="list-row">')
.data("data", (this.meta && this.meta.image_view) == 0 ? row : null)
.appendTo(this.$w.find('.result-list'))
.appendTo(this.wrapper.find('.result-list'))
.get(0);
},
refresh: function() {


+ 3
- 3
frappe/public/js/frappe/ui/tags.js View File

@@ -13,8 +13,8 @@ frappe.ui.TagEditor = Class.extend({
*/
$.extend(this, opts);
var me = this;
this.$w = $('<div class="tag-line">').appendTo(this.parent)
this.$tags = $('<ul>').prependTo(this.$w);
this.wrapper = $('<div class="tag-line">').appendTo(this.parent)
this.$tags = $('<ul>').prependTo(this.wrapper);
this.$tags.tagit({
animate: false,
allowSpaces: true,
@@ -59,7 +59,7 @@ frappe.ui.TagEditor = Class.extend({
},
setup_autocomplete: function() {
var me = this;
this.$w.find("input").autocomplete({
this.wrapper.find("input").autocomplete({
minLength: 0,
minChars: 0,
source: function(request, response) {


+ 4
- 4
frappe/public/js/frappe/ui/tree.js View File

@@ -8,10 +8,10 @@ frappe.ui.Tree = Class.extend({
init: function(args) {
$.extend(this, args);
this.nodes = {};
this.$w = $('<div class="tree">').appendTo(this.parent);
this.wrapper = $('<div class="tree">').appendTo(this.parent);
this.rootnode = new frappe.ui.TreeNode({
tree: this,
parent: this.$w,
parent: this.wrapper,
label: this.label,
parent_label: null,
expandable: true,
@@ -53,7 +53,7 @@ frappe.ui.TreeNode = Class.extend({
this.$a = $('<span class="tree-link">')
.click(function(event) {
me.tree.selected_node = me;
me.tree.$w.find(".tree-link.active").removeClass("active");
me.tree.wrapper.find(".tree-link.active").removeClass("active");
me.$a.addClass("active");
if(me.tree.toolbar) {
me.show_toolbar();
@@ -188,7 +188,7 @@ frappe.ui.TreeNode = Class.extend({
}

// select this link
this.tree.$w.find('.selected')
this.tree.wrapper.find('.selected')
.removeClass('selected');
this.$a.toggleClass('selected');
this.expanded = !this.expanded;


+ 864
- 0
frappe/public/js/frappe/views/gantt.js View File

@@ -0,0 +1,864 @@
/*

Opts:
parent_selector: [reqd]
label_width: default 200
step: 24 // no of hours
column_width: 15 // pixels
date_format: 'YYYY-MM-DD'
bar.height: 26
bar.gap: 24
arrow.curve: 15

*/

var Gantt = Class.extend({
init: function(opts) {
this.opts = opts;
this.events = this.opts.events;
this.tasks = [];
this._bars = [];
this.set_defaults();
this.groups = {};
this.make();
},
set_defaults: function() {
var defaults = {
label_width: 40,
header_height: 50,
column_width: 30,
step: 24,
valid_view_modes: [
"Quarter Day",
"Half Day",
"Day",
"Week",
"Month"
],
view_mode: 'Day',
padding: 18,
date_format: 'YYYY-MM-DD'
};
for(var key in defaults) {
if(defaults.hasOwnProperty(key)) {
if(!this.opts[key]) this.opts[key] = defaults[key];
}
}
},
make: function() {
this.canvas = Snap(this.opts.parent_selector);
this.canvas.addClass("gantt");
this.prepare_filters();
this.set_scale(this.opts.view_mode);
},
render: function() {
this.clear();

this.setup_groups();
this.make_grid();
this.make_dates();
this.make_arrows();
// this.make_label();
this.make_bars();
this.setup_events();
this.set_width();
this.set_scroll_position();
this.bind();
},
bind: function() {
this.bind_grid_click();
},
prepare_filters: function () {
this.filters = {};
},
clear: function () {
this.canvas.clear();
},
prepare_dates: function() {
var me = this;
this.tasks.forEach(function(task) {
// momentify
task._start = moment(task.start, me.opts.date_format);
task._end = moment(task.end, me.opts.date_format);

// set global start and end date
if(!me.start || task._start < me.start) {
me.start = task._start;
}
if(!me.end || task._end > me.end) {
me.end = task._end;
}
});
if(me.view_mode === 'Quarter Day' || me.view_mode === 'Half Day') {
me.start = me.start.clone().subtract(1, 'day');
me.end = me.end.clone().add(1, 'day');
} else if(me.view_mode === 'Month') {
me.start = me.start.clone().startOf('year');
me.end = me.end.clone().endOf('month').add(1, 'year');
} else {
me.start = me.start.clone().startOf('month');
me.end = me.end.clone().endOf('month');
}
this.setup_dates();
},

setup_dates: function() {
this.dates = [];
var cur_date = null;
while(cur_date === null || cur_date < this.end) {
if(!cur_date) {
cur_date = this.start.clone();
} else {
cur_date = (this.view_mode === 'Month') ?
cur_date = cur_date.clone().add(1, 'month') :
cur_date.clone().add(this.opts.step, 'hours');
}
this.dates.push(cur_date);
}
},
set_view_mode: function(mode) {
this.set_scale(mode);
this.start = this.end = undefined;
this.prepare_dates();
this.render();
},
set_scale: function (scale) {
this.view_mode = scale;
this.events.on_viewmode_change(scale);
if(scale === 'Day') {
this.opts.step = 24;
this.opts.column_width = 38;
}
else if(scale === 'Half Day') {
this.opts.step = 24 / 2;
this.opts.column_width = 38;
}
else if(scale === 'Quarter Day') {
this.opts.step = 24 / 4;
this.opts.column_width = 38;
}
else if(scale === 'Week') {
this.opts.step = 24 * 7;
this.opts.column_width = 140;
}
else if(scale === 'Month') {
this.opts.step = 24 * 30;
this.opts.column_width = 120;
}
},
add_task: function(task) {
task._index = this.tasks.length;
this.tasks.push(task);
this.prepare_dates();
},
setup_groups: function() {
var me = this;
// make groups
["grid", "controls", "label", "date",
"arrow", "progress", "bar", "details"].forEach(function(name) {
me.groups[name] = me.canvas.group().attr({'id': name});
});
},
set_width: function () {
var cur_width = this.canvas.node.getBoundingClientRect().width;
var actual_width = this.canvas.getBBox().width;
if(cur_width < actual_width)
this.canvas.attr("width", actual_width);
},
set_scroll_position: function() {
document.querySelector(this.opts.parent_selector).parentElement.scrollLeft =
this.get_min_date().diff(this.start, 'hours')
/ this.opts.step * this.opts.column_width;
},
get_min_date: function() {
return this.tasks.reduce(function(acc, curr) {
return curr._start.isSameOrBefore(acc._start) ? curr : acc;
})._start
},
make_grid: function () {
this.make_grid_background();
this.make_grid_rows();
this.make_grid_header();
this.make_grid_ticks();
},
make_grid_background: function () {
var me = this;
var grid_width = this.opts.label_width + this.dates.length * this.opts.column_width,
grid_height = this.opts.header_height + this.opts.padding
+ (this.opts.bar.height + this.opts.padding) * this.tasks.length;

this.canvas.rect(0,0, grid_width, grid_height)
.addClass('grid-background')
.appendTo(this.groups.grid);

this.canvas.attr({
// viewBox: "0 0 " + (x+10) + " " + (y+10),
height: grid_height + me.opts.padding,
width: "100%"
});
},
make_grid_header: function () {
var me = this;
var header_width = this.opts.label_width + this.dates.length * this.opts.column_width,
header_height = this.opts.header_height + 10;
me.canvas.rect(0,0, header_width, header_height)
.addClass('grid-header')
.appendTo(me.groups.grid);
},
make_grid_rows: function () {
var
me = this,
rows = me.canvas.group()
.appendTo(me.groups.grid),
lines = me.canvas.group()
.appendTo(me.groups.grid),

row_width = me.opts.label_width + me.dates.length * me.opts.column_width,
row_height = me.opts.bar.height + me.opts.padding,
row_y = me.opts.header_height + me.opts.padding/2;
this.tasks.forEach(function (task, i) {
var row_class = i % 2 ? "row-odd" : "row-even";
me.canvas.rect(0, row_y, row_width, row_height)
.addClass(row_class)
.appendTo(rows);

me.canvas.line(0, row_y + row_height, row_width, row_y + row_height)
.addClass('row-line')
.appendTo(lines);
row_y += me.opts.bar.height + me.opts.padding;
});
},
make_grid_ticks: function () {
var me = this;
var tick_x = me.opts.label_width;
var tick_y = me.opts.header_height + me.opts.padding/2;
var tick_height = (me.opts.bar.height + me.opts.padding) * me.tasks.length;

this.dates.forEach(function(date) {
var tick_class = 'tick';
//thick tick for monday
if(me.view_mode === 'Day' && date.day() === 1) {
tick_class += ' thick';
}
//thick tick for first week
if(me.view_mode === 'Week' && date.date() >= 1 && date.date() < 8) {
tick_class += ' thick';
}
//thick ticks for quarters
if(me.view_mode === 'Month' && date.month() % 3 == 0) {
tick_class += ' thick';
}

me.canvas.path(Snap.format("M {x} {y} v {height}", {
x: tick_x,
y: tick_y,
height: tick_height
}))
.addClass(tick_class)
.appendTo(me.groups.grid);

if(me.view_mode === 'Month') {
tick_x += date.daysInMonth() * me.opts.column_width/30;
} else {
tick_x += me.opts.column_width;
}
});
},
make_dates: function() {
var me = this;

this.dates.forEach(function(date, i) {
var primary_text = '';
var secondary_text = '';
if(i===0) {
primary_text = me.get_date_text(date, "primary");
secondary_text = me.get_date_text(date);
} else {
if(me.view_mode === 'Day') {
primary_text = date.date() !== me.dates[i-1].date() ?
me.get_date_text(date, "primary") : "";
secondary_text = date.month() !== me.dates[i-1].month() ?
me.get_date_text(date) : "";
}
else if(me.view_mode === 'Quarter Day') {
primary_text = me.get_date_text(date, "primary");
secondary_text = date.date() !== me.dates[i-1].date() ?
me.get_date_text(date) : "";
}
else if(me.view_mode === 'Half Day') {
primary_text = me.get_date_text(date, "primary");
secondary_text = date.date() !== me.dates[i-1].date() ?
me.get_date_text(date) : "";
}
else if(me.view_mode === 'Week') {
primary_text = me.get_date_text(date, "primary");
secondary_text = date.month() !== me.dates[i-1].month() ?
me.get_date_text(date) : "";
}
else if(me.view_mode === 'Month') {
primary_text = me.get_date_text(date, "primary");
secondary_text = date.year() !== me.dates[i-1].year() ?
me.get_date_text(date) : "";
}
}
var primary_text_x = me.opts.label_width + (i * me.opts.column_width),
primary_text_y = me.opts.header_height,
secondary_text_x = me.opts.label_width + (i * me.opts.column_width),
secondary_text_y = me.opts.header_height - 25;

if(me.view_mode === 'Month') {
primary_text_x += me.opts.column_width/2;
secondary_text_x += (me.opts.column_width * 12)/2;
}
if(me.view_mode === 'Week') {
primary_text_x += me.opts.column_width/2;
secondary_text_x += (me.opts.column_width * 4)/2;
}
if(me.view_mode === 'Day') {
secondary_text_x += (me.opts.column_width * 30)/2;
}
if(me.view_mode === 'Quarter Day') {
secondary_text_x += (me.opts.column_width * 4)/2;
}
if(me.view_mode === 'Half Day') {
secondary_text_x += (me.opts.column_width * 2)/2;
}

me.canvas.text(primary_text_x, primary_text_y, primary_text)
.addClass('primary-text')
.appendTo(me.groups.date)
if(secondary_text) {
var $secondary_text = me.canvas.text(secondary_text_x, secondary_text_y, secondary_text)
.addClass('secondary-text')
.appendTo(me.groups.date)

if($secondary_text.getBBox().x2 > me.groups.grid.getBBox().width) {
$secondary_text.remove();
}
}
});
},
get_date_text: function(date, primary) {
var scale = this.view_mode;
var text = "";
if(scale === 'Day') {
text = (primary) ? date.format('D') : date.format('MMMM');
}
else if(scale === 'Quarter Day' || scale === 'Half Day') {
text = (primary) ? date.format('HH') : date.format('D MMM');
}
else if(scale === 'Week') {
text = (primary) ? "Week " + date.format('W') : date.format('MMMM');
}
else if(scale === 'Month') {
text = (primary) ? date.format('MMMM') : date.format('YYYY');
}
return text;
},
make_arrows: function () {
var me = this;
this.tasks.forEach(function (task) {
if(task.dependent) {
var dependents = task.dependent.split(',');
dependents.forEach(function (task_dependent) {
task_dependent = task_dependent.trim();
var dependent = me.get_task(task_dependent);
var start_x = dependent._start.diff(me.start, 'hours')/me.opts.step
* me.opts.column_width + me.opts.label_width
+ (dependent._end.diff(dependent._start, 'hours')/me.opts.step
* me.opts.column_width) / 2;
var start_y = me.opts.header_height + me.opts.bar.height
+ (me.opts.padding + me.opts.bar.height) * dependent._index;
var end_x = task._start.diff(me.start, 'hours')/me.opts.step
* me.opts.column_width + me.opts.label_width;
var end_y = me.opts.header_height + me.opts.bar.height/2
+ (me.opts.padding + me.opts.bar.height) * task._index;

var path = Snap.format("M {start_x} {start_y} V {offset} a {curve} {curve} " +
"0 0 0 {curve} {curve}" +
"L {end_x} {end_y} m -5 -5 l 5 5 l -5 5",
{
start_x: start_x,
start_y: start_y + me.opts.padding,
end_x: end_x - me.opts.padding,
end_y: end_y + me.opts.padding,
offset: end_y - me.opts.arrow.curve + me.opts.padding,
curve: me.opts.arrow.curve
});
me.groups.arrow.add(me.canvas.path(path));
});
}
});
},
get_task: function (name) {
var result = null;
this.tasks.forEach(function (task) {
if (task.name === name){
result = task;
}
});
return result;
},
make_label: function () {
var me = this;
var label_x = me.opts.label_width - me.opts.padding,
label_y = me.opts.header_height + me.opts.bar.height/2 + me.opts.padding;

this.tasks.forEach(function (task) {
me.canvas.text(label_x, label_y, task.name).appendTo(me.groups.label);
label_y += me.opts.bar.height + me.opts.padding;
});

me.groups.label.attr({
"text-anchor": "end",
"dominant-baseline": "central"
});
},
make_bars: function () {
var me = this;

var bar_position_x,
bar_position_y = this.opts.header_height + me.opts.padding;

this.tasks.forEach(function (task, i) {

var bar = new Bar({
canvas: me.canvas,
task: task,
details: me.groups.details,
gantt: {
offset: me.opts.label_width,
unit_width: me.opts.column_width,
step: me.opts.step,
start: me.start,
header_height: me.opts.header_height,
padding: me.opts.padding,
view_mode: me.view_mode
},
color: {
bar: me.opts.bar.color,
progress: me.opts.bar.progress_color,
hover_bar: me.opts.bar.hover_color,
hover_progress: me.opts.bar.hover_progress_color
}
});

me._bars.push(bar);
me.groups.bar.add(bar.group);
});
},
setup_events: function() {
var me = this;
this._bars.forEach(function(bar) {
bar.events.on_date_change = me.events.bar_on_datechange;
bar.click(me.events.bar_on_click);
});
},
bind_grid_click: function() {
var me = this;
this.groups.grid.click(function() {
me.canvas.selectAll('.bar-wrapper').forEach(function(el) {
el.removeClass('active');
});
})
}
});

/*
Class: Bar

Opts:
canvas [reqd]
task [reqd]
unit_width [reqd]
x
y
*/

var Bar = Class.extend({
init: function (opts) {
for(var key in opts) {
if(opts.hasOwnProperty(key))
this[key] = opts[key];
}
this.set_defaults();
this.prepare();
this.draw();
this.bind();
this.action_completed = false;
},
set_defaults: function () {
var defaults = {
height: 20,
corner_radius: 3,
color: {
bar: "#a3a3ff",
progress: "#7575ff",
hover_bar: "#7575ff",
hover_progress: "#4d4da8"
},
events: {}
};
for(var key in defaults) {
if(defaults.hasOwnProperty(key))
if(!this[key]) this[key] = defaults[key];
}
},
prepare: function () {
this.prepare_values();
this.prepare_plugins();
},
prepare_values: function() {
this.x = this.compute_x();
this.y = this.compute_y();
this.duration = this.task._end.diff(this.task._start, 'hours')/this.gantt.step;
this.width = this.gantt.unit_width * this.duration;
if(this.gantt.view_mode === 'Month')
this.width = (this.gantt.unit_width/30) * (this.duration*this.gantt.step/24);
this.progress_width = this.gantt.unit_width * this.duration * (this.task.progress/100) || 0;
this.group = this.canvas.group().addClass('bar-wrapper');
this.bar_group = this.canvas.group().addClass('bar-group').appendTo(this.group);
this.handle_group = this.canvas.group().addClass('handle-group').appendTo(this.group);
},
prepare_plugins: function() {
var me = this;
this.filters = {};
Snap.plugin(function (Snap, Element, Paper, global, Fragment) {
Element.prototype.get = function (attr) {
return +this.attr(attr);
};
Element.prototype.getX = function () {
return this.get("x");
};
Element.prototype.getY = function () {
return this.get("y");
};
Element.prototype.getWidth = function () {
return this.get("width");
};
Element.prototype.setStartDate = function(date) {
date = moment(date)
var x = me.gantt.offset + (date.diff(me.gantt.start, 'hours')/me.gantt.step)*me.gantt.unit_width;
return this.attr('x', x);
}
Element.prototype.setEndDate = function(date) {
date = moment(date)
var x = me.gantt.offset + (date.diff(me.gantt.start, 'hours')/me.gantt.step)*me.gantt.unit_width;
return this.attr('x', x);
}
});
},
draw: function () {
this.draw_bar();
this.draw_progress_bar();
this.draw_label();
this.draw_resize_handles();
},
draw_bar: function() {
this.canvas.rect(this.x, this.y,
this.width, this.height,
this.corner_radius, this.corner_radius)
.addClass("bar")
.appendTo(this.bar_group);
},
draw_progress_bar: function() {
this.canvas.rect(this.x, this.y,
this.progress_width, this.height,
this.corner_radius, this.corner_radius)
.attr("fill", this.color.progress)
.addClass("bar-progress")
.appendTo(this.bar_group)
},
draw_label: function() {
this.canvas.text(this.x + this.width/2,
this.y + this.height/2,
this.task.name)
.addClass("bar-label")
.appendTo(this.bar_group);
this.update_label_position(this);
},
draw_resize_handles: function() {
var bar = this.group.select('.bar');
this.canvas.rect(bar.getX() + bar.getWidth() - 9, bar.getY() + 1,
8, this.height - 2, this.corner_radius, this.corner_radius)
.addClass('handle right')
.appendTo(this.handle_group);
this.canvas.rect(bar.getX() + 1, bar.getY() + 1,
8, this.height - 2, this.corner_radius, this.corner_radius)
.addClass('handle left')
.appendTo(this.handle_group);
},
bind: function () {
// this.show_details();
this.bind_resize();
this.bind_drag();
},
show_details: function () {
var me = this;

this.group.mouseover(function (e, x, y) {
var details_box = me.canvas.group();
me.details.clear();
var pos = me.get_details_position(me.group);

details_box.attr({ transform: "translate(" + pos.x +"," + pos.y + ")" })
.appendTo(me.details);

var line1_text = me.task.name + ": " +
me.task._start.format("MMM D") + " - " +
me.task._end.format("MMM D");

var line1_el = me.canvas.text(0,0, line1_text).attr({
dx: 10,
dy: 30,
"fill": "#424242",
"font-weight": 500,
"font-size": 14
});

me.canvas.rect(0, 0, 0, 110, 2, 2).attr({
stroke: "#c1c1c1",
"stroke-width": 1.1,
fill: "#fff"
}).appendTo(details_box);

var bbox = line1_el.getBBox();
details_box.select('rect').attr({
width: bbox.width + 20
});
line1_el.appendTo(details_box);

var line2_text =
"Duration: " + me.task._end.diff(me.task._start, 'days') + " days";
me.canvas.text(0,0, line2_text).attr({
dx: 10,
dy: 65,
"fill": "#757575"
}).appendTo(details_box);

var line3_text = me.task.progress ?
"Progress: " + me.task.progress + "%" : "";
me.canvas.text(0,0, line3_text).attr({
dx: 10,
dy: 90,
"fill": "#757575"
}).appendTo(details_box);
me.details.attr({
x: x,
y: y,
"font-size": 14
});
});
this.group.mouseout(function () {
setTimeout(function () {
me.details.clear();
}, 500);
});
},
get_details_position: function (group) {
var bar = group.select('rect');
return {
x: bar.getX() + bar.getWidth() + 2,
y: bar.getY() - 10
};
},
bind_resize: function() {
var me = this;
var bar = me.group.select('.bar');
var handle = me.get_handles(me);

handle.right.drag(onmove_right, onstart, onstop_right);
handle.left.drag(onmove_left, onstart, onstop_left);

function onstart() {
bar.ox = bar.getX();
bar.oy = bar.getY();
bar.owidth = bar.getWidth();
this.ox = this.getX();
this.oy = this.getY();
bar.finaldx = 0;
}

function onmove_right(dx, dy) {
bar.finaldx = me.get_snap_position(me, bar, dx);
me.update_bar_position(null, bar.owidth + bar.finaldx);
}
function onstop_right() {
if(bar.finaldx) me.date_changed();
me.set_action_completed();
}

function onmove_left(dx, dy) {
bar.finaldx = me.get_snap_position(me, bar, dx);
me.update_bar_position(bar.ox + bar.finaldx, bar.owidth - bar.finaldx);
}
function onstop_left() {
if(bar.finaldx) me.date_changed();
me.set_action_completed();
}
},
get_handles: function(me) {
return {
left: me.handle_group.select('.handle.left'),
right: me.handle_group.select('.handle.right')
}
},
bind_drag: function() {
var me = this;
var bar = me.group.select('.bar');
me.bar_group.drag(onmove, onstart, onstop);

function onmove(dx, dy) {
bar.finaldx = me.get_snap_position(me, bar, dx);
me.update_bar_position(bar.ox + bar.finaldx);
}
function onstop() {
if(!bar.finaldx) return;
me.date_changed();
me.set_action_completed();
}
function onstart() {
bar.ox = bar.getX();
bar.finaldx = 0;
}
},
view_is: function(modes) {
var me = this;
if (typeof modes === 'string') {
return me.gantt.view_mode === modes;
} else {
for (var i = 0; i < modes.length; i++) {
if(me.gantt.view_mode === modes[i]) return true;
}
// modes.forEach(function(mode) {
// if(me.gantt.view_mode === mode) return true;
// })
return false;
}
},
update_bar_position: function(x, width) {
var bar = this.group.select('.bar');
if(x) this.update_attr(bar, "x", x);
if(width) this.update_attr(bar, "width", width);
this.update_label_position(this);
this.update_handle_position(this);
this.update_progressbar_position(this);
},
click: function(callback) {
var me = this;
this.group.click(function() {
if(me.action_completed) {
// just finished a move action, wait for a few seconds
return;
}
if(me.group.hasClass('active')) {
callback(me.task);
}
me.unselect_all();
me.group.toggleClass('active');
});
},
date_changed: function() {
if(this.events.on_date_change) {
this.events.on_date_change(
this.task,
this.compute_start_date(),
this.compute_end_date()
);
}
},
set_action_completed: function() {
var me = this;
this.action_completed = true;
setTimeout(function() { me.action_completed = false; }, 2000);
},
compute_date: function(x) {
var pos = x - this.gantt.offset;
var shift = (x - this.compute_x())/this.gantt.unit_width;
var date = this.task._start.clone().add(this.gantt.step*shift, 'hours');
return date;
},
compute_start_date: function() {
var bar = this.group.select(".bar"),
shift = (bar.getX() - this.compute_x()) / this.gantt.unit_width,
new_start_date = this.task._start.clone().add(this.gantt.step*shift, 'hours');
return new_start_date;
},
compute_end_date: function() {
var bar = this.group.select(".bar"),
og_x = this.compute_x() + this.duration * this.gantt.unit_width,
final_x = bar.getX() + bar.getWidth(),
shift = (final_x - og_x) / this.gantt.unit_width,
new_end_date = this.task._end.clone().add(this.gantt.step*shift, 'hours');
return new_end_date;
},
compute_x: function() {
var x = this.gantt.offset
+ (this.task._start.diff(this.gantt.start, 'hours')/this.gantt.step
* this.gantt.unit_width);
if(this.gantt.view_mode === 'Month') {
x = this.gantt.offset
+ this.task._start.diff(this.gantt.start, 'days') * this.gantt.unit_width/30
}
return x;
},
compute_y: function() {
return this.gantt.header_height + this.gantt.padding
+ this.task._index * (this.height + this.gantt.padding)
},
get_snap_position: function(me, bar, dx) {
var odx = dx, rem, position, scale;

if (me.gantt.view_mode === 'Week') {
rem = dx % (me.gantt.unit_width/7);
position = odx - rem +
((rem < me.gantt.unit_width/7) ? 0 : me.gantt.unit_width/7);
} else if (me.gantt.view_mode === 'Month') {
rem = dx % (me.gantt.unit_width/30);
position = odx - rem +
((rem < me.gantt.unit_width/30) ? 0 : me.gantt.unit_width/30);
} else {
rem = dx % me.gantt.unit_width;
position = odx - rem +
((rem < me.gantt.unit_width) ? 0 : me.gantt.unit_width);
}
return position;
},
update_attr: function(element, attr, value) {
value = +value;
if(!isNaN(value)) {
element.attr(attr, value);
}
return element;
},
update_progressbar_position: function(me) {
var bar = me.group.select('.bar');
var bar_progress = me.group.select('.bar-progress');
bar_progress.attr('x', bar.getX());
bar_progress.attr('width', bar.getWidth() * (me.task.progress/100));
},
update_label_position: function(me) {
var bar = me.group.select(".bar");
var label = me.group.select('.bar-label');
if(label.getBBox().width > bar.getWidth()){
label.addClass('big').attr('x', bar.getX() + bar.getWidth() + 5);
} else {
label.removeClass('big').attr('x', bar.getX() + bar.getWidth()/2);
}
},
update_handle_position: function(me) {
var bar = me.group.select(".bar");
me.handle_group.select(".handle.left").attr({
"x": bar.getX() + 1,
});
me.handle_group.select(".handle.right").attr({
"x": bar.getX() + bar.getWidth() - 9,
});
},
unselect_all: function() {
this.canvas.selectAll('.bar-wrapper').forEach(function(el) {
el.removeClass('active');
});
}
});

+ 3
- 3
frappe/public/js/frappe/views/reports/reportview.js View File

@@ -351,7 +351,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
this.dataView = new Slick.Data.DataView();
this.set_data(this.data);

var grid_wrapper = this.$w.find('.result-list').addClass("slick-wrapper");
var grid_wrapper = this.wrapper.find('.result-list').addClass("slick-wrapper");

// set height if not auto
if(!options.autoHeight)
@@ -504,13 +504,13 @@ frappe.views.ReportView = frappe.ui.Listing.extend({

set_tag_and_status_filter: function() {
var me = this;
this.$w.find('.result-list').on("click", ".label-info", function() {
this.wrapper.find('.result-list').on("click", ".label-info", function() {
if($(this).attr("data-label")) {
me.set_filter("_user_tags", $(this).attr("data-label"));
me.refresh();
}
});
this.$w.find('.result-list').on("click", "[data-workflow-state]", function() {
this.wrapper.find('.result-list').on("click", "[data-workflow-state]", function() {
if($(this).attr("data-workflow-state")) {
me.set_filter(me.state_fieldname,
$(this).attr("data-workflow-state"));


+ 0
- 23
frappe/public/js/lib/jQuery.Gantt/README.md View File

@@ -1,23 +0,0 @@
[Demo and Documentation](http://taitems.github.com/jQuery.Gantt/)
==============

jQuery Gantt Chart is a simple chart that implements gantt functionality as
a jQuery component.

It's able to:

- Read json data
- Paging results
- Display different colours for each task
- Display short description as hints
- Mark holidays

Plugin was tested and should work on:

- Firefox 4+
- Chrome 13+
- Safari 5+
- Opera 9+
- IE 8+

Distributed under an MIT license.

+ 0
- 428
frappe/public/js/lib/jQuery.Gantt/css/style.css View File

@@ -1,428 +0,0 @@
.gantt, .gantt2 {
width: 100%;
margin: 20px auto;
border: 14px solid #ddd;
position: relative;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

.gantt:after {
content: ".";
visibility: hidden;
display: block;
height: 0;
clear: both;
}

.fn-gantt {
width: 100%;
}

.fn-gantt .fn-content {
overflow: hidden;
position: relative;
width: 100%;
}




/* === LEFT PANEL === */

.fn-gantt .leftPanel {
float: left;
width: 225px;
overflow: hidden;
border-right: 1px solid #DDD;
position: relative;
z-index: 20;
}

.fn-gantt .row {
float: left;
height: 24px;
line-height: 24px;
margin-left: -1px;
}

.fn-gantt .leftPanel .fn-label {
display: inline-block;
margin: 0 0 0 5px;
color: #484A4D;
width: 110px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}

.fn-gantt .leftPanel .row0 {
border-top: 1px solid #DDD;
}
.fn-gantt .leftPanel .name, .fn-gantt .leftPanel .desc {
float: left;
height: 23px;
margin: 0;
border-bottom: 1px solid #DDD;
background-color: #f6f6f6;
}

.fn-gantt .leftPanel .name {
width: 110px;
font-weight: bold;
}

.fn-gantt .leftPanel .desc {
width: 115px;
}

.fn-gantt .leftPanel .fn-wide, .fn-gantt .leftPanel .fn-wide .fn-label {
width: 225px;
}

.fn-gantt .spacer {
margin: -2px 0 1px 0;
border-bottom: none;
background-color: #f6f6f6;
}




/* === RIGHT PANEL === */

.fn-gantt .rightPanel {
overflow: hidden;
}

.fn-gantt .dataPanel {
margin-left: 0px;
border-right: 1px solid #DDD;
background-image: url(/assets/frappe/js/lib/jQuery.Gantt/img/grid.png);
background-repeat: repeat;
background-position: 24px 24px;
position: relative;
}
.fn-gantt .day, .fn-gantt .date {
overflow: visible;
width: 24px;
line-height: 24px;
text-align: center;
border-left: 1px solid #DDD;
border-bottom: 1px solid #DDD;
margin: -1px 0 0 -1px;
font-size: 11px;
color: #484a4d;
text-shadow: 0 1px 0 rgba(255,255,255,0.75);
text-align: center;
}

.fn-gantt .holiday {
background-color: #ffd263;
height: 23px;
margin: 0 0 -1px -1px;
}

.fn-gantt .today {
background-color: #fff8da;
height: 23px;
margin: 0 0 -1px -1px;
font-weight: bold;
text-align: center;
}

.fn-gantt .sa, .fn-gantt .sn, .fn-gantt .wd {
height: 23px;
margin: 0 0 0 -1px;
text-align: center;
}

.fn-gantt .sa, .fn-gantt .sn {
color: #939496;
background-color: #f5f5f5;
text-align: center;
}

.fn-gantt .wd {
background-color: #f6f6f6;
text-align: center;
}

.fn-gantt .rightPanel .month, .fn-gantt .rightPanel .year {
float: left;
overflow: hidden;
border-left: 1px solid #DDD;
border-bottom: 1px solid #DDD;
height: 23px;
margin: 0 0 0 -1px;
background-color: #f6f6f6;
font-weight: bold;
font-size: 11px;
color: #484a4d;
text-shadow: 0 1px 0 rgba(255,255,255,0.75);
text-align: center;
}

.fn-gantt-hint {
border: 5px solid #edc332;
background-color: #fff5d4;
padding: 10px;
position: absolute;
display: none;
z-index: 11;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}

.fn-gantt .bar {
background-color: #D0E4FD;
height: 18px;
margin: 0px 3px 3px 0px;
position: absolute;
z-index: 10;
text-align: center;
-webkit-box-shadow: 0 0 1px rgba(0,0,0,0.25) inset;
-moz-box-shadow: 0 0 1px rgba(0,0,0,0.25) inset;
box-shadow: 0 0 1px rgba(0,0,0,0.25) inset;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}

.fn-gantt .bar .fn-label {
line-height: 18px;
font-weight: bold;
white-space: nowrap;
width: 100%;
text-overflow: ellipsis;
overflow: hidden;
text-shadow: 0 1px 0 rgba(255,255,255,0.4);
color: #414B57 !important;
text-align: center;
font-size: 11px;
}

.fn-gantt .ganttRed {
background-color: #F9C4E1;
}
.fn-gantt .ganttRed .fn-label {
color: #78436D !important;
}

.fn-gantt .ganttGreen {
background-color: #D8EDA3;
}
.fn-gantt .ganttGreen .fn-label {
color: #778461 !important;
}

.fn-gantt .ganttOrange {
background-color: #FCD29A;
}
.fn-gantt .ganttOrange .fn-label {
color: #714715 !important;
}


/* === BOTTOM NAVIGATION === */

.fn-gantt .bottom {
clear: both;
background-color: #f6f6f6;
width: 100%;
}
.fn-gantt .navigate {
border-top: 1px solid #DDD;
padding: 10px 0 10px 225px;
}

.fn-gantt .navigate .nav-slider {
height: 20px;
display: inline-block;
}

.fn-gantt .navigate .nav-slider-left, .fn-gantt .navigate .nav-slider-right {
text-align: center;
height: 20px;
display: inline-block;
}

.fn-gantt .navigate .nav-slider-left {
float: left;
}

.fn-gantt .navigate .nav-slider-right {
float: right;
}

.fn-gantt .navigate .nav-slider-content {
text-align: left;
width: 160px;
height: 20px;
display: inline-block;
margin: 0 10px;
}

.fn-gantt .navigate .nav-slider-bar, .fn-gantt .navigate .nav-slider-button {
position: absolute;
display: block;
}

.fn-gantt .navigate .nav-slider-bar {
width: 155px;
height: 6px;
background-color: #838688;
margin: 8px 0 0 0;
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.6) inset;
-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.6) inset;
box-shadow: 0 1px 3px rgba(0,0,0,0.6) inset;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}

.fn-gantt .navigate .nav-slider-button {
width: 17px;
height: 60px;
background: url(/assets/frappe/js/lib/jQuery.Gantt/img/slider_handle.png) center center no-repeat;
left: 0px;
top: 0px;
margin: -26px 0 0 0;
cursor: pointer;
}

.fn-gantt .navigate .page-number {
display: inline-block;
font-size: 10px;
height: 20px;
}

.fn-gantt .navigate .page-number span {
color: #666666;
margin: 0 6px;
height: 20px;
line-height: 20px;
display: inline-block;
}

.fn-gantt .navigate a:link, .fn-gantt .navigate a:visited, .fn-gantt .navigate a:active {
text-decoration: none;
}

.fn-gantt .nav-link {
margin: 0 3px 0 0;
display: inline-block;
width: 20px;
height: 20px;
font-size: 0px;
background: #595959 url(/assets/frappe/js/lib/jQuery.Gantt/img/icon_sprite.png) !important;
border: 1px solid #454546;
cursor: pointer;
vertical-align: top;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.1) inset, 0 1px 1px rgba(0,0,0,0.2);
-moz-box-shadow: 0 1px 0 rgba(255,255,255,0.1) inset, 0 1px 1px rgba(0,0,0,0.2);
box-shadow: 0 1px 0 rgba(255,255,255,0.1) inset, 0 1px 1px rgba(0,0,0,0.2);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.fn-gantt .nav-link:active {
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.25) inset, 0 1px 0 #FFF;
-moz-box-shadow: 0 1px 1px rgba(0,0,0,0.25) inset, 0 1px 0 #FFF;
box-shadow: 0 1px 1px rgba(0,0,0,0.25) inset, 0 1px 0 #FFF;
}

.fn-gantt .navigate .nav-page-back {
background-position: 1px 0 !important;
margin: 0;
}

.fn-gantt .navigate .nav-page-next {
background-position: 1px -16px !important;
margin-right: 15px;
}

.fn-gantt .navigate .nav-slider .nav-page-next {
margin-right: 5px;
}

.fn-gantt .navigate .nav-begin {
background-position: 1px -112px !important;
}

.fn-gantt .navigate .nav-prev-week {
background-position: 1px -128px !important;
}

.fn-gantt .navigate .nav-prev-day {
background-position: 1px -48px !important;
}

.fn-gantt .navigate .nav-next-day {
background-position: 1px -64px !important;
}

.fn-gantt .navigate .nav-next-week {
background-position: 1px -160px !important;
}

.fn-gantt .navigate .nav-end {
background-position: 1px -144px !important;
}

.fn-gantt .navigate .nav-zoomOut {
background-position: 1px -96px !important;
}

.fn-gantt .navigate .nav-zoomIn {
background-position: 1px -80px !important;
margin-left: 15px;
}

.fn-gantt .navigate .nav-now {
background-position: 1px -32px !important;
}

.fn-gantt .navigate .nav-slider .nav-now {
margin-right: 5px;
}

.fn-gantt-loader {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#bf000000', endColorstr='#bf000000',GradientType=0 );
background: rgba(0,0,0,0.75);
cursor: wait;
z-index: 30;
}
.fn-gantt-loader-spinner span {
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
height: 1em;
line-height: 1em;
color: #fff;
font-size: 1em;
font-weight: bold;
}

.row:after {
clear: both;
}


BIN
frappe/public/js/lib/jQuery.Gantt/img/grid.png View File

Before After
Width: 24  |  Height: 24  |  Size: 96 B

BIN
frappe/public/js/lib/jQuery.Gantt/img/icon_sprite.png View File

Before After
Width: 16  |  Height: 176  |  Size: 808 B

BIN
frappe/public/js/lib/jQuery.Gantt/img/slider_handle.png View File

Before After
Width: 17  |  Height: 21  |  Size: 817 B

+ 0
- 551
frappe/public/js/lib/jQuery.Gantt/index.html View File

@@ -1,551 +0,0 @@
<!doctype html>
<html lang="en-au">
<head>
<title>jQuery.Gantt</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge;chrome=1" >
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css" />
<link rel="stylesheet" href="http://taitems.github.com/UX-Lab/core/css/prettify.css" />
<style type="text/css">
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
padding: 0 0 50px 0;
}
.contain {
width: 800px;
margin: 0 auto;
}
h1 {
margin: 40px 0 20px 0;
}
h2 {
font-size: 1.5em;
padding-bottom: 3px;
border-bottom: 1px solid #DDD;
margin-top: 50px;
margin-bottom: 25px;
}
table th:first-child {
width: 150px;
}
</style>
</head>
<body>

<div class="contain">

<h1>
jQuery.Gantt
<small>&mdash; Draw Gantt charts with the famous jQuery ease of development</small>
</h1>

<h2>Contributors</h2>
<ul>
<li>
<strong><a href="http://mbielanczuk.com/" target="_blank">Marek Bielańczuk</a></strong> wrote the original jQuery.Gantt plugin that this version is based off of.
</li>
<li>
<strong><a href="http://taitbrown.com/" target="_blank">Tait Brown</a></strong> enforced stricter code guidelines by validating the code, updating it to support HTML5 and tweaking the design.
</li>
<li>
<strong><a href="mailto:leo.pfeifenberger@googlemail.com" target="_blank">Leo Pfeifenberger</a></strong> made <em>major</em> performance updates as well as adding requested features such as click events, state persisting via cookies and scrollToToday on load functionality.
</li>
</ul>

<h2>
Example
</h2>
<div class="gantt"></div>



<h2>
Gantt Configuration
</h2>


<pre class="prettyprint">
$(".selector").gantt({
source: "ajax/data.json",
scale: "weeks",
minScale: "weeks",
maxScale: "months",
onItemClick: function(data) {
alert("Item clicked - show some details");
},
onAddClick: function(dt, rowId) {
alert("Empty space clicked - add an item!");
},
onRender: function() {
console.log("chart rendered");
}
});
</pre>

<table class="table table-striped">
<thead>
<tr>
<th>
Parameter
</th>
<th>
Default
</th>
<th>
Accepts Type
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>source</code>
</td>
<td>
null
</td>
<td>
Array, String (url)
</td>
</tr>
<tr>
<td>
<code>itemsPerPage</code>
</td>
<td>
7
</td>
<td>
Number
</td>
</tr>
<tr>
<td>
<code>months</code>
</td>
<td>
["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
</td>
<td>
Array
</td>
</tr>
<tr>
<td>
<code>dow</code>
</td>
<td>
["S", "M", "T", "W", "T", "F", "S"]
</td>
<td>
Array
</td>
</tr>
<tr>
<td>
<code>navigate</code>
</td>
<td>
"buttons"
</td>
<td>
String ("buttons","scroll")
</td>
</tr>
<tr>
<td>
<code>scale</code>
</td>
<td>
"days"
</td>
<td>
String
</td>
</tr>
<tr>
<td>
<code>maxScale</code>
</td>
<td>
"months"
</td>
<td>
String
</td>
</tr>
<tr>
<td>
<code>minScale</code>
</td>
<td>
"hours"
</td>
<td>
String
</td>
</tr>
<tr>
<td>
<code>waitText</code>
</td>
<td>
"Please Wait..."
</td>
<td>
String
</td>
</tr>
<tr>
<td>
<code>onItemClick: </code>
</td>
<td>
<code>function (data) { return; }</code></td>
<td>
a JS Function that gets called when clicking on a Gantt-Item. <br />The parameter passed to the function is the dataObj of the item</td>
</tr>
<tr>
<td>
<code>onAddClick</code></td>
<td>
<code>function (dt, rowId) { return; }</code></td>
<td>
a JS Function that gets called when clicking on a Gantt-Item. <br />The parameter passed to the function is the DateTime in ms for the clicked Cell, and the ID if the source object (row)</td>
</tr>
<tr>
<td>
<code>onRender</code></td>
<td>
<code>function () { return; }</code></td>
<td>
a JS Function called whenever the chart is (re)rendered</td>
</tr>
<tr>
<td>
<code>useCookie</code></td>
<td>
<code>false</code></td>
<td>
indicates if cookies should be used to track the chart's state (scale, scrollposition) between postpacks<br />
<code>jquery.cookie.js</code> needs to be referenced for this to work</td>
</tr>
<tr>
<td>
<code>scrollToToday</code></td>
<td>
<code>true</code></td>
<td>
Boolean</td>
</tr>
</tbody>
</table>




<h2>
Source Configuration
</h2>

<pre class="prettyprint">
source: [{
name: "Example",
desc: "Lorem ipsum dolor sit amet.",
values: [ ... ]
}]
</pre>

<table class="table table-striped">
<thead>
<tr>
<th>
Parameter
</th>
<th>
Default
</th>
<th>
Accepts Type
</th>
<th>
Meaning
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>name</code>
</td>
<td>
null
</td>
<td>
String
</td>
<td>
Bold value in the left-most column of the gantt row.
</td>
</tr>
<tr>
<td>
<code>desc</code>
</td>
<td>
null
</td>
<td>
String
</td>
<td>
Secondary value in the gantt row.
</td>
</tr>
<tr>
<td>
<code>values</code>
</td>
<td>
null
</td>
<td>
Array
</td>
<td>
Collection of date ranges for gantt items. See next table.
</td>
</tr>
</tbody>
</table>


<h2>
Value Configuration
</h2>

<pre class="prettyprint">
values: [{
to: "/Date(1328832000000)/",
from: "/Date(1333411200000)/",
desc: "Something",
label: "Example Value",
customClass: "ganttRed",
dataObj: foo.bar[i]
}]
</pre>

<table class="table table-striped">
<thead>
<tr>
<th>
Parameter
</th>
<th>
Accepts Type
</th>
<th>
Meaning
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>to</code>
</td>
<td>
String (Date)
</td>
<td>
-
</td>
</tr>
<tr>
<td>
<code>from</code>
</td>
<td>
String (Date)
</td>
<td>
-
</td>
</tr>
<tr>
<td>
<code>desc</code>
</td>
<td>
String
</td>
<td>
Text that appears on hover, I think?
</td>
</tr>
<tr>
<td>
<code>label</code>
</td>
<td>
String
</td>
<td>
Appears on the gantt item.
</td>
</tr>
<tr>
<td>
<code>customClass</code>
</td>
<td>
String
</td>
<td>
Custom class to be applied to the gantt item.
</td>
</tr>
<tr>
<td>
<code>dataObj</code>
</td>
<td>
All
</td>
<td>
A data object that is applied directly to the gantt item.
</td>
</tr>
</tbody>
</table>

</div>

</body>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="js/jquery.fn.gantt.js"></script>
<script src="http://twitter.github.com/bootstrap/assets/js/bootstrap-tooltip.js"></script>
<script src="http://twitter.github.com/bootstrap/assets/js/bootstrap-popover.js"></script>
<script src="http://taitems.github.com/UX-Lab/core/js/prettify.js"></script>
<script>

$(function() {

"use strict";

$(".gantt").gantt({
source: [{
name: "Sprint 0",
desc: "Analysis",
values: [{
from: "/Date(1320192000000)/",
to: "/Date(1322401600000)/",
label: "Requirement Gathering",
customClass: "ganttRed"
}]
},{
name: " ",
desc: "Scoping",
values: [{
from: "/Date(1322611200000)/",
to: "/Date(1323302400000)/",
label: "Scoping",
customClass: "ganttRed"
}]
},{
name: "Sprint 1",
desc: "Development",
values: [{
from: "/Date(1323802400000)/",
to: "/Date(1325685200000)/",
label: "Development",
customClass: "ganttGreen"
}]
},{
name: " ",
desc: "Showcasing",
values: [{
from: "/Date(1325685200000)/",
to: "/Date(1325695200000)/",
label: "Showcasing",
customClass: "ganttBlue"
}]
},{
name: "Sprint 2",
desc: "Development",
values: [{
from: "/Date(1326785200000)/",
to: "/Date(1325785200000)/",
label: "Development",
customClass: "ganttGreen"
}]
},{
name: " ",
desc: "Showcasing",
values: [{
from: "/Date(1328785200000)/",
to: "/Date(1328905200000)/",
label: "Showcasing",
customClass: "ganttBlue"
}]
},{
name: "Release Stage",
desc: "Training",
values: [{
from: "/Date(1330011200000)/",
to: "/Date(1336611200000)/",
label: "Training",
customClass: "ganttOrange"
}]
},{
name: " ",
desc: "Deployment",
values: [{
from: "/Date(1336611200000)/",
to: "/Date(1338711200000)/",
label: "Deployment",
customClass: "ganttOrange"
}]
},{
name: " ",
desc: "Warranty Period",
values: [{
from: "/Date(1336611200000)/",
to: "/Date(1349711200000)/",
label: "Warranty Period",
customClass: "ganttOrange"
}]
}],
navigate: "scroll",
scale: "weeks",
maxScale: "months",
minScale: "days",
itemsPerPage: 10,
onItemClick: function(data) {
alert("Item clicked - show some details");
},
onAddClick: function(dt, rowId) {
alert("Empty space clicked - add an item!");
},
onRender: function() {
if (window.console && typeof console.log === "function") {
console.log("chart rendered");
}
}
});

$(".gantt").popover({
selector: ".bar",
title: "I'm a popover",
content: "And I'm the content of said popover."
});

prettyPrint();

});

</script>
</html>

+ 0
- 1758
frappe/public/js/lib/jQuery.Gantt/js/jquery.fn.gantt.js
File diff suppressed because it is too large
View File


+ 0
- 20
frappe/public/js/lib/jQuery.Gantt/js/jquery.fn.gantt.min.js
File diff suppressed because it is too large
View File


+ 21
- 0
frappe/public/js/lib/snap.svg-min.js
File diff suppressed because it is too large
View File


+ 88
- 29
frappe/public/less/gantt.less View File

@@ -1,38 +1,97 @@
@import "variables.less";

.gantt, .gantt2 {
border: none !important;
border-radius: none !important;
margin: 0px auto !important;
.gantt {
#grid {
.grid-background {
fill: none;
}
.grid-header {
fill: #fff;
stroke: #e0e0e0;
stroke-width: 1.4;
}
.row-odd {
fill: #ffffff;
}
.row-even {
fill: #f5f5f5;
}
.row-line {
stroke: #EBEFF2;
}
.tick {
stroke: #aaa;
stroke-width: 0.2;
&.thick {
stroke-width: 0.4;
}
}
}

* {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
#arrow {
fill: none;
stroke: #333;
stroke-width: 1.4;
}
}

.fn-gantt .leftPanel,
.fn-gantt .leftPanel .row0,
.fn-gantt .leftPanel .name, .fn-gantt .leftPanel .desc,
.fn-gantt .dataPanel,
.fn-gantt .day, .fn-gantt .date,
.fn-gantt .rightPanel .month, .fn-gantt .rightPanel .year {
border-color: @border-color !important;
}
.bar {
fill: #b8c2cc;
stroke: #8D99A6;
stroke-width: 0;
transition: stroke-width .3s ease;
}
.bar-label {
fill: #fff;
dominant-baseline: central;
text-anchor: middle;
font-size: 12px;
font-weight: lighter;
letter-spacing: 0.8px;

.fn-gantt .navigate {
border: none !important;
}
&.big {
fill: #555;
text-anchor: start;
}
}

.fn-gantt .leftPanel .name, .fn-gantt .leftPanel .desc,
.fn-gantt .spacer,
.fn-gantt .wd,
.fn-gantt .rightPanel .month, .fn-gantt .rightPanel .year,
.fn-gantt .bottom {
background-color: @panel-bg !important;
}
.handle {
fill: #ddd;
cursor: ew-resize;
opacity: 0;
visibility: hidden;
transition: opacity .3s ease;
}

.bar-wrapper {
cursor: pointer;

.fn-gantt .today {
background-color: #D9F6FF !important;
&:hover {
.bar {
stroke-width: 2;
}

.handle {
visibility: visible;
opacity: 1;
}
}

&.active {
.bar {
stroke-width: 2;
}
}
}

.primary-text, .secondary-text {
font-size: 12px;
text-anchor: middle;
}
.primary-text {
fill: #999;
}
.secondary-text {
fill: #555;
}
}


+ 1
- 0
patches.txt View File

@@ -0,0 +1 @@
bench.patches.v3.deprecate_old_config

Loading…
Cancel
Save