Converted reporting_engine into a Rails engine

pull/6827/head
Sebastian Schuster 12 years ago
parent cb773f5e4a
commit ece2f6395c
  1. 0
      lib/assets/images/close.gif
  2. 0
      lib/assets/images/delete.gif
  3. 0
      lib/assets/images/delete.png
  4. 0
      lib/assets/images/disk.gif
  5. 0
      lib/assets/images/disks.gif
  6. 0
      lib/assets/images/icon_info_red.gif
  7. 0
      lib/assets/images/loading.gif
  8. 0
      lib/assets/images/remove.gif
  9. 0
      lib/assets/images/remove.png
  10. BIN
      lib/assets/images/reporting_engine/close.gif
  11. BIN
      lib/assets/images/reporting_engine/delete.gif
  12. BIN
      lib/assets/images/reporting_engine/delete.png
  13. BIN
      lib/assets/images/reporting_engine/disk.gif
  14. BIN
      lib/assets/images/reporting_engine/disks.gif
  15. BIN
      lib/assets/images/reporting_engine/icon_info_red.gif
  16. BIN
      lib/assets/images/reporting_engine/loading.gif
  17. BIN
      lib/assets/images/reporting_engine/remove.gif
  18. BIN
      lib/assets/images/reporting_engine/remove.png
  19. 0
      lib/assets/javascripts/cordinc_tooltip.js
  20. 0
      lib/assets/javascripts/reporting.js
  21. 0
      lib/assets/javascripts/reporting/controls.js
  22. 0
      lib/assets/javascripts/reporting/filters.js
  23. 0
      lib/assets/javascripts/reporting/group_bys.js
  24. 0
      lib/assets/javascripts/reporting/lang/reporting-de.js
  25. 0
      lib/assets/javascripts/reporting/lang/reporting-en.js
  26. 0
      lib/assets/javascripts/reporting/progressbar.js
  27. 0
      lib/assets/javascripts/reporting/prototype_progress_bar.js
  28. 0
      lib/assets/javascripts/reporting/restore_query.js
  29. 159
      lib/assets/javascripts/reporting_engine/cordinc_tooltip.js
  30. 72
      lib/assets/javascripts/reporting_engine/reporting.js
  31. 192
      lib/assets/javascripts/reporting_engine/reporting/controls.js
  32. 518
      lib/assets/javascripts/reporting_engine/reporting/filters.js
  33. 208
      lib/assets/javascripts/reporting_engine/reporting/group_bys.js
  34. 3
      lib/assets/javascripts/reporting_engine/reporting/lang/reporting-de.js
  35. 3
      lib/assets/javascripts/reporting_engine/reporting/lang/reporting-en.js
  36. 49
      lib/assets/javascripts/reporting_engine/reporting/progressbar.js
  37. 116
      lib/assets/javascripts/reporting_engine/reporting/prototype_progress_bar.js
  38. 90
      lib/assets/javascripts/reporting_engine/reporting/restore_query.js
  39. 0
      lib/assets/javascripts/reporting_engine/sortable.js
  40. 306
      lib/assets/javascripts/sortable.js
  41. 0
      lib/assets/stylesheets/help.css
  42. 0
      lib/assets/stylesheets/reporting.css
  43. 56
      lib/assets/stylesheets/reporting_engine/help.css
  44. 619
      lib/assets/stylesheets/reporting_engine/reporting.css
  45. 5
      lib/open_project/reporting_engine.rb
  46. 33
      lib/open_project/reporting_engine/engine.rb
  47. 0
      lib/open_project/reporting_engine/engine_module.rb
  48. 20
      lib/open_project/reporting_engine/helpers/reporting_helper.rb
  49. 2
      lib/open_project/reporting_engine/patches.rb
  50. 4
      lib/open_project/reporting_engine/patches/big_decimal_patch.rb
  51. 4
      lib/open_project/reporting_engine/patches/to_date_patch.rb
  52. 0
      lib/open_project/reporting_engine/proactive_autoloader.rb
  53. 2
      lib/open_project/reporting_engine/report.rb
  54. 0
      lib/open_project/reporting_engine/report/chainable.rb
  55. 0
      lib/open_project/reporting_engine/report/controller.rb
  56. 4
      lib/open_project/reporting_engine/report/filter.rb
  57. 0
      lib/open_project/reporting_engine/report/filter/base.rb
  58. 0
      lib/open_project/reporting_engine/report/filter/multi_choice.rb
  59. 0
      lib/open_project/reporting_engine/report/filter/no_filter.rb
  60. 8
      lib/open_project/reporting_engine/report/group_by.rb
  61. 0
      lib/open_project/reporting_engine/report/group_by/base.rb
  62. 0
      lib/open_project/reporting_engine/report/group_by/ruby_aggregation.rb
  63. 0
      lib/open_project/reporting_engine/report/group_by/singleton_value.rb
  64. 0
      lib/open_project/reporting_engine/report/group_by/sql_aggregation.rb
  65. 2
      lib/open_project/reporting_engine/report/inherited_attribute.rb
  66. 0
      lib/open_project/reporting_engine/report/operator.rb
  67. 0
      lib/open_project/reporting_engine/report/query_utils.rb
  68. 0
      lib/open_project/reporting_engine/report/result.rb
  69. 0
      lib/open_project/reporting_engine/report/sql_statement.rb
  70. 0
      lib/open_project/reporting_engine/report/table.rb
  71. 0
      lib/open_project/reporting_engine/report/transformer.rb
  72. 0
      lib/open_project/reporting_engine/report/validation.rb
  73. 0
      lib/open_project/reporting_engine/report/validation/dates.rb
  74. 0
      lib/open_project/reporting_engine/report/validation/integers.rb
  75. 0
      lib/open_project/reporting_engine/report/validation/sql.rb
  76. 0
      lib/open_project/reporting_engine/report/walker.rb
  77. 0
      lib/open_project/reporting_engine/tasks/spec.rake
  78. 5
      lib/open_project/reporting_engine/version.rb
  79. 4
      lib/open_project/reporting_engine/widget.rb
  80. 0
      lib/open_project/reporting_engine/widget/base.rb
  81. 0
      lib/open_project/reporting_engine/widget/controls.rb
  82. 0
      lib/open_project/reporting_engine/widget/controls/apply.rb
  83. 0
      lib/open_project/reporting_engine/widget/controls/clear.rb
  84. 0
      lib/open_project/reporting_engine/widget/controls/delete.rb
  85. 0
      lib/open_project/reporting_engine/widget/controls/query_name.rb
  86. 0
      lib/open_project/reporting_engine/widget/controls/save.rb
  87. 0
      lib/open_project/reporting_engine/widget/controls/save_as.rb
  88. 0
      lib/open_project/reporting_engine/widget/filters.rb
  89. 0
      lib/open_project/reporting_engine/widget/filters/base.rb
  90. 0
      lib/open_project/reporting_engine/widget/filters/date.rb
  91. 0
      lib/open_project/reporting_engine/widget/filters/heavy.rb
  92. 0
      lib/open_project/reporting_engine/widget/filters/label.rb
  93. 0
      lib/open_project/reporting_engine/widget/filters/multi_choice.rb
  94. 0
      lib/open_project/reporting_engine/widget/filters/multi_values.rb
  95. 0
      lib/open_project/reporting_engine/widget/filters/operators.rb
  96. 0
      lib/open_project/reporting_engine/widget/filters/option.rb
  97. 0
      lib/open_project/reporting_engine/widget/filters/remove_button.rb
  98. 0
      lib/open_project/reporting_engine/widget/filters/text_box.rb
  99. 0
      lib/open_project/reporting_engine/widget/group_bys.rb
  100. 0
      lib/open_project/reporting_engine/widget/help.rb
  101. Some files were not shown because too many files have changed in this diff Show More

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 139 B

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 67 B

Before

Width:  |  Height:  |  Size: 1022 B

After

Width:  |  Height:  |  Size: 1022 B

Before

Width:  |  Height:  |  Size: 64 B

After

Width:  |  Height:  |  Size: 64 B

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 67 B

Before

Width:  |  Height:  |  Size: 67 B

After

Width:  |  Height:  |  Size: 67 B

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before

Width:  |  Height:  |  Size: 54 B

After

Width:  |  Height:  |  Size: 54 B

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

