sinatra-hexacta 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sinatra/extensions/antiquity.rb +34 -0
- data/lib/sinatra/extensions/date.rb +49 -0
- data/lib/sinatra/extensions/init.rb +4 -0
- data/lib/sinatra/extensions/notification.rb +41 -0
- data/lib/sinatra/handlers/errors.rb +10 -3
- data/lib/sinatra/handlers/init.rb +3 -1
- data/lib/sinatra/handlers/notifications.rb +17 -28
- data/lib/sinatra/handlers/params.rb +26 -0
- data/lib/sinatra/handlers/reports.rb +28 -1
- data/lib/sinatra/helpers/alerts.rb +27 -0
- data/lib/sinatra/helpers/cas.rb +92 -0
- data/lib/sinatra/helpers/charts.rb +20 -4
- data/lib/sinatra/helpers/init.rb +4 -0
- data/lib/sinatra/helpers/inputs.rb +2 -2
- data/lib/sinatra/helpers/libraries.rb +2 -2
- data/lib/sinatra/helpers/mailer.rb +74 -0
- data/lib/sinatra/helpers/reports.rb +27 -0
- data/lib/sinatra/helpers/schedule.rb +68 -0
- data/lib/sinatra/helpers/subscriptions.rb +1 -1
- data/lib/sinatra/hexacta.rb +13 -5
- data/lib/sinatra/public/css/app.min.1.css +130 -12
- data/lib/sinatra/public/js/app.js +49 -42
- data/lib/sinatra/public/vendors/chartist/chartist-plugin-legend.js +237 -0
- data/lib/sinatra/views/alerts/empty.slim +7 -0
- data/lib/sinatra/views/alerts/error.slim +7 -0
- data/lib/sinatra/views/alerts/info.slim +7 -0
- data/lib/sinatra/views/alerts/warning.slim +7 -0
- data/lib/sinatra/views/charts/bar.slim +56 -0
- data/lib/sinatra/views/charts/gauge.slim +30 -0
- data/lib/sinatra/views/charts/{simple_line.slim → line.slim} +7 -8
- data/lib/sinatra/views/charts/pie.slim +34 -0
- data/lib/sinatra/views/charts/stacked_bar.slim +36 -0
- data/lib/sinatra/views/inputs/multiple_select.slim +4 -0
- data/lib/sinatra/views/inputs/select.slim +3 -0
- data/lib/sinatra/views/libraries/include_js_after.slim +0 -24
- data/lib/sinatra/views/libraries/include_js_before.slim +1 -0
- data/lib/sinatra/views/notifications.slim +37 -31
- data/lib/sinatra/views/notifications/form.slim +4 -4
- data/lib/sinatra/views/notifications/new.slim +4 -4
- data/lib/sinatra/views/notifications/widget.slim +9 -5
- data/lib/sinatra/views/reports/pick_date.slim +14 -0
- data/lib/sinatra/views/reports/pick_dates.slim +16 -0
- data/lib/sinatra/views/reports/pick_month.slim +14 -0
- data/lib/sinatra/views/reports/pick_year.slim +14 -0
- metadata +26 -3
@@ -23,12 +23,30 @@ $(document).ready(function(){
|
|
23
23
|
// Fix modal inside other components
|
24
24
|
$('.modal').appendTo("body");
|
25
25
|
|
26
|
-
|
27
|
-
$("a[href=" + window.top.location.hash +"]").trigger('click');
|
28
|
-
}
|
26
|
+
$( ".paginator" ).clone().appendTo( "#content" );
|
29
27
|
|
30
|
-
$(
|
31
|
-
|
28
|
+
$('form').on('submit', function(e) {
|
29
|
+
$(this).find(':input[required]').each(function() {
|
30
|
+
if ($(this).val() == "" || $(this).val() == null) {
|
31
|
+
$(this).parent().removeClass("success");
|
32
|
+
$(this).parent().addClass("error");
|
33
|
+
} else {
|
34
|
+
$(this).parent().removeClass("error");
|
35
|
+
$(this).parent().addClass("success");
|
36
|
+
}
|
37
|
+
});
|
38
|
+
if ($(this).find('.error').length == 0 ) {
|
39
|
+
$(this).find('#submit').attr('disabled','disabled');
|
40
|
+
}
|
41
|
+
});
|
42
|
+
$('.chosen[required]').on('change', function(change, deselected) { //selected OR deselected
|
43
|
+
if ($(this).val() == "" || $(this).val() == null) {
|
44
|
+
$(this).parent().removeClass("success");
|
45
|
+
$(this).parent().addClass("error");
|
46
|
+
} else {
|
47
|
+
$(this).parent().removeClass("error");
|
48
|
+
$(this).parent().addClass("success");
|
49
|
+
}
|
32
50
|
});
|
33
51
|
/* --------------------------------------------------------
|
34
52
|
Layout
|
@@ -704,33 +722,6 @@ function enableButtons() {
|
|
704
722
|
};
|
705
723
|
})( jQuery );
|
706
724
|
|
707
|
-
/*
|
708
|
-
* Bootstrap Growl - Notifications popups
|
709
|
-
*/
|
710
|
-
function notify(message, type){
|
711
|
-
$('[data-growl="container"]').find('[data-growl="dismiss"]').trigger('click');
|
712
|
-
$.growl({
|
713
|
-
message: message
|
714
|
-
},{
|
715
|
-
type: type,
|
716
|
-
allow_dismiss: false,
|
717
|
-
label: 'Cancel',
|
718
|
-
className: 'btn-xs btn-inverse growl-animated',
|
719
|
-
placement: {
|
720
|
-
from: 'bottom',
|
721
|
-
align: 'left'
|
722
|
-
},
|
723
|
-
delay: 5000,
|
724
|
-
animate: {
|
725
|
-
enter: 'animated fadeInUp',
|
726
|
-
exit: 'animated fadeOutDown'
|
727
|
-
},
|
728
|
-
offset: {
|
729
|
-
x: 0,
|
730
|
-
y: 0
|
731
|
-
}
|
732
|
-
});
|
733
|
-
};
|
734
725
|
|
735
726
|
function encodeQueryData(data)
|
736
727
|
{
|
@@ -761,27 +752,43 @@ function encodeQueryData(data)
|
|
761
752
|
|
762
753
|
function buildFilterMap(offset) {
|
763
754
|
filter_map = {};
|
764
|
-
$("#form
|
755
|
+
$("#form :input").each(function() {
|
765
756
|
if ($(this).val() != null && $(this).val() != "") {
|
766
|
-
if ($(this).
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
757
|
+
if ($(this)[0].name != "") {
|
758
|
+
filter_map[$(this)[0].name] = $(this).val();
|
759
|
+
}
|
760
|
+
}
|
761
|
+
});
|
762
|
+
$("#form input[type=radio]").each(function() {
|
763
|
+
if ($(this).val() != null && $(this).val() != "") {
|
764
|
+
if ($(this).is(':checked')) {
|
773
765
|
filter_map[$(this)[0].name] = $(this).val();
|
774
766
|
}
|
775
767
|
}
|
776
768
|
});
|
777
769
|
if (offset != null) {
|
778
770
|
filter_map["offset"] = offset;
|
779
|
-
} else {
|
780
|
-
filter_map["offset"] = filter_map["offset"] - 1;
|
781
771
|
}
|
782
772
|
return filter_map;
|
783
773
|
}
|
784
774
|
|
775
|
+
function advance_search(url,offset,format) {
|
776
|
+
filter_map = buildFilterMap(offset);
|
777
|
+
filter_map["format"] = format;
|
778
|
+
if (format != 'xls') {
|
779
|
+
window.location.href = url + "?" + encodeQueryData(filter_map);
|
780
|
+
} else {
|
781
|
+
window.open(
|
782
|
+
url + "?" + encodeQueryData(filter_map),
|
783
|
+
'_blank' // <- This is what makes it open in a new window.
|
784
|
+
);
|
785
|
+
}
|
786
|
+
};
|
787
|
+
|
788
|
+
$(document).ready(function(){
|
789
|
+
$( ".paginator" ).clone().appendTo( "#content" );
|
790
|
+
});
|
791
|
+
|
785
792
|
function read_notify(id,url) {
|
786
793
|
$.ajax({
|
787
794
|
url: '/notifications/' + id,
|
@@ -0,0 +1,237 @@
|
|
1
|
+
(function (root, factory) {
|
2
|
+
if (typeof define === 'function' && define.amd) {
|
3
|
+
// AMD. Register as an anonymous module.
|
4
|
+
define(['chartist'], function (chartist) {
|
5
|
+
return (root.returnExportsGlobal = factory(chartist));
|
6
|
+
});
|
7
|
+
} else if (typeof exports === 'object') {
|
8
|
+
// Node. Does not work with strict CommonJS, but
|
9
|
+
// only CommonJS-like enviroments that support module.exports,
|
10
|
+
// like Node.
|
11
|
+
module.exports = factory(require('chartist'));
|
12
|
+
} else {
|
13
|
+
root['Chartist.plugins.legend'] = factory(root.Chartist);
|
14
|
+
}
|
15
|
+
}(this, function (Chartist) {
|
16
|
+
/**
|
17
|
+
* This Chartist plugin creates a legend to show next to the chart.
|
18
|
+
*
|
19
|
+
*/
|
20
|
+
'use strict';
|
21
|
+
|
22
|
+
var defaultOptions = {
|
23
|
+
className: '',
|
24
|
+
classNames: false,
|
25
|
+
removeAll: false,
|
26
|
+
legendNames: false,
|
27
|
+
clickable: true,
|
28
|
+
onClick: null,
|
29
|
+
position: 'top'
|
30
|
+
};
|
31
|
+
|
32
|
+
Chartist.plugins = Chartist.plugins || {};
|
33
|
+
|
34
|
+
Chartist.plugins.legend = function (options) {
|
35
|
+
|
36
|
+
// Catch invalid options
|
37
|
+
if (options && options.position) {
|
38
|
+
if (!(options.position === 'top' || options.position === 'bottom' || options.position instanceof HTMLElement)) {
|
39
|
+
throw Error('The position you entered is not a valid position');
|
40
|
+
}
|
41
|
+
if (options.position instanceof HTMLElement) {
|
42
|
+
// Detatch DOM element from options object, because Chartist.extend
|
43
|
+
// currently chokes on circular references present in HTMLElements
|
44
|
+
var cachedDOMPosition = options.position;
|
45
|
+
delete options.position;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
options = Chartist.extend({}, defaultOptions, options);
|
50
|
+
|
51
|
+
if (cachedDOMPosition) {
|
52
|
+
// Reattatch the DOM Element position if it was removed before
|
53
|
+
options.position = cachedDOMPosition
|
54
|
+
}
|
55
|
+
|
56
|
+
return function legend(chart) {
|
57
|
+
|
58
|
+
function removeLegendElement() {
|
59
|
+
var legendElement = chart.container.querySelector('.ct-legend');
|
60
|
+
if (legendElement) {
|
61
|
+
legendElement.parentNode.removeChild(legendElement);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
// Set a unique className for each series so that when a series is removed,
|
66
|
+
// the other series still have the same color.
|
67
|
+
function setSeriesClassNames() {
|
68
|
+
chart.data.series = chart.data.series.map(function (series, seriesIndex) {
|
69
|
+
if (typeof series !== 'object') {
|
70
|
+
series = {
|
71
|
+
value: series
|
72
|
+
};
|
73
|
+
}
|
74
|
+
series.className = series.className || chart.options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex);
|
75
|
+
return series;
|
76
|
+
});
|
77
|
+
}
|
78
|
+
|
79
|
+
function createLegendElement() {
|
80
|
+
var legendElement = document.createElement('ul');
|
81
|
+
legendElement.className = 'ct-legend';
|
82
|
+
if (chart instanceof Chartist.Pie) {
|
83
|
+
legendElement.classList.add('ct-legend-inside');
|
84
|
+
}
|
85
|
+
if (typeof options.className === 'string' && options.className.length > 0) {
|
86
|
+
legendElement.classList.add(options.className);
|
87
|
+
}
|
88
|
+
if (chart.options.width) {
|
89
|
+
legendElement.style.cssText = 'width: ' + chart.options.width + 'px;margin: 0 auto;';
|
90
|
+
}
|
91
|
+
return legendElement;
|
92
|
+
}
|
93
|
+
|
94
|
+
// Get the right array to use for generating the legend.
|
95
|
+
function getLegendNames(useLabels) {
|
96
|
+
return options.legendNames || (useLabels ? chart.data.labels : chart.data.series);
|
97
|
+
}
|
98
|
+
|
99
|
+
// Initialize the array that associates series with legends.
|
100
|
+
// -1 indicates that there is no legend associated with it.
|
101
|
+
function initSeriesMetadata(useLabels) {
|
102
|
+
var seriesMetadata = new Array(chart.data.series.length);
|
103
|
+
for (var i = 0; i < chart.data.series.length; i++) {
|
104
|
+
seriesMetadata[i] = {
|
105
|
+
data: chart.data.series[i],
|
106
|
+
label: useLabels ? chart.data.labels[i] : null,
|
107
|
+
legend: -1
|
108
|
+
};
|
109
|
+
}
|
110
|
+
return seriesMetadata;
|
111
|
+
}
|
112
|
+
|
113
|
+
function createNameElement(i, legendText, classNamesViable) {
|
114
|
+
var li = document.createElement('li');
|
115
|
+
li.classList.add('ct-series-' + i);
|
116
|
+
// Append specific class to a legend element, if viable classes are given
|
117
|
+
if (classNamesViable) {
|
118
|
+
li.classList.add(options.classNames[i]);
|
119
|
+
}
|
120
|
+
li.setAttribute('data-legend', i);
|
121
|
+
li.textContent = legendText;
|
122
|
+
return li;
|
123
|
+
}
|
124
|
+
|
125
|
+
// Append the legend element to the DOM
|
126
|
+
function appendLegendToDOM(legendElement) {
|
127
|
+
if (!(options.position instanceof HTMLElement)) {
|
128
|
+
switch (options.position) {
|
129
|
+
case 'top':
|
130
|
+
chart.container.insertBefore(legendElement, chart.container.childNodes[0]);
|
131
|
+
break;
|
132
|
+
|
133
|
+
case 'bottom':
|
134
|
+
chart.container.insertBefore(legendElement, null);
|
135
|
+
break;
|
136
|
+
}
|
137
|
+
} else {
|
138
|
+
// Appends the legend element as the last child of a given HTMLElement
|
139
|
+
options.position.insertBefore(legendElement, null);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
function addClickHandler(legendElement, legends, seriesMetadata, useLabels) {
|
144
|
+
legendElement.addEventListener('click', function(e) {
|
145
|
+
var li = e.target;
|
146
|
+
if (li.parentNode !== legendElement || !li.hasAttribute('data-legend'))
|
147
|
+
return;
|
148
|
+
e.preventDefault();
|
149
|
+
|
150
|
+
var legendIndex = parseInt(li.getAttribute('data-legend'));
|
151
|
+
var legend = legends[legendIndex];
|
152
|
+
|
153
|
+
if (!legend.active) {
|
154
|
+
legend.active = true;
|
155
|
+
li.classList.remove('inactive');
|
156
|
+
} else {
|
157
|
+
legend.active = false;
|
158
|
+
li.classList.add('inactive');
|
159
|
+
|
160
|
+
var activeCount = legends.filter(function(legend) { return legend.active; }).length;
|
161
|
+
if (!options.removeAll && activeCount == 0) {
|
162
|
+
// If we can't disable all series at the same time, let's
|
163
|
+
// reenable all of them:
|
164
|
+
for (var i = 0; i < legends.length; i++) {
|
165
|
+
legends[i].active = true;
|
166
|
+
legendElement.childNodes[i].classList.remove('inactive');
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
var newSeries = [];
|
172
|
+
var newLabels = [];
|
173
|
+
|
174
|
+
for (var i = 0; i < seriesMetadata.length; i++) {
|
175
|
+
if (seriesMetadata[i].legend != -1 && legends[seriesMetadata[i].legend].active) {
|
176
|
+
newSeries.push(seriesMetadata[i].data);
|
177
|
+
newLabels.push(seriesMetadata[i].label);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
chart.data.series = newSeries;
|
182
|
+
if (useLabels) {
|
183
|
+
chart.data.labels = newLabels;
|
184
|
+
}
|
185
|
+
|
186
|
+
chart.update();
|
187
|
+
|
188
|
+
if (options.onClick) {
|
189
|
+
options.onClick(chart, e);
|
190
|
+
}
|
191
|
+
});
|
192
|
+
}
|
193
|
+
|
194
|
+
removeLegendElement();
|
195
|
+
|
196
|
+
var legendElement = createLegendElement();
|
197
|
+
var useLabels = chart instanceof Chartist.Pie && chart.data.labels && chart.data.labels.length;
|
198
|
+
var legendNames = getLegendNames(useLabels);
|
199
|
+
var seriesMetadata = initSeriesMetadata(useLabels);
|
200
|
+
var legends = [];
|
201
|
+
|
202
|
+
// Check if given class names are viable to append to legends
|
203
|
+
var classNamesViable = Array.isArray(options.classNames) && options.classNames.length === legendNames.length;
|
204
|
+
|
205
|
+
// Loop through all legends to set each name in a list item.
|
206
|
+
legendNames.forEach(function (legend, i) {
|
207
|
+
var legendText = legend.name || legend;
|
208
|
+
var legendSeries = legend.series || [i];
|
209
|
+
|
210
|
+
var li = createNameElement(i, legendText, classNamesViable);
|
211
|
+
legendElement.appendChild(li);
|
212
|
+
|
213
|
+
legendSeries.forEach(function(seriesIndex) {
|
214
|
+
seriesMetadata[seriesIndex].legend = i;
|
215
|
+
});
|
216
|
+
|
217
|
+
legends.push({
|
218
|
+
text: legendText,
|
219
|
+
series: legendSeries,
|
220
|
+
active: true
|
221
|
+
});
|
222
|
+
});
|
223
|
+
|
224
|
+
chart.on('created', function (data) {
|
225
|
+
appendLegendToDOM(legendElement);
|
226
|
+
});
|
227
|
+
|
228
|
+
if (options.clickable) {
|
229
|
+
setSeriesClassNames();
|
230
|
+
addClickHandler(legendElement, legends, seriesMetadata, useLabels);
|
231
|
+
}
|
232
|
+
};
|
233
|
+
};
|
234
|
+
|
235
|
+
return Chartist.plugins.legend;
|
236
|
+
|
237
|
+
}));
|
@@ -0,0 +1,56 @@
|
|
1
|
+
.ct-chart.bar-chart id="#{id}"
|
2
|
+
|
3
|
+
.table-responsive.chart-table
|
4
|
+
table.table.table-striped
|
5
|
+
tbody
|
6
|
+
tr
|
7
|
+
-for label in labels
|
8
|
+
th #{label}
|
9
|
+
-for serie in series
|
10
|
+
tr
|
11
|
+
-for element in serie
|
12
|
+
td #{element}
|
13
|
+
|
14
|
+
|
15
|
+
javascript:
|
16
|
+
var labels = #{{labels}};
|
17
|
+
var series = #{{series}};
|
18
|
+
|
19
|
+
var options = {
|
20
|
+
seriesBarDistance: 30,
|
21
|
+
fullWidth: true,
|
22
|
+
chartPadding: {
|
23
|
+
right: 40
|
24
|
+
},
|
25
|
+
height: '300px',
|
26
|
+
showLabel: true,
|
27
|
+
plugins: [
|
28
|
+
Chartist.plugins.legend({
|
29
|
+
legendNames: #{{names}},
|
30
|
+
})
|
31
|
+
]
|
32
|
+
};
|
33
|
+
|
34
|
+
var responsiveOptions = [
|
35
|
+
['screen and (max-width: 640px)', {
|
36
|
+
seriesBarDistance: 5,
|
37
|
+
axisX: {
|
38
|
+
labelInterpolationFnc: function (value) {
|
39
|
+
return value[0];
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}]
|
43
|
+
];
|
44
|
+
|
45
|
+
new Chartist.Bar("##{id}", {
|
46
|
+
labels: labels,
|
47
|
+
series: series
|
48
|
+
},
|
49
|
+
options,
|
50
|
+
responsiveOptions
|
51
|
+
);
|
52
|
+
|
53
|
+
css:
|
54
|
+
##{{id}} .ct-bar {
|
55
|
+
stroke-width: #{{100/(labels.count*series.count)}}%
|
56
|
+
}
|