Merge pull request #897 from opf/feature/remove-raphaël-dependency

Feature/remove raphaël dependency
pull/917/head
Till Breuer 11 years ago
commit 7664f0d6cf
  1. 10
      app/assets/javascripts/raphael-min.js
  2. 5815
      app/assets/javascripts/raphael.js
  3. 55
      app/assets/javascripts/timelines.js
  4. 194
      app/assets/javascripts/timelines/FilterQueryStringBuilder.js
  5. 164
      app/assets/javascripts/timelines/SvgHelper.js
  6. 2
      app/assets/javascripts/timelines/TimelineLoader.js
  7. 2
      app/assets/javascripts/timelines/TreeNode.js
  8. 2
      app/assets/javascripts/timelines/constants.js
  9. 2
      app/assets/javascripts/timelines/model/Color.js
  10. 2
      app/assets/javascripts/timelines/model/HistoricalPlanningElement.js
  11. 2
      app/assets/javascripts/timelines/model/PlanningElement.js
  12. 4
      app/assets/javascripts/timelines/model/PlanningElementType.js
  13. 2
      app/assets/javascripts/timelines/model/Project.js
  14. 2
      app/assets/javascripts/timelines/model/ProjectAssociation.js
  15. 2
      app/assets/javascripts/timelines/model/ProjectType.js
  16. 2
      app/assets/javascripts/timelines/model/Reporting.js
  17. 2
      app/assets/javascripts/timelines/model/Status.js
  18. 2
      app/assets/javascripts/timelines/model/User.js
  19. 16
      app/assets/javascripts/timelines/ui.js
  20. 1
      app/views/timelines/_timeline.html.erb

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -37,21 +37,54 @@
// │ OpenProject timelines module. │
// ╰───────────────────────────────────────────────────────────────╯
// This file adds some svg-helper methods
// to make svg creation easier
//= require timelines/SvgHelper
/*
* These files handle loading of timelines data.
* The TimelineLoader finds all dependencies and issues
* REST-server requests to grab the necessary data.
* The filterQueryStringBuilder creates our request parameters
* adding filter criteria to it.
*/
//= require timelines/FilterQueryStringBuilder
//= require timelines/TimelineLoader
// as our planning elements and projects are painted as a tree
// we need some representation of said tree and an easy method
// to iterate it. This class takes care of it!
//= require timelines/TreeNode
//= require timelines/constants
//= require timelines/ui
// renders the table and graph-background
//= require timelines/ui
// A model for the typical OpenProject Project.
//= require timelines/model/Project
// PlanningElements are what we paint as svgs in the end.
// PlanningElement is the old name for Work Package
//= require timelines/model/PlanningElement
// Historical Planning elements represent old states
// of planning elements for comparisons.
// These are painted as svgs too.
//= require timelines/model/HistoricalPlanningElement
//= require timelines/model/ProjectAssociation
// reportings are loaded first and they determine our
// project scope. Only projects reporting to the project
// we are currently looking at will be shown in the timeline.
//= require timelines/model/Reporting
// associations are nondirection relationships between projects.
// they are mainly used for the second level grouping which is
// calculated in the function secondLevelGroupingAdjustments.
//= require timelines/model/ProjectAssociation
// remaining simple models for project type, color, status
// planning element type and user.
//= require timelines/model/ProjectType
//= require timelines/model/Color
//= require timelines/model/CustomFields
@ -59,6 +92,13 @@
//= require timelines/model/PlanningElementType
//= require timelines/model/User
/* startup
* -> setupUI -> loader -> load & create model objects
* -> link model objects
* -> getLeftHandTree
* -> completeUI -> zoom -> rebuildAll -> rebuildTree -> filter nodes
* -> rebuldGraph -> render models in svg
*/
// stricter than default
/*jshint undef:true,
@ -74,7 +114,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true, modalHelperInstance: true, I18n: true*/
/*global jQuery:false, Timeline:true, modalHelperInstance: true, I18n: true*/
if (typeof Timeline === "undefined") {
Timeline = {};
@ -337,8 +377,6 @@ jQuery.extend(Timeline, {
throw new Error('jQuery UI seems to be missing (jQuery().slider is undefined)');
} else if ((1).month === undefined) {
throw new Error('date.js seems to be missing ((1).month is undefined)');
} else if (Raphael === undefined) {
throw new Error('Raphael seems to be missing (Raphael is undefined)');
}
return true;
},
@ -455,6 +493,10 @@ jQuery.extend(Timeline, {
this.die(e);
}
},
/* This function calculates the second level grouping adjustments.
* For every base project it finds all associates with the given project type.
* It removes every such project from the trees root and adds it underneath the base project.
*/
secondLevelGroupingAdjustments : function () {
var grouping = jQuery.map(this.options.grouping_two_selection || [], Timeline.pnum);
var root = this.getProject();
@ -472,8 +514,9 @@ jQuery.extend(Timeline, {
if (typeof other.getProjectType === "function") {
var pt = other.getProjectType();
var type = pt !== null ? pt.id : -1;
var relevant = false;
//check if the type is selected as 2nd level grouping
var relevant = false;
jQuery.each(grouping, function(k, l) {
if (l === type) {
relevant = true;

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};
@ -59,99 +59,99 @@ if (typeof Timeline === "undefined") {
Timeline.FilterQueryStringBuilder = (function() {
/**
* FilterQueryStringBuilder
*
* Simple serializer of query strings that satisfies OpenProject's filter
* API. Transforms hashes of desired filterings into the proper query strings.
*
* Examples:
*
* fqsb = (new FilterQueryStringBuilder({
* 'type_id': [4, 5]
* })).build(
* '/api/v2/projects/sample_project/planning_elements.json'
* );
*
* => /api/v2/projects/sample_project/planning_elements.json?f[]=type_id&op[type_id]==&v[type_id][]=4&v[type_id][]=5
*
* fqsb = (new FilterQueryStringBuilder())
* .filter({ 'type_id': [4, 5] })
* .append({ 'at_time': 1380795754 })
* .build( '/api/v2/projects/sample_project/planning_elements.json' );
*
* => /api/v2/projects/sample_project/planning_elements.json?f[]=type_id&op[type_id]==&v[type_id][]=4&v[type_id][]=5&at_time=1380795754
*/
var FilterQueryStringBuilder = function (filterHash) {
this.filterHash = filterHash || {};
this.paramsHash = {};
};
FilterQueryStringBuilder.prototype.filter = function(filters) {
this.filterHash = jQuery.extend({}, this.filterHash, filters);
return this;
};
FilterQueryStringBuilder.prototype.append = function(addition) {
this.paramsHash = jQuery.extend({}, this.paramsHash, addition);
return this;
};
FilterQueryStringBuilder.prototype.buildMetaDataForKey = function(key) {
this.queryStringParts.push({name: 'f[]', value: key},
{name: 'op[' + key + ']', value: '='});
};
FilterQueryStringBuilder.prototype.prepareFilterDataForKeyAndValue = function(key, value) {
this.queryStringParts.push({name: 'v[' + key + '][]', value: value});
};
FilterQueryStringBuilder.prototype.prepareAdditionalQueryData = function(key, value) {
this.queryStringParts.push({name: key, value: value});
};
FilterQueryStringBuilder.prototype.prepareFilterDataForKeyAndArrayOfValues = function(key, value) {
jQuery.each(value, jQuery.proxy( function(i, e) {
this.prepareFilterDataForKeyAndValue(key, e);
}, this));
};
FilterQueryStringBuilder.prototype.buildFilterDataForValue = function(key, value) {
if (value instanceof Array) {
this.prepareFilterDataForKeyAndArrayOfValues(key, value);
} else {
this.prepareFilterDataForKeyAndValue(key, value);
}
};
FilterQueryStringBuilder.prototype.registerKeyAndValue = function(key, value) {
this.buildMetaDataForKey(key);
this.buildFilterDataForValue(key, value);
};
FilterQueryStringBuilder.prototype.prepareQueryStringParts = function() {
this.queryStringParts = [];
jQuery.each(this.filterHash, jQuery.proxy(this.registerKeyAndValue, this));
jQuery.each(this.paramsHash, jQuery.proxy(this.prepareAdditionalQueryData, this));
};
FilterQueryStringBuilder.prototype.buildQueryStringFromQueryStringParts = function(url) {
return jQuery.map(this.queryStringParts, function(e, i) {
return e.name + "=" + encodeURIComponent(e.value);
}).join('&');
};
FilterQueryStringBuilder.prototype.buildUrlFromQueryStringParts = function(url) {
var resultUrl = url;
resultUrl += "?";
resultUrl += this.buildQueryStringFromQueryStringParts();
return resultUrl;
};
FilterQueryStringBuilder.prototype.build = function(url) {
this.prepareQueryStringParts();
return this.buildUrlFromQueryStringParts(url);
};
return FilterQueryStringBuilder;
})();
/**
* FilterQueryStringBuilder
*
* Simple serializer of query strings that satisfies OpenProject's filter
* API. Transforms hashes of desired filterings into the proper query strings.
*
* Examples:
*
* fqsb = (new FilterQueryStringBuilder({
* 'type_id': [4, 5]
* })).build(
* '/api/v2/projects/sample_project/planning_elements.json'
* );
*
* => /api/v2/projects/sample_project/planning_elements.json?f[]=type_id&op[type_id]==&v[type_id][]=4&v[type_id][]=5
*
* fqsb = (new FilterQueryStringBuilder())
* .filter({ 'type_id': [4, 5] })
* .append({ 'at_time': 1380795754 })
* .build( '/api/v2/projects/sample_project/planning_elements.json' );
*
* => /api/v2/projects/sample_project/planning_elements.json?f[]=type_id&op[type_id]==&v[type_id][]=4&v[type_id][]=5&at_time=1380795754
*/
var FilterQueryStringBuilder = function (filterHash) {
this.filterHash = filterHash || {};
this.paramsHash = {};
};
FilterQueryStringBuilder.prototype.filter = function(filters) {
this.filterHash = jQuery.extend({}, this.filterHash, filters);
return this;
};
FilterQueryStringBuilder.prototype.append = function(addition) {
this.paramsHash = jQuery.extend({}, this.paramsHash, addition);
return this;
};
FilterQueryStringBuilder.prototype.buildMetaDataForKey = function(key) {
this.queryStringParts.push({name: 'f[]', value: key},
{name: 'op[' + key + ']', value: '='});
};
FilterQueryStringBuilder.prototype.prepareFilterDataForKeyAndValue = function(key, value) {
this.queryStringParts.push({name: 'v[' + key + '][]', value: value});
};
FilterQueryStringBuilder.prototype.prepareAdditionalQueryData = function(key, value) {
this.queryStringParts.push({name: key, value: value});
};
FilterQueryStringBuilder.prototype.prepareFilterDataForKeyAndArrayOfValues = function(key, value) {
jQuery.each(value, jQuery.proxy( function(i, e) {
this.prepareFilterDataForKeyAndValue(key, e);
}, this));
};
FilterQueryStringBuilder.prototype.buildFilterDataForValue = function(key, value) {
if (value instanceof Array) {
this.prepareFilterDataForKeyAndArrayOfValues(key, value);
} else {
this.prepareFilterDataForKeyAndValue(key, value);
}
};
FilterQueryStringBuilder.prototype.registerKeyAndValue = function(key, value) {
this.buildMetaDataForKey(key);
this.buildFilterDataForValue(key, value);
};
FilterQueryStringBuilder.prototype.prepareQueryStringParts = function() {
this.queryStringParts = [];
jQuery.each(this.filterHash, jQuery.proxy(this.registerKeyAndValue, this));
jQuery.each(this.paramsHash, jQuery.proxy(this.prepareAdditionalQueryData, this));
};
FilterQueryStringBuilder.prototype.buildQueryStringFromQueryStringParts = function(url) {
return jQuery.map(this.queryStringParts, function(e, i) {
return e.name + "=" + encodeURIComponent(e.value);
}).join('&');
};
FilterQueryStringBuilder.prototype.buildUrlFromQueryStringParts = function(url) {
var resultUrl = url;
resultUrl += "?";
resultUrl += this.buildQueryStringFromQueryStringParts();
return resultUrl;
};
FilterQueryStringBuilder.prototype.build = function(url) {
this.prepareQueryStringParts();
return this.buildUrlFromQueryStringParts(url);
};
return FilterQueryStringBuilder;
})();

@ -0,0 +1,164 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
// ╭───────────────────────────────────────────────────────────────╮
// │ _____ _ _ _ │
// │ |_ _(_)_ __ ___ ___| (_)_ __ ___ ___ │
// │ | | | | '_ ` _ \ / _ \ | | '_ \ / _ \/ __| │
// │ | | | | | | | | | __/ | | | | | __/\__ \ │
// │ |_| |_|_| |_| |_|\___|_|_|_| |_|\___||___/ │
// ├───────────────────────────────────────────────────────────────┤
// │ Javascript library that fetches and plots timelines for the │
// │ OpenProject timelines module. │
// ╰───────────────────────────────────────────────────────────────╯
if (typeof Timeline === "undefined") {
Timeline = {};
}
Timeline.SvgHelper = (function() {
var SvgHelper = function(node) {
this.root = this.provideNode('svg').attr({
'width': 640,
'height': 480
});
jQuery(node).append(this.root);
};
SvgHelper.prototype.toString = function() {
return "SvgHelper";
};
SvgHelper.prototype.provideNode = function(elementName) {
return document.createElementNS(
'http://www.w3.org/2000/svg',
elementName
);
};
SvgHelper.prototype.clear = function() {
var node = this.root;
while (node.hasChildNodes() ){
node.removeChild(node.lastChild);
}
return this;
};
SvgHelper.prototype.setSize = function(w, h) {
this.root.attr({
'width': w,
'height': h,
});
};
SvgHelper.prototype.rect = function(x, y, w, h, r) {
var node = this.provideNode('rect').attr({
'x': x,
'y': y,
'width': w,
'height': h
});
if (r) {
node.round(r);
}
this.root.appendChild(node);
return node;
};
SvgHelper.prototype.path = function(direction) {
var node = this.provideNode('path').attr({
'd': direction
});
this.root.appendChild(node);
return node;
};
SvgHelper.prototype.text = function(x, y, text) {
var node = this.provideNode('text');
node.translate(x, y);
node.textContent = text;
this.root.appendChild(node);
return node;
};
return SvgHelper;
})();
jQuery.each([SVGSVGElement, SVGRectElement, SVGPathElement,
SVGTextElement], function (i, klass) {
klass.prototype.attr = function(attributeHash) {
for (key in attributeHash) {
if (attributeHash.hasOwnProperty(key)) {
this.setAttribute(key, attributeHash[key]);
}
}
// allow chaining.
return this;
};
});
jQuery.each([SVGRectElement, SVGTextElement], function (i, klass) {
klass.prototype.translate = function(x, y) {
return this.attr({
'x': x,
'y': y
});
};
});
SVGTextElement.prototype.insertAfter = function(node) {
this.parentNode.insertBefore(node, this.nextSibling);
};
SVGRectElement.prototype.round = function(r) {
this.attr({
'rx': r,
'ry': r
});
};
SVGRectElement.prototype.hover = function(f_in, f_out) {
this.addEventListener("mouseover", f_in);
this.addEventListener("mouseout", f_out)
};
SVGRectElement.prototype.unhover = function() {
// TODO (not sure if we even need this)
};
SVGRectElement.prototype.click = function(cb) {
this.addEventListener("click", cb);
};
SVGPathElement.prototype.transform = function(transform) {
return this.attr({'transform': transform});
};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};
@ -76,4 +76,4 @@ jQuery.extend(Timeline, {
return result;
}
}
});
});

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -51,7 +51,7 @@
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*global jQuery:false, Timeline:true*/
if (typeof Timeline === "undefined") {
Timeline = {};

@ -50,8 +50,8 @@
/*jshint eqnull:true */
// environment and other global vars
/*jshint browser:true, devel:true*/
/*global jQuery:false, Raphael:false, Timeline:true*/
/*jshint browser:true, devel:true */
/*global jQuery:false, Timeline:true */
if (typeof Timeline === "undefined") {
Timeline = {};
@ -695,7 +695,7 @@ jQuery.extend(Timeline, {
// lift the curtain, paper otherwise doesn't show w/ VML.
jQuery('.timeline').removeClass('tl-under-construction');
this.paper = new Raphael(this.paperElement, 640, 480);
this.paper = new Timeline.SvgHelper(this.paperElement);
// perform some zooming. if there is a zoom level stored with the
// report, zoom to it. otherwise, zoom out. this also constructs
@ -1184,7 +1184,9 @@ jQuery.extend(Timeline, {
y: deco + 0.5, // the vertical line otherwise overlaps.
w: width
})
);
).attr({
'stroke': '#000000'
});
}
}
@ -1402,7 +1404,7 @@ jQuery.extend(Timeline, {
})
).attr({
'stroke': 'blue',
'stroke-dasharray': '- '
'stroke-dasharray': '4,3'
});
}
@ -1417,7 +1419,7 @@ jQuery.extend(Timeline, {
})
).attr({
'stroke': 'blue',
'stroke-dasharray': '- '
'stroke-dasharray': '4,3'
});
}
},
@ -1441,7 +1443,7 @@ jQuery.extend(Timeline, {
})
).attr({
'stroke': 'red',
'stroke-dasharray': '- '
'stroke-dasharray': '4,3'
});
var setDateTime = 5 * 60 * 1000;

@ -107,7 +107,6 @@ See doc/COPYRIGHT.rdoc for more details.
<%= include_calendar_headers_tags %>
<%= javascript_include_tag 'raphael-min.js', :plugin => 'chiliproject_timelines' %>
<%= javascript_include_tag 'timelines.js', :plugin => 'chiliproject_timelines' %>
<%= javascript_include_tag 'timelines_modal.js', :plugin => 'chiliproject_timelines' %>
<% @timeline_header_included = true %>

Loading…
Cancel
Save