@ -0,0 +1,159 @@
/*
* Copyright (c) 2009 Charles Cordingley (www.cordinc.com)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* cordinc_tooltip.js, v1.0.2 - 27 August 2008
* For help see www.cordinc.com/projects/tooltips.html
*/
var Tooltip = Class.create({
initialize: function(target, tooltip) {
var options = Object.extend({
start_effect: function(element) {},
end_effect: function(element) {},
zindex: 1000,
offset: {x:0, y:0},
hook: {target:'topRight', tip:'bottomLeft'},
trigger: false,
DOM_location: false,
className: false,
delay: {}
}, arguments[2] || {});
this.target = $(target);
this.show_at = (options.show_at_id !== undefined) ? $(options.show_at_id) : undefined
this.tooltip = $(tooltip);
this.options = options;
this.event_target = this.options.trigger?$(this.options.trigger):this.target;
if (this.options.className) {
this.tooltip.addClassName(this.options.className);
}
this.tooltip.hide();
this.display=false;
this.mouse_over = this.displayTooltip.bindAsEventListener(this);
this.mouse_out = this.removeTooltip.bindAsEventListener(this);
this.event_target.observe("mouseover", this.mouse_over);
this.event_target.observe("mouseout", this.mouse_out);
},
displayTooltip: function(event){
event.stop();
if (this.display) {return;}
if (this.options.delay.start) {
var self = this;
this.timer_id = setTimeout(function(){self.timer_id = false; self.showTooltip(event);}, this.options.delay.start*1000);
} else {
this.showTooltip(event);
}
},
showTooltip: function(event) {
var show_at = (this.show_at !== undefined) ? this.show_at : this.target
this.display=true;
position = this.positionTooltip(event);
this.clone = this.tooltip.cloneNode(true);
parentId = this.options.DOM_location?$(this.options.DOM_location.parentId):show_at.parentNode;
successorId = this.options.DOM_location?$(this.options.DOM_location.successorId):show_at;
parentId.insertBefore(this.clone, successorId);
this.clone.setStyle({
position: 'absolute',
top: position.top + "px",
left: position.left + "px",
display: "inline",
zIndex:this.options.zindex,
/* fix for ur dashboard */
visibility: 'visible',
width: "400px"
});
if (this.options.start_effect) {
this.options.start_effect(this.clone);
}
},
positionTooltip: function(event) {
target_position = this.target.cumulativeOffset();
tooltip_dimensions = this.tooltip.getDimensions();
target_dimensions = this.target.getDimensions();
this.positionModify(target_position, target_dimensions, this.options.hook.target, 1);
this.positionModify(target_position, tooltip_dimensions, this.options.hook.tip, -1);
target_position.top += this.options.offset.y;
target_position.left += this.options.offset.x;
return target_position;
},
positionModify: function(position, box, corner, neg) {
if (corner == 'topRight') {
position.left += box.width*neg;
} else if (corner == 'topLeft') {
} else if (corner == 'bottomLeft') {
position.top += box.height*neg;
} else if (corner == 'bottomRight') {
position.top += box.height*neg;
position.left += box.width*neg;
} else if (corner == 'topMid') {
position.left += (box.width/2)*neg;
} else if (corner == 'leftMid') {
position.top += (box.height/2)*neg;
} else if (corner == 'bottomMid') {
position.top += box.height*neg;
position.left += (box.width/2)*neg;
} else if (corner == 'rightMid') {
position.top += (box.height/2)*neg;
position.left += box.width*neg;
}
},
removeTooltip: function(event) {
if (this.timer_id) {
clearTimeout(this.timer_id);
this.timer_id = false;
return;
}
if (this.options.end_effect) {
this.options.end_effect(this.clone);
}
if (this.options.delay.end) {
var self = this;
setTimeout(function(){self.clearTooltip();}, this.options.delay.end*1000);
} else {
this.clearTooltip();
}
},
clearTooltip: function() {
if (this.clone !== undefined && this.clone !== null) {
this.clone.remove();
this.clone = null;
this.display=false;
}
},
destroy: function() {
this.event_target.stopObserving("mouseover", this.mouse_over);
this.event_target.stopObserving("mouseout", this.mouse_out);
this.clearTooltip();
}
})

@ -0,0 +1,72 @@
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Element */
window.Reporting = {
source: ($$("head")[0].select("script[src*='reporting.js']")[0].src),
require: function (libraryName) {
var jsName = Reporting.source.replace("reporting.js", "reporting/" + libraryName + ".js");
try {
// inserting via DOM fails in Safari 2.0, so brute force approach
document.write('<script type="text/javascript" src="' + jsName + '"><\/script>');
} catch (e) {
// for xhtml+xml served content, fall back to DOM methods
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = jsName;
document.getElementsByTagName('head')[0].appendChild(script);
}
},
onload: function (func) {
document.observe("dom:loaded", func);
},
flash: function (string, type) {
if (type === undefined) {
type = "error";
}
if ($("flash_" + type) !== null) {
$("flash_" + type).remove();
}
var flash = new Element('div', {
'id': 'flash_' + type,
'class': 'flash ' + type
}).update(new Element('a', {
'href': '#'
}).update(string));
$("content").insert({top: flash});
$$("#flash_" + type + " a")[0].focus();
},
clearFlash: function () {
$$('div[id^=flash]').each(function (oldMsg) {
oldMsg.remove();
});
},
fireEvent: function (element, event) {
var evt;
if (document.createEventObject) {
// dispatch for IE
evt = document.createEventObject();
return element.fireEvent('on' + event, evt);
} else {
// dispatch for firefox + others
evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
}
}
};
Reporting.require("filters");
Reporting.require("group_bys");
Reporting.require("restore_query");
Reporting.require("controls");
Reporting.require("prototype_progress_bar");
Reporting.require("progressbar");

@ -0,0 +1,192 @@
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Effect, Ajax, Element, selectAllOptions, Form */
Reporting.Controls = {
query_name_editor: function (target_id) {
var target = $(target_id);
var isPublic = target.getAttribute("data-is_public") === "true";
var updateUrl = target.getAttribute("data-update-url");
var translations = target.getAttribute("data-translations");
if (translations.isJSON()) {
translations = translations.evalJSON(true);
}
if (translations === undefined) {
translations = {};
}
if (translations.rename === undefined) {
translations.rename = 'ok';
}
if (translations.cancel === undefined) {
translations.cancel = 'cancel';
}
if (translations.saving === undefined) {
translations.saving = 'Saving...';
}
if (translations.loading === undefined) {
translations.loading = 'Loading...';
}
if (translations.clickToEdit === undefined) {
translations.loading = 'Click to edit';
}
var editor = new Ajax.InPlaceEditor(target_id, updateUrl, {
callback: function (form, value) {
return 'query_name=' + encodeURIComponent(value);
},
okControl: 'button',
cancelControl: 'button',
externalControl: 'query-name-edit-button',
okText: translations.rename,
cancelText: translations.cancel,
savingText: translations.saving,
loadingText: translations.loading,
clickToEditText: translations.clickToEdit,
onFailure: function (editor, response) {
Reporting.flash(response.responseText);
},
onComplete: function () {
Reporting.Controls.update_report_lists();
}
});
},
toggle_delete_form: function (e) {
var offset = $('query-icon-delete').positionedOffset().left;
$('delete_form').setStyle("left: " + offset + "px").toggle();
e.preventDefault();
},
toggle_save_as_form: function (e) {
var offset = $('query-icon-save-as').positionedOffset().left;
$('save_as_form').setStyle("left: " + offset + "px").toggle();
e.preventDefault();
},
clear_query: function (e) {
Reporting.Filters.clear();
Reporting.GroupBys.clear();
e.preventDefault();
},
send_settings_data: function (targetUrl, callback, failureCallback) {
if (failureCallback === undefined) {
failureCallback = Reporting.Controls.default_failure_callback;
}
Reporting.clearFlash();
new Ajax.Request(
targetUrl,
{ asynchronous: true,
evalScripts: true,
postBody: Reporting.Controls.serialize_settings_form(),
onSuccess: callback,
onFailure: failureCallback });
},
serialize_settings_form: function() {
var ret_str, grouping_str;
ret_str = Form.serialize('query_form');
grouping_str = $w('rows columns').inject('', function(grouping, type) {
return grouping + $('group_by_' + type).select('.group_by_element').map(function(group_by) {
return 'groups[' + type + '][]=' + group_by.readAttribute('data-group-by');
}).inject('', function(all_group_str, group_str) {
return all_group_str + '&' + group_str;
});
});
if (grouping_str.length > 0) {
ret_str += grouping_str;
}
return ret_str;
},
attach_settings_callback: function (element, callback) {
if (element === null) {
return;
}
failureCallback = function (response) {
$('result-table').update("");
Reporting.Controls.default_failure_callback(response);
};
element.observe("click", function (e) {
Reporting.Controls.send_settings_data(this.getAttribute("data-target"), callback, failureCallback);
e.preventDefault();
});
},
observe_click: function (element_id, callback) {
var el = $(element_id);
if (el !== null && el !== undefined) {
el.observe("click", callback);
}
},
update_result_table: function (response) {
$('result-table').update(response.responseText);
Reporting.Progress.confirm_question();
},
default_failure_callback: function (response) {
if (response.status >= 400 && response.status < 500) {
Reporting.flash(response.responseText);
Reporting.Progress.abort();
} else {
Reporting.flash(Reporting._LA["RESPONSE_ERROR"]);
Reporting.Progress.abort();
}
},
update_report_lists: function () {
$$(".report_list").each(function (list) {
Reporting.Controls.update_report_list(list);
});
},
update_report_list: function (list) {
var url = $(list).readAttribute("data-update-url");
if (url == null) {
return;
}
new Ajax.Request(url, {
onSuccess: function (response) {
list.replace(response.responseText);
}
});
}
};
Reporting.onload(function () {
if ($('query_saved_name') !== null) {
if ($('query_saved_name').getAttribute("data-update-url") !== null) {
Reporting.Controls.query_name_editor('query_saved_name');
}
// don't concern ourselves with new queries
if ($('query_saved_name').getAttribute("data-is_new") !== null) {
if ($('query-icon-delete') !== null) {
Reporting.Controls.observe_click("query-icon-delete", Reporting.Controls.toggle_delete_form);
Reporting.Controls.observe_click("query-icon-delete-cancel", Reporting.Controls.toggle_delete_form);
$('delete_form').hide();
}
if ($("query-breadcrumb-save") !== null) {
// When saving an update of an exisiting query or apply filters, we replace the table on success
Reporting.Controls.attach_settings_callback($("query-breadcrumb-save"), Reporting.Controls.update_result_table);
}
}
}
Reporting.Controls.observe_click("query-icon-save-as", Reporting.Controls.toggle_save_as_form);
Reporting.Controls.observe_click("query-icon-save-as-cancel", Reporting.Controls.toggle_save_as_form);
if ($('save_as_form') !== null) {
$('save_as_form').hide();
}
// When saving a new query, the success-response is the new saved query's url -> redirect to that
Reporting.Controls.attach_settings_callback($("query-icon-save-button"), function (response) {
Ajax.activeRequestCount = Ajax.activeRequestCount + 1; // HACK: Prevent Loading spinner from disappearing
document.location = response.responseText;
});
// When saving an update of an exisiting query or apply filters, we replace the table on success
Reporting.Controls.attach_settings_callback($("query-icon-apply-button"), Reporting.Controls.update_result_table);
Reporting.Controls.observe_click($('query-link-clear'), Reporting.Controls.clear_query);
});

