* [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/monthversion-14
@@ -61,7 +61,7 @@ frappe.Chat = Class.extend({ | |||||
var $row = $('<div class="list-row"/>'); | var $row = $('<div class="list-row"/>'); | ||||
frappe.pages.chat.chat.list.data.unshift(comment); | frappe.pages.chat.chat.list.data.unshift(comment); | ||||
frappe.pages.chat.chat.list.render_row($row, 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() { | make_sidebar: function() { | ||||
@@ -193,8 +193,7 @@ | |||||
"css/list.min.css": [ | "css/list.min.css": [ | ||||
"public/css/list.css", | "public/css/list.css", | ||||
"public/css/tag-it.css", | "public/css/tag-it.css", | ||||
"public/css/calendar.css", | |||||
"public/css/gantt.css" | |||||
"public/css/calendar.css" | |||||
], | ], | ||||
"js/list.min.js": [ | "js/list.min.js": [ | ||||
"public/js/frappe/ui/listing.html", | "public/js/frappe/ui/listing.html", | ||||
@@ -219,13 +218,13 @@ | |||||
"public/js/frappe/list/listview.js", | "public/js/frappe/list/listview.js", | ||||
"public/js/frappe/views/calendar_base.js", | "public/js/frappe/views/calendar_base.js", | ||||
"public/js/frappe/views/calendar.js", | "public/js/frappe/views/calendar.js", | ||||
"public/js/frappe/views/ganttview.js", | |||||
"public/js/frappe/list/blueimp-gallery.html", | "public/js/frappe/list/blueimp-gallery.html", | ||||
"public/js/frappe/list/image_view_item_row.html", | "public/js/frappe/list/image_view_item_row.html", | ||||
"public/js/frappe/list/image_view_item_main_head.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/header_select_all_like_filter.html", | ||||
"public/js/frappe/list/item_assigned_to_comment_count.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": [ | "css/report.min.css": [ | ||||
"public/css/report.css", | "public/css/report.css", | ||||
@@ -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; | |||||
} | } |
@@ -130,14 +130,13 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
this.init_listview(); | this.init_listview(); | ||||
this.setup_filterable(); | this.setup_filterable(); | ||||
this.init_filters(); | this.init_filters(); | ||||
this.init_headers(); | |||||
this.init_sort_selector(); | this.init_sort_selector(); | ||||
this.init_like(); | |||||
this.init_select_all(); | |||||
}, | }, | ||||
init_headers: function() { | 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, { | var main = frappe.render_template(this.header, { | ||||
columns: this.listview.columns, | columns: this.listview.columns, | ||||
right_column: this.listview.settings.right_column, | 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 })) | this.list_header = $(frappe.render_template("list_item_row_head", { main:main, list:this.listview })) | ||||
.appendTo(this.page.main.find(".list-headers")); | .appendTo(this.page.main.find(".list-headers")); | ||||
this.init_like(); | |||||
this.init_select_all(); | |||||
}, | }, | ||||
init_listview: function() { | init_listview: function() { | ||||
@@ -303,7 +305,14 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
refresh: function(dirty) { | refresh: function(dirty) { | ||||
if(dirty!==undefined) this.dirty = 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) { | if(this.listview.settings.refresh) { | ||||
this.listview.settings.refresh(this); | this.listview.settings.refresh(this); | ||||
@@ -354,8 +363,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
if(!this.listview.settings.use_route) { | if(!this.listview.settings.use_route) { | ||||
var route = frappe.get_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) { | $.each(frappe.utils.get_args_dict_from_url(route[2]), function(key, val) { | ||||
me.set_filter(key, val, true); | me.set_filter(key, val, true); | ||||
}); | }); | ||||
@@ -401,16 +409,131 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
return no_result_message; | 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) { | render_row: function(row, data) { | ||||
data.doctype = this.doctype; | data.doctype = this.doctype; | ||||
this.listview.render(row, data, this); | this.listview.render(row, data, this); | ||||
}, | }, | ||||
render_image_view_row: function(row, data) { | render_image_view_row: function(row, data) { | ||||
for (var i = 0; i < data.length; i++) { | for (var i = 0; i < data.length; i++) { | ||||
data[i].doctype = this.doctype; | data[i].doctype = this.doctype; | ||||
this.listview.render(row, data[i], this) | this.listview.render(row, data[i], this) | ||||
} | } | ||||
}, | }, | ||||
get_args: function() { | get_args: function() { | ||||
var args = { | var args = { | ||||
doctype: this.doctype, | doctype: this.doctype, | ||||
@@ -644,7 +767,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
}); | }); | ||||
// after delete, hide delete button | // after delete, hide delete button | ||||
this.$w.on("render-complete", function() { | |||||
this.wrapper.on("render-complete", function() { | |||||
me.toggle_delete(); | me.toggle_delete(); | ||||
}); | }); | ||||
} | } | ||||
@@ -675,7 +798,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
get_checked_items: function() { | get_checked_items: function() { | ||||
var me = this; | var me = this; | ||||
return $.map(this.$page.find('.list-delete:checked'), function(e) { | 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'); | return $(e).parents(".list-row:first").data('data'); | ||||
} | } | ||||
else{ | else{ | ||||
@@ -711,9 +834,9 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
} | } | ||||
); | ); | ||||
}, | }, | ||||
init_stats: function() { | |||||
refresh_sidebar: function() { | |||||
var me = this; | var me = this; | ||||
this.sidebar_stats = new frappe.views.ListSidebar({ | |||||
this.list_sidebar = new frappe.views.ListSidebar({ | |||||
doctype: this.doctype, | doctype: this.doctype, | ||||
stats: this.listview.stats, | stats: this.listview.stats, | ||||
parent: this.$page.find('.layout-side-section'), | parent: this.$page.find('.layout-side-section'), | ||||
@@ -14,15 +14,17 @@ | |||||
</div> | </div> | ||||
</li> | </li> | ||||
<li class="divider"></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 tree-link"><a href="#Tree/{%= doctype %}">{%= __("Tree") %}</a></li> | ||||
<li class="hide calendar-link"><a href="#Calendar/{%= doctype %}">{%= __("Calendar") %}</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"> | <li class="assigned-to-me"> | ||||
<a>{%= __("Assigned To Me") %}</a> | <a>{%= __("Assigned To Me") %}</a> | ||||
</li> | </li> | ||||
<li class="hide switch-list-view"> | |||||
<a>{%= __("Show Images") %}</a> | |||||
</li> | |||||
{% if(frappe.help.has_help(doctype)) { %} | {% if(frappe.help.has_help(doctype)) { %} | ||||
<li><a class="help-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li> | <li><a class="help-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li> | ||||
{% } %} | {% } %} | ||||
@@ -24,15 +24,41 @@ frappe.views.ListSidebar = Class.extend({ | |||||
this.setup_reports(); | this.setup_reports(); | ||||
this.setup_assigned_to_me(); | 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]) { | 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]) { | if(frappe.treeview_settings[this.doctype]) { | ||||
this.sidebar.find(".tree-link").removeClass("hide"); | 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() { | setup_reports: function() { | ||||
// add reports linked to this doctype to the dropdown | // add reports linked to this doctype to the dropdown | ||||
@@ -78,35 +104,6 @@ frappe.views.ListSidebar = Class.extend({ | |||||
me.doclistview.assigned_to_me(); | 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() { | get_stats: function() { | ||||
var me = this | var me = this | ||||
return frappe.call({ | return frappe.call({ | ||||
@@ -214,12 +214,7 @@ frappe.views.ListView = Class.extend({ | |||||
this.id_list.push(data.name); | 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) { | if(this.settings.post_render_item) { | ||||
this.settings.post_render_item(this, row, data); | this.settings.post_render_item(this, row, data); | ||||
@@ -228,7 +223,7 @@ frappe.views.ListView = Class.extend({ | |||||
this.render_tags(row, data); | 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", { | var main = frappe.render_template("list_item_main", { | ||||
data: data, | data: data, | ||||
columns: this.columns, | columns: this.columns, | ||||
@@ -244,7 +239,7 @@ frappe.views.ListView = Class.extend({ | |||||
right_column: this.settings.right_column | right_column: this.settings.right_column | ||||
})).appendTo(row); | })).appendTo(row); | ||||
}, | }, | ||||
render_list_image: function(row, data) { | |||||
render_row_Image: function(row, data) { | |||||
this.allowed_type = [ | this.allowed_type = [ | ||||
"Check", "Currency", "Data", "Date", | "Check", "Currency", "Data", "Date", | ||||
"Datetime", "Float", "Int", "Link", | "Datetime", "Float", "Int", "Link", | ||||
@@ -290,7 +285,7 @@ frappe.views.ListView = Class.extend({ | |||||
//me.render_timestamp_and_comments(row, data); | //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", | me.doclistview.set_filter("_user_tags", | ||||
$(this).text()); | $(this).text()); | ||||
}); | }); | ||||
@@ -5,22 +5,22 @@ frappe.ui.FilterList = Class.extend({ | |||||
init: function(opts) { | init: function(opts) { | ||||
$.extend(this, opts); | $.extend(this, opts); | ||||
this.filters = []; | this.filters = []; | ||||
this.$w = this.$parent; | |||||
this.wrapper = this.$parent; | |||||
this.set_events(); | this.set_events(); | ||||
}, | }, | ||||
set_events: function() { | set_events: function() { | ||||
var me = this; | var me = this; | ||||
// show filters | // show filters | ||||
this.$w.find('.new-filter').bind('click', function() { | |||||
this.wrapper.find('.new-filter').bind('click', function() { | |||||
me.add_filter(me.doctype, 'name'); | me.add_filter(me.doctype, 'name'); | ||||
}); | }); | ||||
}, | }, | ||||
show_filters: function() { | show_filters: function() { | ||||
this.$w.find('.show_filters').toggle(); | |||||
this.wrapper.find('.show_filters').toggle(); | |||||
if(!this.filters.length) { | if(!this.filters.length) { | ||||
this.add_filter(this.doctype, 'name'); | 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; | 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! | // only allow 1 new filter at a time! | ||||
return; | return; | ||||
} | } | ||||
@@ -53,7 +53,7 @@ frappe.ui.FilterList = Class.extend({ | |||||
var filter = this.push_new_filter(doctype, fieldname, condition, value); | var filter = this.push_new_filter(doctype, fieldname, condition, value); | ||||
if (filter && is_new_filter) { | if (filter && is_new_filter) { | ||||
filter.$w.addClass("is-new-filter"); | |||||
filter.wrapper.addClass("is-new-filter"); | |||||
} | } | ||||
if (filter && hidden) { | if (filter && hidden) { | ||||
@@ -131,12 +131,12 @@ frappe.ui.Filter = Class.extend({ | |||||
this.set_events(); | this.set_events(); | ||||
}, | }, | ||||
make: function() { | 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() { | make_select: function() { | ||||
var me = this; | var me = this; | ||||
this.fieldselect = new frappe.ui.FieldSelect({ | this.fieldselect = new frappe.ui.FieldSelect({ | ||||
parent: this.$w.find('.fieldname_select_area'), | |||||
parent: this.wrapper.find('.fieldname_select_area'), | |||||
doctype: this.doctype, | doctype: this.doctype, | ||||
filter_fields: this.filter_fields, | filter_fields: this.filter_fields, | ||||
select: function(doctype, fieldname) { | select: function(doctype, fieldname) { | ||||
@@ -150,17 +150,17 @@ frappe.ui.Filter = Class.extend({ | |||||
set_events: function() { | set_events: function() { | ||||
var me = this; | var me = this; | ||||
this.$w.find("a.remove-filter").on("click", function() { | |||||
this.wrapper.find("a.remove-filter").on("click", function() { | |||||
me.remove(); | 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(); | me.flist.listobj.run(); | ||||
}); | }); | ||||
// add help for "in" codition | // add help for "in" codition | ||||
me.$w.find('.condition').change(function() { | |||||
me.wrapper.find('.condition').change(function() { | |||||
if(!me.field) return; | if(!me.field) return; | ||||
var condition = $(this).val(); | var condition = $(this).val(); | ||||
if(in_list(["in", "like", "not in", "not like"], condition)) { | if(in_list(["in", "like", "not in", "not like"], condition)) { | ||||
@@ -188,7 +188,7 @@ frappe.ui.Filter = Class.extend({ | |||||
}, | }, | ||||
remove: function(dont_run) { | remove: function(dont_run) { | ||||
this.$w.remove(); | |||||
this.wrapper.remove(); | |||||
this.$btn_group && this.$btn_group.remove(); | this.$btn_group && this.$btn_group.remove(); | ||||
this.field = null; | this.field = null; | ||||
this.flist.update_filters(); | this.flist.update_filters(); | ||||
@@ -202,7 +202,7 @@ frappe.ui.Filter = Class.extend({ | |||||
set_values: function(doctype, fieldname, condition, value) { | set_values: function(doctype, fieldname, condition, value) { | ||||
// presents given (could be via tags!) | // presents given (could be via tags!) | ||||
this.set_field(doctype, fieldname); | 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); | if(value!=null) this.field.set_input(value); | ||||
}, | }, | ||||
@@ -247,7 +247,7 @@ frappe.ui.Filter = Class.extend({ | |||||
old_text = me.field.get_parsed_value(); | 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({ | var f = frappe.ui.form.make_control({ | ||||
df: df, | df: df, | ||||
parent: field_area, | parent: field_area, | ||||
@@ -301,7 +301,7 @@ frappe.ui.Filter = Class.extend({ | |||||
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments', | } else if(['Text','Small Text','Text Editor','Code','Tag','Comments', | ||||
'Dynamic Link','Read Only','Assign'].indexOf(df.fieldtype)!=-1) { | 'Dynamic Link','Read Only','Assign'].indexOf(df.fieldtype)!=-1) { | ||||
df.fieldtype = 'Data'; | 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'; | df.fieldtype = 'Data'; | ||||
} | } | ||||
if(df.fieldtype==="Data" && (df.options || "").toLowerCase()==="email") { | if(df.fieldtype==="Data" && (df.options || "").toLowerCase()==="email") { | ||||
@@ -313,9 +313,9 @@ frappe.ui.Filter = Class.extend({ | |||||
if(!fieldtype) { | if(!fieldtype) { | ||||
// set as "like" for data fields | // set as "like" for data fields | ||||
if(df.fieldtype=='Data') { | if(df.fieldtype=='Data') { | ||||
this.$w.find('.condition').val('like'); | |||||
this.wrapper.find('.condition').val('like'); | |||||
} else { | } else { | ||||
this.$w.find('.condition').val('='); | |||||
this.wrapper.find('.condition').val('='); | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
@@ -356,14 +356,14 @@ frappe.ui.Filter = Class.extend({ | |||||
}, | }, | ||||
get_condition: function() { | get_condition: function() { | ||||
return this.$w.find('.condition').val(); | |||||
return this.wrapper.find('.condition').val(); | |||||
}, | }, | ||||
freeze: function() { | freeze: function() { | ||||
if(this.$btn_group) { | if(this.$btn_group) { | ||||
// already made, just hide the condition setter | // already made, just hide the condition setter | ||||
this.set_filter_button_text(); | this.set_filter_button_text(); | ||||
this.$w.toggle(false); | |||||
this.wrapper.toggle(false); | |||||
return; | return; | ||||
} | } | ||||
@@ -379,7 +379,7 @@ frappe.ui.Filter = Class.extend({ | |||||
title="'+__("Remove Filter")+'">\ | title="'+__("Remove Filter")+'">\ | ||||
<i class="icon-remove text-muted"></i>\ | <i class="icon-remove text-muted"></i>\ | ||||
</button></div>') | </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(); | this.set_filter_button_text(); | ||||
@@ -388,9 +388,9 @@ frappe.ui.Filter = Class.extend({ | |||||
}); | }); | ||||
this.$btn_group.find(".toggle-filter").on("click", function() { | 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() { | set_filter_button_text: function() { | ||||
@@ -27,15 +27,15 @@ | |||||
<div class="list-paging-area"> | <div class="list-paging-area"> | ||||
<div class="row"> | <div class="row"> | ||||
<div class="col-xs-6"> | <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 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="100">100</button> | ||||
<button type="button" class="btn btn-default btn-sm" data-value="500">500</button> | <button type="button" class="btn btn-default btn-sm" data-value="500">500</button> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="col-xs-6 text-right"> | |||||
<button class="btn btn-default btn-more btn-sm">{%= _more %}...</button> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> |
@@ -64,11 +64,11 @@ frappe.ui.Listing = Class.extend({ | |||||
$.extend(this, this.opts); | $.extend(this, this.opts); | ||||
$(this.parent).html(frappe.render_template("listing", 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(); | this.set_events(); | ||||
if(this.page) { | if(this.page) { | ||||
this.$w.find('.list-toolbar-wrapper').toggle(false); | |||||
this.wrapper.find('.list-toolbar-wrapper').toggle(false); | |||||
} | } | ||||
if(this.show_filters) { | if(this.show_filters) { | ||||
@@ -79,9 +79,9 @@ frappe.ui.Listing = Class.extend({ | |||||
if(this.page) { | if(this.page) { | ||||
return this.page.add_menu_item(label, click, icon) | return this.page.add_menu_item(label, click, icon) | ||||
} else { | } else { | ||||
this.$w.find('.list-toolbar-wrapper').removeClass("hide"); | |||||
this.wrapper.find('.list-toolbar-wrapper').removeClass("hide"); | |||||
$button = $('<button class="btn btn-default"></button>') | $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) | .html((icon ? ("<i class='"+icon+"'></i> ") : "") + label) | ||||
.click(click); | .click(click); | ||||
return $button | return $button | ||||
@@ -91,13 +91,13 @@ frappe.ui.Listing = Class.extend({ | |||||
var me = this; | var me = this; | ||||
// next page | // next page | ||||
this.$w.find('.btn-more').click(function() { | |||||
this.wrapper.find('.btn-more').click(function() { | |||||
me.run(true); | 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.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"); | $(this).addClass("btn-info"); | ||||
// always reset when changing list page length | // always reset when changing list page length | ||||
@@ -106,20 +106,20 @@ frappe.ui.Listing = Class.extend({ | |||||
// select the correct page length | // select the correct page length | ||||
if(this.opts.page_length != 20) { | 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 | // title | ||||
if(this.title) { | if(this.title) { | ||||
this.$w.find('h3').html(this.title).toggle(true); | |||||
this.wrapper.find('h3').html(this.title).toggle(true); | |||||
} | } | ||||
// new | // new | ||||
this.set_primary_action(); | this.set_primary_action(); | ||||
if(me.no_toolbar || me.hide_toolbar) { | 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() { | make_filters: function() { | ||||
this.filter_list = new frappe.ui.FilterList({ | this.filter_list = new frappe.ui.FilterList({ | ||||
listobj: this, | listobj: this, | ||||
$parent: this.$w.find('.list-filters').toggle(true), | |||||
$parent: this.wrapper.find('.list-filters').toggle(true), | |||||
doctype: this.doctype, | doctype: this.doctype, | ||||
filter_fields: this.filter_fields | filter_fields: this.filter_fields | ||||
}); | }); | ||||
@@ -170,9 +170,9 @@ frappe.ui.Listing = Class.extend({ | |||||
clear: function() { | clear: function() { | ||||
this.data = []; | 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; | this.start = 0; | ||||
}, | }, | ||||
@@ -274,7 +274,7 @@ frappe.ui.Listing = Class.extend({ | |||||
} | } | ||||
}, | }, | ||||
set_working: function(flag) { | set_working: function(flag) { | ||||
this.$w.find('.img-load').toggle(flag); | |||||
this.wrapper.find('.img-load').toggle(flag); | |||||
}, | }, | ||||
get_call_args: function() { | get_call_args: function() { | ||||
// load query | // load query | ||||
@@ -305,7 +305,7 @@ frappe.ui.Listing = Class.extend({ | |||||
render_results: function(r) { | render_results: function(r) { | ||||
if(this.start===0) this.clear(); | 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) { | if(r.message) { | ||||
r.values = this.get_values_from_response(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); | this.update_paging(r.values); | ||||
} else { | } else { | ||||
if(this.start===0) { | if(this.start===0) { | ||||
this.$w.find('.result').toggle(false); | |||||
this.wrapper.find('.result').toggle(false); | |||||
var msg = this.get_no_result_message | var msg = this.get_no_result_message | ||||
? this.get_no_result_message() | ? this.get_no_result_message() | ||||
@@ -325,7 +325,7 @@ frappe.ui.Listing = Class.extend({ | |||||
? this.no_result_message | ? this.no_result_message | ||||
: __("Nothing to show")); | : __("Nothing to show")); | ||||
this.$w.find('.no-result') | |||||
this.wrapper.find('.no-result') | |||||
.html(msg) | .html(msg) | ||||
.toggle(true); | .toggle(true); | ||||
} | } | ||||
@@ -334,7 +334,7 @@ frappe.ui.Listing = Class.extend({ | |||||
// callbacks | // callbacks | ||||
if(this.onrun) this.onrun(); | if(this.onrun) this.onrun(); | ||||
if(this.callback) this.callback(r); | if(this.callback) this.callback(r); | ||||
this.$w.trigger("render-complete"); | |||||
this.wrapper.trigger("render-complete"); | |||||
}, | }, | ||||
get_values_from_response: function(data) { | get_values_from_response: function(data) { | ||||
@@ -356,21 +356,9 @@ frappe.ui.Listing = Class.extend({ | |||||
}, | }, | ||||
render_rows: function(values) { | render_rows: function(values) { | ||||
// render the rows | // 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(){ | render_image_gallery: function(){ | ||||
@@ -384,17 +372,17 @@ frappe.ui.Listing = Class.extend({ | |||||
"assets/frappe/js/lib/gallery/css/blueimp-gallery-indicator.css" | "assets/frappe/js/lib/gallery/css/blueimp-gallery-indicator.css" | ||||
], function(){ | ], function(){ | ||||
// remove previous gallery container | // remove previous gallery container | ||||
me.$w.find(".blueimp-gallery").remove(); | |||||
me.wrapper.find(".blueimp-gallery").remove(); | |||||
// append gallery div | // append gallery div | ||||
var gallery = frappe.render_template("blueimp-gallery", {}); | 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(); | event.preventDefault(); | ||||
opts = { | opts = { | ||||
doctype: me.doctype, | doctype: me.doctype, | ||||
docname: $(this).parent().attr('data-name'), | docname: $(this).parent().attr('data-name'), | ||||
container: me.$w | |||||
container: me.wrapper | |||||
}; | }; | ||||
new frappe.views.ImageView(opts); | new frappe.views.ImageView(opts); | ||||
}); | }); | ||||
@@ -402,14 +390,14 @@ frappe.ui.Listing = Class.extend({ | |||||
}, | }, | ||||
update_paging: function(values) { | update_paging: function(values) { | ||||
if(values.length >= this.page_length) { | 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; | this.start += this.page_length; | ||||
} | } | ||||
}, | }, | ||||
add_row: function(row) { | add_row: function(row) { | ||||
return $('<div class="list-row">') | return $('<div class="list-row">') | ||||
.data("data", (this.meta && this.meta.image_view) == 0 ? row : null) | .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); | .get(0); | ||||
}, | }, | ||||
refresh: function() { | refresh: function() { | ||||
@@ -13,8 +13,8 @@ frappe.ui.TagEditor = Class.extend({ | |||||
*/ | */ | ||||
$.extend(this, opts); | $.extend(this, opts); | ||||
var me = this; | 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({ | this.$tags.tagit({ | ||||
animate: false, | animate: false, | ||||
allowSpaces: true, | allowSpaces: true, | ||||
@@ -59,7 +59,7 @@ frappe.ui.TagEditor = Class.extend({ | |||||
}, | }, | ||||
setup_autocomplete: function() { | setup_autocomplete: function() { | ||||
var me = this; | var me = this; | ||||
this.$w.find("input").autocomplete({ | |||||
this.wrapper.find("input").autocomplete({ | |||||
minLength: 0, | minLength: 0, | ||||
minChars: 0, | minChars: 0, | ||||
source: function(request, response) { | source: function(request, response) { | ||||
@@ -8,10 +8,10 @@ frappe.ui.Tree = Class.extend({ | |||||
init: function(args) { | init: function(args) { | ||||
$.extend(this, args); | $.extend(this, args); | ||||
this.nodes = {}; | this.nodes = {}; | ||||
this.$w = $('<div class="tree">').appendTo(this.parent); | |||||
this.wrapper = $('<div class="tree">').appendTo(this.parent); | |||||
this.rootnode = new frappe.ui.TreeNode({ | this.rootnode = new frappe.ui.TreeNode({ | ||||
tree: this, | tree: this, | ||||
parent: this.$w, | |||||
parent: this.wrapper, | |||||
label: this.label, | label: this.label, | ||||
parent_label: null, | parent_label: null, | ||||
expandable: true, | expandable: true, | ||||
@@ -53,7 +53,7 @@ frappe.ui.TreeNode = Class.extend({ | |||||
this.$a = $('<span class="tree-link">') | this.$a = $('<span class="tree-link">') | ||||
.click(function(event) { | .click(function(event) { | ||||
me.tree.selected_node = me; | 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"); | me.$a.addClass("active"); | ||||
if(me.tree.toolbar) { | if(me.tree.toolbar) { | ||||
me.show_toolbar(); | me.show_toolbar(); | ||||
@@ -188,7 +188,7 @@ frappe.ui.TreeNode = Class.extend({ | |||||
} | } | ||||
// select this link | // select this link | ||||
this.tree.$w.find('.selected') | |||||
this.tree.wrapper.find('.selected') | |||||
.removeClass('selected'); | .removeClass('selected'); | ||||
this.$a.toggleClass('selected'); | this.$a.toggleClass('selected'); | ||||
this.expanded = !this.expanded; | this.expanded = !this.expanded; | ||||
@@ -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'); | |||||
}); | |||||
} | |||||
}); |
@@ -351,7 +351,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({ | |||||
this.dataView = new Slick.Data.DataView(); | this.dataView = new Slick.Data.DataView(); | ||||
this.set_data(this.data); | 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 | // set height if not auto | ||||
if(!options.autoHeight) | if(!options.autoHeight) | ||||
@@ -504,13 +504,13 @@ frappe.views.ReportView = frappe.ui.Listing.extend({ | |||||
set_tag_and_status_filter: function() { | set_tag_and_status_filter: function() { | ||||
var me = this; | 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")) { | if($(this).attr("data-label")) { | ||||
me.set_filter("_user_tags", $(this).attr("data-label")); | me.set_filter("_user_tags", $(this).attr("data-label")); | ||||
me.refresh(); | 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")) { | if($(this).attr("data-workflow-state")) { | ||||
me.set_filter(me.state_fieldname, | me.set_filter(me.state_fieldname, | ||||
$(this).attr("data-workflow-state")); | $(this).attr("data-workflow-state")); | ||||
@@ -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. |
@@ -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; | |||||
} | |||||
@@ -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>— 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> |
@@ -1,38 +1,97 @@ | |||||
@import "variables.less"; | @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; | |||||
} | |||||
} | } | ||||
@@ -0,0 +1 @@ | |||||
bench.patches.v3.deprecate_old_config |