@ -0,0 +1,518 @@
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Effect, Ajax, Element, Form */
Reporting.Filters = {
load_available_values_for_filter: function (filter_name, callback_func) {
var select, radio_options, post_select_values;
select = $$('.filter-value[data-filter-name="' + filter_name + '"]').first();
// check if we might have a radio-box
radio_options = $$('.' + filter_name + '_radio_option input');
if (radio_options && radio_options.size() !== 0) {
radio_options.first().checked = true;
callback_func();
}
if (select === null || select === undefined) {
return;
}
url = select.readAttribute("data-remote-url");
json_post_select_values = select.readAttribute('data-initially-selected')
if (json_post_select_values !== null && json_post_select_values !== undefined) {
post_select_values = json_post_select_values.replace(/'/g, '"').evalJSON(true);
}
if (select.readAttribute('data-loading') === "ajax" && select.childElements().length === 0) {
if (window.global_prefix === undefined) {
window.global_prefix = "";
}
new Ajax.Updater({ success: select.id }, url, {
parameters: {
filter_name: filter_name,
values: json_post_select_values
},
insertion: 'bottom',
evalScripts: false,
onCreate: function (a, b) {
$$("select[data-filter-name='" + filter_name + "']").each(function (e) { e.disable(); });
},
onComplete: function (a, b) {
$$("select[data-filter-name='" + filter_name + "']").each(function (e) { e.enable(); });
if (select.tagName.toLowerCase() === "select") {
if (post_select_values === undefined || post_select_values === null || post_select_values.size() === 0) {
select.selectedIndex = 0;
} else {
Reporting.Filters.select_values(select, post_select_values);
}
}
callback_func();
}
});
Reporting.Filters.multi_select(select, false);
} else {
callback_func();
}
},
show_filter: function (field, options) {
if (options === undefined) {
options = {};
}
if (options.callback_func === undefined) {
options.callback_func = function () {};
}
if (options.slowly === undefined) {
options.slowly = false;
}
if (options.show_filter === undefined) {
options.show_filter = true;
}
if (options.hide_only === undefined) {
options.hide_only = false;
}
var field_el = $('tr_' + field);
if (field_el !== null) {
if (options.insert_after === undefined) {
options.insert_after = Reporting.Filters.last_visible_filter();
}
if (options.insert_after !== undefined && options.show_filter) {
// Move the filter down to appear after the last currently visible filter
if (field_el.id !== options.insert_after.id) {
field_el.remove();
options.insert_after.insert({after: field_el});
}
}
// the following command might be included into the callback_function (which is called after the ajax request) later
var display_functor;
if (options.show_filter) {
(options.slowly ? Effect.Appear : Element.show)(field_el);
Reporting.Filters.load_available_values_for_filter(field, options.callback_func);
$('rm_' + field).value = field; // set the value, so the serialized form will return this filter
Reporting.Filters.value_changed(field);
Reporting.Filters.set_filter_value_widths(100);
} else {
(options.slowly ? Effect.Fade : Element.hide)(field_el);
if (!options.hide_only) { // remember that this filter used to be selected
field_el.removeAttribute('data-selected');
}
$('rm_' + field).value = ""; // reset the value, so the serialized form will not return this filter
Reporting.Filters.set_filter_value_widths(5000);
}
Reporting.Filters.operator_changed(field, $("operators[" + field + "]"));
Reporting.Filters.display_category($(field_el.getAttribute("data-label")));
}
},
/**
* Activates the filter with the given name and loads dependent filters if necessary.
*
* @param filter_name Name of the filter to be activated.
*/
add_filter: function (filter_name, activate_dependent, on_complete) {
var field = filter_name
if (activate_dependent === undefined) {
activate_dependent = true;
}
if (on_complete === undefined) {
on_complete = function() { };
}
// do this immediately instead of in callback to avoid concurrency issues during testing
Reporting.Filters.select_option_enabled($("add_filter_select"), filter_name, false);
Reporting.Filters.show_filter(field, { slowly: true, callback_func: function() {
if (activate_dependent) {
Reporting.Filters.activate_dependents($(field + "_arg_1_val"));
}
on_complete();
}
});
},
remove_filter: function (field, hide_only) {
Reporting.Filters.show_filter(field, { show_filter: false, hide_only: hide_only });
var dependent = Reporting.Filters.get_dependents($(field + '_arg_1_val'), false).find(function(d) {
return Reporting.Filters.visible_filters().include(d);
});
if (dependent !== undefined) {
Reporting.Filters.remove_filter(dependent);
}
Reporting.Filters.select_option_enabled($("add_filter_select"), field, true);
},
/*
Smoothly sets the width of currently displayed filters.
Params:
delay:Int
Time to wait before resizing the filters width */
set_filter_value_widths: function (delay) {
window.clearTimeout(Reporting.Filters.set_filter_value_widths_timeout);
if (Reporting.Filters.visible_filters().size() > 0) {
Reporting.Filters.set_filter_value_widths_timeout = window.setTimeout(function () {
var table_data = $("tr_" + Reporting.Filters.visible_filters().first()).select(".filter_values").first().up();
var current_width = table_data.getWidth();
var filter_values = $($$(".filter_values"));
// First, reset all widths
filter_values.each(function (f) {
$(f).up().style.width = "auto";
});
// Now, get the current width
// Any width will be fine, as the table layout makes all elements the same width
var new_width = table_data.getWidth();
if (new_width < current_width) {
// Set all widths to previous, so we can animate
filter_values.each(function (f) {
$(f).up().style.width = current_width + "px";
});
}
// Now, set all widths to be the widest
filter_values.each(function (f) {
if (new_width < current_width) {
$(f).up().morph("width: " + new_width + "px;");
} else {
$(f).up().style.width = new_width + "px";
}
});
}, delay);
}
},
set_filter_value_widths_timeout: undefined,
last_visible_filter: function () {
return $($$('.filter')).reverse().detect(function (f) {
return f.visible();
});
},
/* Display the given category if any of its filters are visible. Otherwise hide it */
display_category: function (label) {
if (label !== null) {
var filters = $$('.filter');
for (var i = 0; i < filters.length; i += 1) {
if (filters[i].visible() && filters[i].getAttribute("data-label") === label) {
Element.show(label);
return;
}
}
Element.hide(label);
}
},
operator_changed: function (field, select) {
var option_tag, arity, first;
if (select === null) {
return;
}
first = false
if (select.getAttribute("data-first") === undefined || select.getAttribute("data-first") === null) {
first = true;
$(select).setAttribute("data-first", "false");
}
option_tag = select.options[select.selectedIndex];
arity = parseInt(option_tag.getAttribute("data-arity"), 10);
Reporting.Filters.change_argument_visibility(field, arity);
if (option_tag.getAttribute("data-forced") !== undefined && option_tag.getAttribute("data-forced") !== null) {
Reporting.Filters.force_type(option_tag, first);
};
},
// Overwrite to customize input enforcements.
// option: 'option' HTMLElement
// first: Boolean indicating whether the operator changed for the first time
force_type: function (option, first) {
true;
},
value_changed: function (field) {
var val, tr;
val = $(field + '_arg_1_val');
tr = $('tr_' + field);
if (!val) {
return;
}
if (val.value === '<<inactive>>') {
tr.addClassName('inactive-filter');
} else {
tr.removeClassName('inactive-filter');
}
},
change_argument_visibility: function (field, arg_nr) {
var params, i;
params = [$(field + '_arg_1'), $(field + '_arg_2')];
for (i = 0; i < 2; i += 1) {
if (params[i] !== null) {
if (arg_nr >= (i + 1) || arg_nr <= (-1 - i)) {
params[i].show();
params[i].descendants().each(function (desc) { desc.show(); });
} else {
params[i].hide();
params[i].descendants().each(function (desc) { desc.hide(); });
}
}
}
},
select_option_enabled: function (box, value, state) {
var option = box.select("[value='" + value + "']").first();
if (option !== undefined) {
option.disabled = !state;
}
},
multi_select: function (select, multi) {
select.multiple = multi;
if (multi) {
select.size = 4;
// deselect first option if it's present
if (select.options[0] !== undefined && select.options[0] !== null) {
select.options[0].selected = false;
}
} else {
select.size = 1;
}
},
toggle_multi_select: function (select) {
Reporting.Filters.multi_select(select, !select.multiple);
},
visible_filters: function () {
return $("filter_table").select("tr").select(function (tr) {
return tr.visible() === true;
}).collect(function (filter) {
return filter.getAttribute("data-filter-name");
});
},
clear: function () {
Reporting.Filters.visible_filters().each(function (filter) {
Reporting.Filters.remove_filter(filter);
});
},
// Returns an array of dependents of the given element
// get_all -> Boolean: whether to return all dependends (even the
// dependents of this filters dependents) or not
get_dependents: function (element, get_all) {
var dependent_field = "data-all-dependents";
if (get_all === false) {
dependent_field = "data-next-dependents";
}
if (element.hasAttribute(dependent_field)) {
return element.getAttribute(dependent_field).replace(/'/g, '"').evalJSON(true);
} else {
return [];
}
},
// Activate the first dependent of the changed filter, if it is not already active.
// Afterwards, collect the visible filters from the dependents list and start
// narrowing down their values.
// Param: select [optional] - the select-box of the filter which should activate it's dependents
activate_dependents: function (selectBox, callbackWhenFinished) {
var all_dependents, next_dependents, dependent, active_filters, source;
if (selectBox === undefined || (selectBox.type && selectBox.type.toLowerCase() == 'change')) {
selectBox = this;
}
if (selectBox.tagName.toLowerCase() !== "select") {
return; // only multi_value filters have dependents
}
if (callbackWhenFinished === undefined) {
callbackWhenFinished = function(dependent) { };
}
source = selectBox.getAttribute("data-filter-name");
all_dependents = Reporting.Filters.get_dependents(selectBox);
next_dependents = Reporting.Filters.get_dependents(selectBox, false);
dependent = Reporting.Filters.which_dependent_shall_i_take(source, next_dependents);
if (!dependent) {
return;
}
active_filters = Reporting.Filters.visible_filters();
if (!active_filters.include(dependent)) {
// in case we run into a situation where the dependent to show is not in the currently selected dependency chain
// we have to remove all filters until we reach the source and add the new dependent
if (next_dependents.any( function(d){ return active_filters.include(d) } )) {
while (active_filters.last() !== source) {
Reporting.Filters.show_filter(active_filters.pop(1), { show_filter: false, slowly: true });
}
}
Reporting.Filters.show_filter(dependent, { slowly: true, insert_after: $(selectBox.up(".filter")) });
// render filter inactive if possible to avoid unintended filtering
$(dependent + '_arg_1_val').value = '<<inactive>>'
Reporting.Filters.operator_changed(dependent, $('operators[' + dependent + ']'));
// Hide remove box of dependent
$('rm_box_' + dependent).hide();
// Remove border of dependent, so it "merges" with the filter before
$('tr_' + dependent).addClassName("no-border");
active_filters.unshift(dependent);
}
setTimeout(function () { // Make sure the newly shown filters are in the DOM
var active_dependents = all_dependents.select(function (d) {
return active_filters.include(d);
});
Reporting.Filters.narrow_values(
Reporting.Filters.dependent_for(source),
active_dependents,
function() { callbackWhenFinished(dependent); }
);
}, 1);
},
// return an array of all filters that depend on the given filter plus the given filter
dependent_for: function(field) {
var deps = $$('.filters-select[data-all-dependents]').findAll(function(selectBox) {
return (selectBox.up('tr').visible()) && Reporting.Filters.get_dependents(selectBox).include(field)
}).map(function(selectBox) {
return selectBox.getAttribute("data-filter-name");
});
return deps === undefined ? [ field ] : [ field ].concat(deps)
},
// Select the given values of the selectBox.
// Toggle multi-select state of the selectBox depending on how many values were given.
select_values: function(selectBox, values_to_select) {
Reporting.Filters.multi_select(selectBox, values_to_select.size() > 1);
values_to_select.each(function (val) {
var opt = selectBox.select("option[value='" + val + "']");
if (opt.size() === 1) {
opt.first().selected = true;
}
});
},
exists: function (filter) {
return Reporting.Filters.visible_filters().include(filter);
},
// Narrow down the available values for the [dependents] of [sources].
// This will narrow down for each dependent separately, adding each finished
// dependent to the sources array and removing it from the dependents array.
narrow_values: function (sources, dependents, callbackWhenFinished) {
if (sources.size() === 0 || dependents.size === 0 || dependents.first() === undefined) {
return;
}
if (callbackWhenFinished === undefined) {
callbackWhenFinished = function() {};
}
var params = document.location.href.include('?') ? '&' : '?'
params = params + "narrow_values=1&dependent=" + dependents.first();
sources.each(function (filter) {
params = params + "&sources[]=" + filter;
});
var targetUrl = document.location.href + params;
var currentDependent = dependents.first();
var updater = new Ajax.Request(targetUrl,
{
asynchronous: true,
evalScripts: true,
postBody: Reporting.Controls.serialize_settings_form(),
onSuccess: function (response) {
Reporting.clearFlash();
if (response.responseJSON !== undefined) {
var continue_narrowing = true;
var selectBox = $(currentDependent + "_arg_1_val");
var selected = selectBox.select("option").collect(function (sel) {
if (sel.selected) {
return sel.value;
}
}).compact();
// remove old values
$(selectBox).childElements().each(function (o) {
o.remove();
});
// insert new values
response.responseJSON.each(function (o) {
var ary = [ (o === null ? "" : o) ].flatten();
var label = ary.first();
var value = ary.last();
// cannot use .innerhtml due to IE wierdness
$(selectBox).insert(new Element('option', {value: value}).update(label.escapeHTML()));
});
Reporting.Filters.select_values(selectBox, selected);
sources.push(currentDependent); // Add as last element
dependents.splice(0, 1); // Delete first element
// if we got no values besides the <<inactive>> value, do not show this selectBox
if (!selectBox.select("option").any(function (opt) { return opt.value != '<<inactive>>' })) {
Reporting.Filters.show_filter(currentDependent, { show_filter: false });
continue_narrowing = false;
}
// if the current filter is inactive, hide dependent - otherwise recurisvely narrow dependent values
if (selectBox.value == '<<inactive>>') {
Reporting.Filters.value_changed(currentDependent);
dependents.each(function (dependent) {
Reporting.Filters.show_filter(dependent, {
slowly: true,
show_filter: false });
});
continue_narrowing = false;
}
if (continue_narrowing) {
Reporting.Filters.narrow_values(sources, dependents);
}
callbackWhenFinished();
}
},
onException: function (response, error) {
if (console) {
console.log(error);
}
Reporting.flash("Loading of filter values failed. Probably, the server is temporary offline for maintenance.");
var selectBox = $(currentDependent + "_arg_1_val");
$(selectBox).insert(new Element('option', {value: '<<inactive>>'}).update('Failed to load values.'));
}
}
);
},
// This method may be overridden by the actual application to define custon behavior
// If there are multiple possible dependents to follow.
// The dependent to follow should be returned.
which_dependent_shall_i_take: function(source, dependents) {
return dependents.first();
}
};
Reporting.onload(function () {
if ($("add_filter_select")) {
$("add_filter_select").observe("change", function () {
if (!(Reporting.Filters.exists(this.value))) {
Reporting.Filters.add_filter(this.value);
this.selectedIndex = 0;
};
});
}
$$(".filter_rem").each(function (e) {
e.observe("click", function () {
var filter_name = this.up('tr').getAttribute("data-filter-name");
Reporting.Filters.remove_filter(filter_name);
});
});
$$(".filter_operator").each(function (e) {
e.observe("change", function (evt) {
var filter_name = this.getAttribute("data-filter-name");
Reporting.Filters.operator_changed(filter_name, this);
Reporting.fireEvent($(filter_name + "_arg_1_val"), "change");
});
});
$$(".filter_multi-select").each(function (e) {
e.observe("click", function () {
Reporting.Filters.toggle_multi_select($(this.getAttribute("data-filter-name") + '_arg_1_val'));
});
});
$$(".filters-select").each(function (s) {
var selected_size = Array.from(s.options).findAll(function (o) {
return o.selected === true;
}).size();
s.multiple = (selected_size > 1);
s.observe("change", function (evt) {
var filter_name = this.up('tr').getAttribute("data-filter-name");
Reporting.Filters.value_changed(filter_name);
});
});
$$('.filters-select[data-all-dependents]').each(function (dependency) {
dependency.observe("change", Reporting.Filters.activate_dependents);
});
});

@ -0,0 +1,208 @@
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Effect, Ajax, selectAllOptions, moveOptions, moveOptionUp, moveOptionDown */
Reporting.GroupBys = {
group_by_container_ids: function() {
var ids = $w('group_by_columns group_by_rows');
return ids.select(function (i) {
return $(i) !== null
});
},
sortable_options: function() {
return {
tag: 'span',
only: "drag_element",
overlap: 'horizontal',
constraint:'horizontal',
containment: Reporting.GroupBys.group_by_container_ids(),
dropOnEmpty: true,
hoverclass: 'drag_container_accept'
};
},
recreate_sortables: function() {
Reporting.GroupBys.group_by_container_ids().each(function(id) {
Sortable.create(id, Reporting.GroupBys.sortable_options());
});
},
initialize_drag_and_drop_areas: function() {
Reporting.GroupBys.recreate_sortables();
},
create_label: function(group_by, text) {
return new Element('label', {
'class': 'in_row group_by_label',
'for': group_by.identify(),
'id': group_by.identify() + '_label'
}).update(text);
},
create_remove_button: function(group_by) {
var remove_link, remove_icon;
remove_link = new Element('a', {
'class': 'group_by_remove in_row',
'id': group_by.identify() + '_remove',
'href': 'javascript:'
});
remove_icon = $('hidden_remove_img').clone();
remove_icon.removeAttribute('id');
remove_icon.removeAttribute('style');
if (Reporting._LA != undefined) {
remove_link.setAttribute('title', Reporting._LA["REMOVE"] + ' ' + group_by.down('label').innerHTML);
remove_icon.setAttribute('alt', Reporting._LA["REMOVE"] + ' ' + group_by.down('label').innerHTML);
}
remove_link.observe('click', function(e) {
Reporting.GroupBys.remove_element_event_action(e, group_by, remove_link)
});
remove_link.observe('keypress', function(e) {
/* keyCode 32: Space */
if (e.keyCode == 32) {
e.preventDefault();
Reporting.GroupBys.remove_element_event_action(e, group_by, remove_link)
}
});
remove_link.appendChild(remove_icon);
return remove_link;
},
remove_element_event_action: function(event, group_by, button) {
var node;
if (node = group_by.next('span')) {
node = node.down('a');
if (node) {
node.focus();
}
}
else if (node = group_by.next('select')) {
node.focus();
}
Reporting.GroupBys.remove_group_by(button.up('.group_by_element'));
},
create_arrow: function(group_by, position) {
return new Element('span', {
'class': 'arrow in_row arrow_' + position,
'id': group_by.identify() + '_arrow_' + position
});
},
create_group_by: function(field, caption) {
var group_by, label, right_arrow, left_arrow, remove_button;
group_by = new Element('span', {
'class': 'in_row drag_element group_by_element',
'data-group-by': field
});
group_by.identify(); // give it a unique id
left_arrow = Reporting.GroupBys.create_arrow(group_by, 'left');
group_by.appendChild(left_arrow);
label = Reporting.GroupBys.create_label(group_by, caption);
Reporting.GroupBys.init_group_by_hover_effects([group_by, label]);
group_by.appendChild(label);
remove_button = Reporting.GroupBys.create_remove_button(group_by);
group_by.appendChild(remove_button);
right_arrow = Reporting.GroupBys.create_arrow(group_by, 'right');
group_by.appendChild(right_arrow);
return group_by;
},
// on mouse_over of a group_by or it's label, change the color of the group_by
// also change the color of the arrows
init_group_by_hover_effects: function(elements) {
elements.each(function(element) {
['mouseover', 'mouseout'].each(function(event_type) {
element.observe(event_type, function(event) {
Reporting.GroupBys.group_by_hover_effect(event, event_type == 'mouseover');
});
});
});
},
group_by_hover_effect: function(event, do_hover) {
var group_by = $(Event.element(event));
// we possibly hit a tag inside the group_by, so go search the group_by then
if (!group_by.hasClassName('group_by_element')) {
group_by = group_by.up('.group_by_element');
}
if (group_by !== null) {
Reporting.GroupBys.group_by_hover(group_by, do_hover);
}
},
group_by_hover: function(group_by, state) {
if (state) {
group_by.childElements().each(function(e) { e.addClassName('hover'); });
} else {
group_by.childElements().each(function(e) { e.removeClassName('hover'); });
}
},
// This is whether it is possible to add a new group if <<field>> through the
// add-group-by select-box or not.
adding_group_by_enabled: function(field, state) {
$w('add_group_by_columns add_group_by_rows').each(function(container_id) {
Reporting.Filters.select_option_enabled($(container_id), field, state);
});
},
remove_group_by: function(group_by) {
Reporting.GroupBys.adding_group_by_enabled(group_by.readAttribute('data-group-by'), true);
group_by.remove();
},
add_group_by_from_select: function(select) {
var field, caption, container, selected_option;
field = $(select).getValue();
container = select.up('.drag_container');
selected_option = select.select("[value='" + field + "']").first();
caption = selected_option.readAttribute('data-label');
Reporting.GroupBys.add_group_by(field, caption, container);
select.select("[value='']").first().selected = true;
},
add_group_by: function(field, caption, container) {
var group_by, add_groups_select_box;
add_groups_select_box = container.select('select').first();
group_by = Reporting.GroupBys.create_group_by(field, caption);
add_groups_select_box.insert({ before: group_by });
Reporting.GroupBys.adding_group_by_enabled(field, false);
Reporting.GroupBys.recreate_sortables();
},
clear: function() {
Reporting.GroupBys.visible_group_bys().each(function (group_by) {
Reporting.GroupBys.remove_group_by(group_by);
});
},
visible_group_bys: function() {
return Reporting.GroupBys.group_by_container_ids().collect(function (container) {
return $(container).select('[data-group-by]')
}).flatten();
},
exists: function(group_by_name) {
return Reporting.GroupBys.visible_group_bys().any(function (grp) {
return grp.getAttribute('data-group-by') == group_by_name;
});
}
};
Reporting.onload(function () {
Reporting.GroupBys.initialize_drag_and_drop_areas();
[$('add_group_by_rows'), $('add_group_by_columns')].each(function (select) {
if (select !== null) {
select.observe("change", function () {
if (!(Reporting.GroupBys.exists(this.value))) {
Reporting.GroupBys.add_group_by_from_select(this);
};
});
}
});
});

@ -0,0 +1,3 @@
Reporting._LA = {};
Reporting._LA["REMOVE"] = "Lösche";
Reporting._LA["RESPONSE_ERROR"] = "Bei der Bearbeitung der Anfrage ist ein Fehler aufgetreten.";

@ -0,0 +1,3 @@
Reporting._LA = {};
Reporting._LA["REMOVE"] = "Delete";
Reporting._LA["RESPONSE_ERROR"] = "There was an error handling the query.";

@ -0,0 +1,49 @@
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Effect, Ajax */
Reporting.Progress = {
abort: function () {
if (window.progressbar !== undefined && window.progressbar !== null) {
window.progressbar.stop();
}
},
replace_with_bar: function (element) {
var parent = element.up();
var size = parseInt(element.getAttribute('data-query-size'), 10) || 500;
element.remove();
window.progressbar = Reporting.Progress.add_bar_to_parent(parent);
// Speed determined through laborous experimentation!
window.progressbar.options.interval = (size * (Math.log(size))) / 100000;
window.progressbar.start();
},
add_bar_to_parent: function (parent) {
parent.appendChild(new Element('div', {
'id': 'progressbar_container',
'class': 'progressbar_container'
}));
return new Control.ProgressBar('progressbar_container');
},
confirm_question: function () {
var bar = $('progressbar');
if (bar !== null && bar !== undefined) {
var size = bar.getAttribute('data-size');
var question = bar.getAttribute('data-translation');
if (confirm(question)) {
var target = bar.getAttribute("data-target");
bar.up().show();
Reporting.Progress.replace_with_bar(bar);
Reporting.Controls.send_settings_data(target, Reporting.Controls.update_result_table);
} else {
bar.toggle();
}
}
}
};
Reporting.onload(function () {
Reporting.Progress.confirm_question();
});

@ -0,0 +1,116 @@
/**
* @author Ryan Johnson <http://syntacticx.com/>
* @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
* @package LivePipe UI
* @license MIT
* @url http://livepipe.net/control/progressbar
* @require prototype.js, livepipe.js
*/
/*global document, Prototype, Ajax, Class, PeriodicalExecuter, $, $A, Control */
if (typeof(Prototype) === "undefined") {
throw "Control.ProgressBar requires Prototype to be loaded.";
}
if (typeof(Event) === "undefined") {
throw "Control.ProgressBar requires Event to be loaded.";
}
if (typeof(Control) === "undefined") {
if (window.console && window.console.log) {
window.console.log("Control.ProgressBar requires Prototype ~= 1.7");
}
} else {
Control.ProgressBar = Class.create({
initialize: function(container, options) {
this.progress = 0;
this.executer = false;
this.active = false;
this.poller = false;
this.container = $(container);
this.containerWidth = this.container.getDimensions().width;
this.progressContainer = $(document.createElement('div'));
this.progressContainer.setStyle({
width: this.containerWidth + 'px',
height: '100%',
position: 'absolute',
top: '0px',
right: '0px'
});
this.container.appendChild(this.progressContainer);
this.options = {
afterChange: Prototype.emptyFunction,
interval: 0.25,
step: 1,
classNames: {
active: 'progress_bar_active',
inactive: 'progress_bar_inactive'
}
};
Object.extend(this.options, options || {});
this.container.addClassName(this.options.classNames.inactive);
this.active = false;
},
setProgress: function (value) {
this.progress = value;
this.draw();
if (this.progress >= 100) {
this.stop(false);
}
this.notify('afterChange', this.progress, this.active);
},
poll: function (url, interval, ajaxOptions) {
// Extend the passed ajax options and success callback with our own.
ajaxOptions = ajaxOptions || {};
var success = ajaxOptions.onSuccess || Prototype.emptyFunction;
ajaxOptions.onSuccess = success.wrap(function (callOriginal, request) {
this.setProgress(parseInt(request.responseText, 10));
if (!this.active) {
this.poller.stop();
}
callOriginal(request);
}).bind(this);
this.active = true;
this.poller = new PeriodicalExecuter(function () {
var a = new Ajax.Request(url, ajaxOptions);
}.bindAsEventListener(this), interval || 3);
},
start: function () {
this.active = true;
this.container.removeClassName(this.options.classNames.inactive);
this.container.addClassName(this.options.classNames.active);
this.executer = new PeriodicalExecuter(this.step.bind(this, this.options.step), this.options.interval);
},
stop: function (reset) {
this.active = false;
if (this.executer) {
this.executer.stop();
}
this.container.removeClassName(this.options.classNames.active);
this.container.addClassName(this.options.classNames.inactive);
if (typeof reset === 'undefined' || reset === true) {
this.reset();
}
},
step: function (amount) {
this.active = true;
this.setProgress(Math.min(100, this.progress + amount));
},
reset: function () {
this.active = false;
this.setProgress(0);
},
draw: function () {
this.progressContainer.setStyle({
width: (100 - this.progress) + "%"
});
},
notify: function (event_name) {
if (this.options[event_name]) {
return [this.options[event_name].apply(this.options[event_name], $A(arguments).slice(1))];
}
}
});
Event.extend(Control.ProgressBar);
}

@ -0,0 +1,90 @@
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Effect, Ajax */
Reporting.RestoreQuery = {
select_operator: function (field, operator) {
var select, i;
select = $("operators_" + field);
if (select === null) {
return; // there is no such operator select field
}
for (i = 0; i < select.options.length; i += 1) {
if (select.options[i].value === operator) {
select.selectedIndex = i;
break;
}
}
Reporting.Filters.operator_changed(field, select);
},
disable_select_option: function (select, field) {
for (var i = 0; i < select.options.length; i += 1) {
if (select.options[i].value === field) {
select.options[i].disabled = true;
break;
}
}
},
restore_dependent_filters: function(filter_name) {
$$("tr.filter[data-filter-name=" + filter_name + "] select.filter-value").each(function(selectBox) {
var activateNext = function(dependent) {
if (!dependent) return;
Reporting.RestoreQuery.restore_dependent_filters(dependent);
};
if (selectBox.hasAttribute('data-initially-selected')) {
var selected_values = selectBox.readAttribute('data-initially-selected').replace(/'/g, '"').evalJSON(true);
Reporting.Filters.select_values(selectBox, selected_values);
Reporting.Filters.value_changed(filter_name);
}
if (selectBox.getValue() !== '<<inactive>>') {
Reporting.Filters.activate_dependents(selectBox, activateNext);
}
});
},
restore_filters: function () {
var deps = $$('.filters-select.filter-value').each(function(select) {
var tr = select.up('tr');
if (tr.visible()) {
var filter = tr.readAttribute('data-filter-name');
var dependent = select.readAttribute('data-dependent');
if (filter && dependent) {
Reporting.Filters.remove_filter(filter, false);
}
}
});
$$("tr[data-selected=true]").each(function (e) {
var select = e.down(".filter_values select");
if (select && select.hasAttribute("data-dependent")) return;
var filter_name = e.getAttribute("data-filter-name");
var on_complete = function() {
Reporting.RestoreQuery.restore_dependent_filters(filter_name);
};
Reporting.Filters.add_filter(filter_name, false, on_complete);
});
},
restore_group_bys: function () {
Reporting.GroupBys.group_by_container_ids().each(function(id) {
var container, selected_groups;
container = $(id);
if (container.hasAttribute('data-initially-selected')) {
selected_groups = container.readAttribute('data-initially-selected').replace(/'/g, '"').evalJSON(true);
selected_groups.each(function(group_and_label) {
var group, label;
group = group_and_label[0];
label = group_and_label[1];
Reporting.GroupBys.add_group_by(group, label, container);
});
}
});
}
};
Reporting.onload(function () {
Reporting.RestoreQuery.restore_group_bys();
Reporting.RestoreQuery.restore_filters();
});

@ -0,0 +1,306 @@
/*
Table sorting script by Joost de Valk, check it out at http://www.joostdevalk.nl/code/sortable-table/.
Based on a script from http://www.kryogenix.org/code/browser/sorttable/.
Distributed under the MIT license: http://www.kryogenix.org/code/browser/licence.html .
Copyright (c) 1997-2007 Stuart Langridge, Joost de Valk.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Version 1.5.7
*/
/* You can change these values */
var europeandate = true;
var alternate_row_colors = true;
/* Don't change anything below this unless you know what you're doing */
// addEvent(window, "load", sortables_init);
var SORT_COLUMN_INDEX;
var thead = false;
function alternate(table) {
// Take object table and get all it's tbodies.
var i, j, tableBodies, tableRows;
tableBodies = table.getElementsByTagName("tbody");
// Loop through these tbodies
for (i = 0; i < tableBodies.length; i += 1) {
// Take the tbody, and get all it's rows
tableRows = tableBodies[i].getElementsByTagName("tr");
// Loop through these rows
// Start at 1 because we want to leave the heading row untouched
for (j = 0; j < tableRows.length; j += 1) {
// Check if j is even, and apply classes for both possible results
if ((j % 2) === 0) {
if (tableRows[j].className.indexOf('odd') !== -1) {
tableRows[j].className = tableRows[j].className.replace('odd', 'even');
} else {
if (tableRows[j].className.indexOf('even') === -1) {
tableRows[j].className += " even";
}
}
} else {
if (tableRows[j].className.indexOf('even') !== -1) {
tableRows[j].className = tableRows[j].className.replace('even', 'odd');
} else {
if (tableRows[j].className.indexOf('odd') === -1) {
tableRows[j].className += " odd";
}
}
}
}
}
}
function ts_getInnerText(el) {
if (typeof el === "string") {
return el;
}
if (typeof el === "undefined") {
return el;
}
if (el.innerText) {
return el.innerText;
} //Not needed but it is faster
var str, cs, l, i;
str = "";
cs = el.childNodes;
l = cs.length;
for (i = 0; i < l; i += 1) {
switch (cs[i].nodeType) {
case 1: //ELEMENT_NODE
str += ts_getInnerText(cs[i]);
break;
case 3: //TEXT_NODE
str += cs[i].nodeValue;
break;
}
}
return str;
}
function ts_makeSortable(t) {
var firstRow, i, cell, txt;
if (t.rows && t.rows.length > 0) {
if (t.tHead && t.tHead.rows.length > 0) {
firstRow = t.tHead.rows[t.tHead.rows.length - 1];
thead = true;
} else {
firstRow = t.rows[0];
}
}
if (!firstRow) {
return;
}
// We have a first row: assume it's the header, and make its contents clickable links
for (i = 0; i < firstRow.cells.length; i += 1) {
cell = firstRow.cells[i];
txt = ts_getInnerText(cell);
if (cell.className !== "unsortable" && cell.className.indexOf("unsortable") === -1) {
cell.innerHTML = '<a href="#" class="sortheader sort" onclick="ts_resortTable(this, ' +
i +
');return false;">' +
txt +
'</a>';
}
}
if (alternate_row_colors) {
alternate(t);
}
}
function sortables_init() {
// Find table with id sortable-table and make them sortable
if (!document.getElementById) {
return;
}
var tbl = document.getElementById("sortable-table");
ts_makeSortable(tbl);
}
function getParent(el, pTagName) {
if (el === null) {
return null;
} else if (el.nodeType === 1 && el.tagName.toLowerCase() === pTagName.toLowerCase()) {
return el;
} else {
return getParent(el.parentNode, pTagName);
}
}
function ts_get_cell_data(a, idx) {
var acell, aa;
if ((typeof idx) === "undefined") {
acell = a.cells[SORT_COLUMN_INDEX];
} else {
acell = a.cells[idx];
}
if ((aa = acell.getAttribute("raw-data")) === null) {
aa = ts_getInnerText(acell).toLowerCase();
}
return aa;
}
function compare_numeric(a, b) {
var af, bf;
af = parseFloat(a);
af = (isNaN(af) ? 0 : af);
bf = parseFloat(b);
bf = (isNaN(bf) ? 0 : bf);
return af - bf;
}
function ts_sort_numeric(a, b) {
var cells = [ts_get_cell_data(a), ts_get_cell_data(b)];
return compare_numeric(cells[0], cells[1]);
}
function ts_sort_caseinsensitive(a, b) {
var cells = [ts_get_cell_data(a), ts_get_cell_data(b)];
if (cells[0] === cells[1]) {
return 0;
}
if (cells[0] < cells[1]) {
return -1;
}
return 1;
}
function trim(s) {
return s.replace(/^\s+|\s+$/g, "");
}
function ts_resortTable(lnk, clid) {
var td, column, t, first, itm, i, j, k, numeric_flag, all_sort_links, ci, firstRow, newRows, sortfn;
td = lnk.parentNode;
column = clid || td.cellIndex;
t = getParent(td, 'TABLE');
// Do not sort single a row
if (t.rows.length <= 1) {
return;
}
// Determine if all rows are equal
first = ts_get_cell_data(t.tBodies[0].rows[0], 0);
itm = first;
i = 0;
while (itm === first && i < t.tBodies[0].rows.length) {
itm = ts_get_cell_data(t.tBodies[0].rows[i], column);
itm = trim(itm);
if (itm.substr(0, 4) === "<!--" || itm.length === 0) {
itm = "";
}
i += 1;
}
if (itm === first) {
return;
}
// Determine the sort type. You can set numeric=true on the header to force numeric sorting
sortfn = ts_sort_caseinsensitive;
if (thead) {
if (itm.match(/-?\d+(?:\.\d+)?/)) {
sortfn = ts_sort_numeric; // Normal number
}
numeric_flag = t.tHead.rows[0].cells[column].getAttribute("numeric");
if (numeric_flag === "true") {
sortfn = ts_sort_numeric;
}
}
// Delete any other arrows there may be showing
all_sort_links = $$("a.sortheader.sort");
for (ci = 0; ci < all_sort_links.length; ci += 1) {
if (getParent(all_sort_links[ci], "table") === getParent(lnk, "table")) { // in the same table as us?
all_sort_links[ci].className = all_sort_links[ci].className.replace(" desc", "").replace(" asc", "");
}
}
// Do the sorting
SORT_COLUMN_INDEX = column;
firstRow = [];
newRows = [];
for (k = 0; k < t.tBodies.length; k += 1) {
for (i = 0; i < t.tBodies[k].rows[0].length; i += 1) {
firstRow[i] = t.tBodies[k].rows[0][i];
}
}
for (k = 0; k < t.tBodies.length; k += 1) {
if (!thead) {
// Skip the first row
for (j = 1; j < t.tBodies[k].rows.length; j += 1) {
newRows[j - 1] = t.tBodies[k].rows[j];
}
} else {
// Do NOT skip the first row
for (j = 0; j < t.tBodies[k].rows.length; j += 1) {
newRows[j] = t.tBodies[k].rows[j];
}
}
}
newRows.sort(sortfn);
if (lnk.getAttribute("sortdir") === 'down') {
lnk.setAttribute('sortdir', 'up');
lnk.className += " asc";
} else {
newRows.reverse();
lnk.setAttribute('sortdir', 'down');
lnk.className += " desc";
}
// We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
// don't do sortbottom rows
for (i = 0; i < newRows.length; i += 1) {
if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') === -1))) {
t.tBodies[0].appendChild(newRows[i]);
}
}
// do sortbottom rows only
for (i = 0; i < newRows.length; i += 1) {
if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') !== -1)) {
t.tBodies[0].appendChild(newRows[i]);
}
}
alternate(t);
}
function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+, NS6 and Mozilla
// By Scott Andrew
{
if (elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);
return true;
} else if (elm.attachEvent) {
var r = elm.attachEvent("on" + evType, fn);
return r;
} else {
alert("Handler could not be removed");
}
}
function clean_num(str) {
str = str.replace(/^[^\-?\d]+/, "");
str.replace(/(\d),(\d)/g, "$1$2");
return str;
}

@ -0,0 +1,56 @@
.help {
margin-left: 5px;
margin-right: 5px;
}
.tooltip {
position: absolute;
margin-top: 3px;
margin-bottom: 3px;
padding: 3px;
width: 400px;
z-index: 256;
color: #000000;
border: 1px solid #000000;
background: #FFFFCC;
font: 12px Verdana, sans-serif;
text-align: left;
padding: -50px;
line-height: 16px;
font-size: 11px;
white-space: normal;
}
.filter-icon {
}
.filter-tip {
}
.group-by-icon {
float: right;
margin-right: 5px;
}
.group-by-tip {
margin-top: -300px;
margin-left: -475px;
}
.filter-legend-icon {
}
.filter-legend-tip {
margin-left: 10px;
}
.group_by-legend-icon {
}
.group_by-legend-tip {
margin-left: 10px;
}

@ -0,0 +1,619 @@
.cost_types {
padding-bottom: 3px;
}
.cost_types a.active {
color: #000;
font-weight: bold;
}
.report {
text-align: center;
border-collapse: collapse;
border: solid 1px #ccc !important;
width: auto !important;
}
.report td, .report th {
min-width: 90px;
white-space: nowrap;
}
.report td {
border: dotted 1px #ddd;
color: #666;
text-align: right;
padding-right: 5px;
}
.report tbody th, .report tbody td, .inner {
max-width: 300px;
white-space: normal !important;
}
.report td:hover {
color: #000;
outline: #ccc 1px solid;
outline-offset: 1px;
}
.report td.empty:hover {
outline: none;
}
.report th {
border: solid 1px #ccc;
background-color: #e3e3e3;
text-align: center;
}
.report .odd th.inner {
background-color: #e8e8e8;
}
.report .even th.inner {
background-color: #e3e3e3;
}
.report th.inner {
border: solid 1px #ccc;
background-color: #efefef;
text-align: right;
}
.report tr.even:hover .inner,
.report tr.even:hover .bottom,
.report tr.even:hover .empty,
.report tr.even:hover .right {
background-color: #f5f5c5 !important;
}
/* IE7 made me do it! */
.report tr.odd:hover .inner,
.report tr.odd:hover .bottom,
.report tr.odd:hover .empty,
.report tr.odd:hover .right {
background-color: #f5f5c5 !important;
}
.report .top {
border-top-style: solid;
border-top-color: #ccc;
/* border-top: 2px solid #ccc !important; */
}
.report .bottom {
border-bottom-style: solid;
border-bottom-color: #ccc;
/* border-bottom: 2px solid #ccc !important; */
}
.report td.penultimate {
border-right-style: solid;
}
.report thead .inner, .report tfoot .inner {
text-align: right;
padding-right: 5px;
}
.report .result {
font-size: 120%;
text-align: right;
}
#result-table {
margin-top: 10px !important;
}
.report thead tr:hover .inner, .report tfoot tr:hover .inner {
background-color: #efefef;
}
.report .left {
text-align: left !important;
padding-left: 5px;
}
.report .right {
text-align: right !important;
padding-right: 5px;
}
/* Details view*/
.detail-report td {
text-align: left;
vertical-align: top;
}
#query_form_content {
width: 916px;
}
#query_form fieldset.header_collapsible.collapsible {
padding-bottom: 10px;
}
/* Overwriting styling for headlines within the query. */
/* TODO: Font-size seems to be a bit odd. Needs some love. */
.new_report fieldset h3 {
font-size: 1.17em;
border: none;
}
.remove-box {
height: 20px;
width: 20px;
background: white;
float: right;
padding: 1px 0 0 0;
display: block;
margin-top: -5px;
margin-right: -2px;
}
.filter_rem {
color: transparent;
overflow: hidden;
cursor: pointer;
background: no-repeat center center transparent;
height: 18px;
width: 18px;
border-style: none;
display: block;
margin: 0 0 0 2px;
}
.icon-filter-rem {
background-image: url(../images/close.gif);
position: relative;
float: right;
padding: 0px;
}
/***** icons *****/
/*
We hide the original content of things with class 'icon' and disply an icon instead.
This css class is optimized for usage report breadcrumbs.
Hint: The content of the title attribute is shown as a tooltip if the underlying DOM element is an <a>.
*/
.breadcrumb_icon {
padding: 3px 5px 0 16px;
cursor: pointer;
background: no-repeat left center;
border-style: none;
display: inline-block;
margin-top: 0px;
margin-bottom: 0px;
}
.icon-edit {
background-image: url(../images/edit.png);
}
.icon-delete {
background-image: url(../images/delete.png);
}
#query-name-edit-button {
margin-left: 16px;
font-size: 12px;
}
.filter {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.inactive-filter {
background-color: #FCE29A !important;
}
.dependent-filter-label {
margin-left: 20px;
}
.filter_values {
white-space: nowrap;
}
.filter_radio_option {
padding-left: 5px;
padding-right: 5px;
}
#add_filter_block {
margin-top: 6px;
}
#add_filter_select {
margin-bottom: 10px;
}
fieldset#filters table tr.filter:hover {
background: #aaa;
}
fieldset#filters table tr.filter {
color: #000;
background: #ededed;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
/* Aligning filter elements at the top. */
fieldset#filters table td {
vertical-align: top;
border-spacing: 5px 5px;
border-color: white;
border-style: solid;
border-width: 2px 0px 0px;
padding: 5px 2px 5px 2px;
}
fieldset#filters table .no-border td {
border-style: none !important;
}
fieldset#filters table td > label {
left: 3px;
top: 3px;
position: relative;
}
/* ----- group by --- */
#group_by_area {
margin: 5px 0 10px 0;
}
.in_row {
float: left;
display: block;
list-style: none;
border-width: 0px;
}
.group_by_element {
margin-left: -15px;
cursor: move;
}
/* have #content here to overwrite line-heigth of other themes through being more specific*/
#content .group_by_label {
margin: 0px;
padding: 0px 18px 0 0;
min-width: 60px;
text-align: center;
white-space: nowrap;
font-weight: bold;
color: #fff;
background-color: #9A9A9A;
height: 22px;
line-height: 22px;
cursor: move;
}
.group_by_label.hover {
background-color: #009999 !important;
}
.group_by_remove {
background-color: #9A9A9A;
height: 7px;
width: 8px;
position: absolute;
top: 7px;
right: 21px;
cursor: pointer;
}
.group_by_remove.hover {
background-color: #009999 !important;
}
/* Overwrite normal h3 definition - a h-tag is needed for accessibility purposes */
h3.reporting_formatting {
font-weight:normal;
font-size: 13px;
margin:0px;
padding:0px;
color:#333;
border:0px;
}
/* have #content here to overwrite line-heigth of other themes through being more specific*/
#content .group_by_caption {
color: #FFFFFF;
background-color: #4B4B4B;
font-weight: bold;
padding: 0 7px;
margin: 0;
height: 22px;
line-height: 22px;
min-width: 55px;
}
.arrow {
height: 0;
width: 0;
border-style: solid;
border-width: 11px 11px 11px 7px;
}
.arrow_left {
border-color: #9A9A9A #9A9A9A #9A9A9A transparent;
}
.arrow_left.hover {
border-color: #009999 #009999 #009999 transparent !important;
}
.arrow_right {
border-color: transparent transparent transparent #9A9A9A;
}
.arrow_right.hover {
border-color: transparent transparent transparent #009999 !important;
}
.arrow_group_by_caption {
border-color: transparent transparent transparent #4B4B4B;
}
.drag_container {
padding: 0;
height: 22px;
margin-bottom: 1em;
background-color: #EEE;
}
.drag_container select {
margin-right: 3px;
float: right;
}
.drag_target {
min-height: 10px;
}
.drag_container_accept {
background-color: #F5F5C5;
}
/* -- end group-by -- */
td .drill_down, th .drill_down {
font-size: 8px;
display: block;
float: right;
font-weight: bold;
visibility: hidden;
}
td:hover .drill_down, th:hover .drill_down {
visibility: visible;
}
/*Buttons*/
.buttons .reporting_button {
background-color: #008BD0;
border: none;
cursor: pointer;
margin: 0px;
overflow: visible;
text-align: center;
white-space: nowrap;
-moz-border-radius: 3px;
border-radius: 3px;
padding: 4px;
}
.form_controls {
margin-top: 6px;
}
.form_controls > * {
margin: 0 5px 0 5px;
}
.buttons .reporting_button:hover {
background-color: #24B3E7;
}
.buttons .reporting_button * em {
color: white;
display: block;
font-style: normal;
font-weight: bold;
line-height: 17px;
}
.buttons .reporting_button > * {
display: inline-block;
margin: 0px;
}
.saved_queries .reporting_button {
float: left;
margin: 2px;
}
.buttons .button {
border: none;
cursor: pointer;
margin: 0px;
margin-right: 4px;
overflow: visible;
text-align: center;
white-space: nowrap;
-moz-border-radius: 3px;
border-radius: 3px;
padding: 4px;
}
.buttons .apply {
background-color: #008BD0;
}
.buttons .apply:hover {
background-color: #24B3E7;
}
.buttons .secondary {
background-color: #9a9a9a;
}
.buttons .secondary:hover {
background-color: #666666;
}
.buttons .button span em {
color: white;
display: block;
font-style: normal;
font-weight: bold;
line-height: 17px;
}
.buttons .button span {
display: inline-block;
margin: 3px;
}
.buttons .button-icon {
padding: 0px 5px 0 16px;
cursor: pointer;
background: no-repeat left center;
border-style: none;
display: inline-block;
margin-top: 0px;
margin-bottom: 0px;
}
.button .icon-save {
background-image: url(../images/disk.gif);
}
.button .icon-save-as {
background-image: url(../images/disks.gif);
}
.button .icon-delete {
background-image: url(../images/delete.gif);
}
.button .icon-clear {
background-image: url(../images/remove.gif);
}
div.button_form {
/* TODO IE Compatibility! */
background-color: white;
border: 1px solid gray;
-moz-border-radius: 3px;
border-radius: 3px;
left: 100px;
position: absolute;
padding: 5px;
}
div.button_form * input#name {
width: 200px
}
div.button_form * input[type="button"] {
float: right;
} br { clear: right; }
div.button_form p * {
margin: 2px;
}
/***** Save and Delete Reports ****/
#save_as_form, #delete_form {
z-index: 999;
}
#progressbar, .hidden {
display: none;
}
#progressbar_container {
width: 300px;
height: 16px;
border: 1px solid #ccc;
padding: 0;
margin: 0;
position: relative;
background-color: #9A9A9A;
background-repeat: repeat-x;
}
#progressbar_container div {
background-color:#fff;
}
/***** Ajax indicator ******/
#ajax-indicator {
font-family: Verdana, sans-serif;
position: absolute; /* fixed not supported by IE */
background-color:#eee;
border: 1px solid #bbb;
top:35%;
left:40%;
width:20%;
font-weight:bold;
text-align:center;
padding:0.6em;
z-index:100;
filter:alpha(opacity=50);
opacity: 0.5;
line-height: 10px;
font-size: 18px;
}
html>body #ajax-indicator { position: fixed; }
#ajax-indicator span {
background-position: 0% 40%;
background-repeat: no-repeat;
background-image: url(../images/loading.gif);
padding-left: 26px;
vertical-align: bottom;
}
/* Calendar Fixes */
div.calendar /* let calendar expand properly */
{
font-size: medium;
line-height: normal;
}
div.calendar table div { /* make sure the nested divs are large enough, too */
font-size: medium;
line-height: normal;
}
.calendar .combo .label, .calendar .combo .label-IEfix { /* set the proper size for the combo boxes with months and years */
font-size: 10px;
line-height: normal;
}
.calendar tbody .day { /* avoid jitter during quick mouse-overs over days */
border: 1px dotted transparent;
padding: 1px 3px 1px 1px;
}
/* Accessibility specific styles */
fieldset#filters table td > label.hidden-for-sighted, .hidden-for-sighted {
position:absolute;
left:-10000px;
top:auto;
width:1px;
height:1px;
overflow:hidden;
}

@ -0,0 +1,5 @@
module OpenProject
module ReportingEngine
require "open_project/reporting_engine/engine"
end
end

@ -0,0 +1,33 @@
require 'rails/engine'
module OpenProject::ReportingEngine
class Engine < ::Rails::Engine
engine_name :openproject_reportingengine
config.autoload_paths += Dir["#{config.root}/lib/"]
initializer 'reportingengine.precompile_assets' do
Rails.application.config.assets.precompile += %w(reportingengine.css reportingengine.js)
end
config.to_prepare do
require_dependency 'open_project/reporting_engine/patches'
require_dependency 'open_project/reporting_engine/patches/big_decimal_patch'
require_dependency 'open_project/reporting_engine/patches/to_date_patch'
end
config.after_initialize do
Redmine::Plugin.register :openproject_reportingengine do
name 'OpenProject ReportingEngine'
author 'Finn GmbH'
description 'A plugin for reports'
url 'https://github.com/finnlabs/openproject_reportingengine'
author_url 'http://www.finn.de/'
version OpenProject::ReportingEngine::VERSION
end
end
end
end

@ -7,13 +7,13 @@
# or Controllers will go to this module, first. The default behavior # or Controllers will go to this module, first. The default behavior
# is to pass translation work on to I18n.t() or I18n.l(), depending on # is to pass translation work on to I18n.t() or I18n.l(), depending on
# the type of arguments. # the type of arguments.
module ReportingHelper # module ReportingHelper
def l(*values) # def l(*values)
return values.first if values.size == 1 and values.first.respond_to? :to_str # return values.first if values.size == 1 and values.first.respond_to? :to_str
if [Date, DateTime, Time].include? values.first.class # if [Date, DateTime, Time].include? values.first.class
::I18n.l(values.first) # ::I18n.l(values.first)
else # else
::I18n.t(*values) # ::I18n.t(*values)
end # end
end # end
end # end

@ -0,0 +1,2 @@
module OpenProject::ReportingEngine::Patches
end

@ -1,4 +1,4 @@
module BigDecimalPatch module OpenProject::ReportingEngine::Patches::BigDecimalPatch
module BigDecimal module BigDecimal
::BigDecimal.send :include, self ::BigDecimal.send :include, self
def to_d; self end def to_d; self end
@ -13,7 +13,7 @@ module BigDecimalPatch
::String.send :include, self ::String.send :include, self
def to_d; ::BigDecimal.new(self) end def to_d; ::BigDecimal.new(self) end
end end
module NilClass module NilClass
::NilClass.send :include, self ::NilClass.send :include, self
def to_d; 0 end def to_d; 0 end

@ -1,6 +1,6 @@
require 'date' require 'date'
module ToDatePatch module OpenProject::ReportingEngine::Patches::ToDatePatch
module StringAndNil module StringAndNil
::String.send(:include, self) ::String.send(:include, self)
::NilClass.send(:include, self) ::NilClass.send(:include, self)
@ -14,7 +14,7 @@ module ToDatePatch
module DateAndTime module DateAndTime
::Date.send(:include, self) ::Date.send(:include, self)
::Time.send(:include, self) ::Time.send(:include, self)
def to_dateish def to_dateish
self self
end end

@ -1,4 +1,4 @@
require 'reporting_engine/engine' require_dependency 'open_project/reporting_engine/engine_module'
class Report < ActiveRecord::Base class Report < ActiveRecord::Base
extend ProactiveAutoloader extend ProactiveAutoloader

@ -2,8 +2,8 @@ require "set"
class Report::Filter class Report::Filter
extend ProactiveAutoloader extend ProactiveAutoloader
autoload :Base, 'reporting_engine/report/filter/base' autoload :Base, 'open_project/reporting_engine/report/filter/base'
autoload :NoFilter, 'reporting_engine/report/filter/no_filter' autoload :NoFilter, 'open_project/reporting_engine/report/filter/no_filter'
def self.all def self.all
@all ||= Set[] @all ||= Set[]

@ -3,10 +3,10 @@ require "set"
class Report::GroupBy class Report::GroupBy
extend ProactiveAutoloader extend ProactiveAutoloader
include Report::QueryUtils include Report::QueryUtils
autoload :Base, 'reporting_engine/report/group_by/base' autoload :Base, 'open_project/reporting_engine/report/group_by/base'
autoload :RubyAggregation, 'reporting_engine/report/group_by/ruby_aggregation' autoload :RubyAggregation, 'open_project/reporting_engine/report/group_by/ruby_aggregation'
autoload :SingletonValue, 'reporting_engine/report/group_by/singleton_value.rb' autoload :SingletonValue, 'open_project/reporting_engine/report/group_by/singleton_value.rb'
autoload :SqlAggregation, 'reporting_engine/report/group_by/sql_aggregation' autoload :SqlAggregation, 'open_project/reporting_engine/report/group_by/sql_aggregation'
def self.all def self.all
Set[engine::GroupBy::SingletonValue] Set[engine::GroupBy::SingletonValue]

@ -1,5 +1,5 @@
require 'set' require 'set'
require 'reporting_engine/report' require_dependency 'open_project/reporting_engine/report'
module Report::InheritedAttribute module Report::InheritedAttribute
include Report::QueryUtils include Report::QueryUtils

@ -0,0 +1,5 @@
module OpenProject
module ReportingEngine
VERSION = '0.0.1'
end
end

@ -1,5 +1,5 @@
require 'reporting_engine/reporting_helper' require_dependency 'open_project/reporting_engine/helpers/reporting_helper'
require 'reporting_engine/proactive_autoloader' require_dependency 'open_project/reporting_engine/proactive_autoloader'
class Widget < ActionView::Base class Widget < ActionView::Base

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save