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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sinatra/extensions/antiquity.rb +34 -0
  3. data/lib/sinatra/extensions/date.rb +49 -0
  4. data/lib/sinatra/extensions/init.rb +4 -0
  5. data/lib/sinatra/extensions/notification.rb +41 -0
  6. data/lib/sinatra/handlers/errors.rb +10 -3
  7. data/lib/sinatra/handlers/init.rb +3 -1
  8. data/lib/sinatra/handlers/notifications.rb +17 -28
  9. data/lib/sinatra/handlers/params.rb +26 -0
  10. data/lib/sinatra/handlers/reports.rb +28 -1
  11. data/lib/sinatra/helpers/alerts.rb +27 -0
  12. data/lib/sinatra/helpers/cas.rb +92 -0
  13. data/lib/sinatra/helpers/charts.rb +20 -4
  14. data/lib/sinatra/helpers/init.rb +4 -0
  15. data/lib/sinatra/helpers/inputs.rb +2 -2
  16. data/lib/sinatra/helpers/libraries.rb +2 -2
  17. data/lib/sinatra/helpers/mailer.rb +74 -0
  18. data/lib/sinatra/helpers/reports.rb +27 -0
  19. data/lib/sinatra/helpers/schedule.rb +68 -0
  20. data/lib/sinatra/helpers/subscriptions.rb +1 -1
  21. data/lib/sinatra/hexacta.rb +13 -5
  22. data/lib/sinatra/public/css/app.min.1.css +130 -12
  23. data/lib/sinatra/public/js/app.js +49 -42
  24. data/lib/sinatra/public/vendors/chartist/chartist-plugin-legend.js +237 -0
  25. data/lib/sinatra/views/alerts/empty.slim +7 -0
  26. data/lib/sinatra/views/alerts/error.slim +7 -0
  27. data/lib/sinatra/views/alerts/info.slim +7 -0
  28. data/lib/sinatra/views/alerts/warning.slim +7 -0
  29. data/lib/sinatra/views/charts/bar.slim +56 -0
  30. data/lib/sinatra/views/charts/gauge.slim +30 -0
  31. data/lib/sinatra/views/charts/{simple_line.slim → line.slim} +7 -8
  32. data/lib/sinatra/views/charts/pie.slim +34 -0
  33. data/lib/sinatra/views/charts/stacked_bar.slim +36 -0
  34. data/lib/sinatra/views/inputs/multiple_select.slim +4 -0
  35. data/lib/sinatra/views/inputs/select.slim +3 -0
  36. data/lib/sinatra/views/libraries/include_js_after.slim +0 -24
  37. data/lib/sinatra/views/libraries/include_js_before.slim +1 -0
  38. data/lib/sinatra/views/notifications.slim +37 -31
  39. data/lib/sinatra/views/notifications/form.slim +4 -4
  40. data/lib/sinatra/views/notifications/new.slim +4 -4
  41. data/lib/sinatra/views/notifications/widget.slim +9 -5
  42. data/lib/sinatra/views/reports/pick_date.slim +14 -0
  43. data/lib/sinatra/views/reports/pick_dates.slim +16 -0
  44. data/lib/sinatra/views/reports/pick_month.slim +14 -0
  45. data/lib/sinatra/views/reports/pick_year.slim +14 -0
  46. 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
- if (window.top.location.hash.indexOf("#") != -1) {
27
- $("a[href=" + window.top.location.hash +"]").trigger('click');
28
- }
26
+ $( ".paginator" ).clone().appendTo( "#content" );
29
27
 
30
- $("a[data-toggle='tab']").click(function() {
31
- window.top.location.hash = $(this).attr("href");
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 select, #form input").each(function() {
755
+ $("#form :input").each(function() {
765
756
  if ($(this).val() != null && $(this).val() != "") {
766
- if ($(this).is(':checkbox')) {
767
- if ($(this).is(':checked')) {
768
- filter_map[$(this)[0].name] = "on";
769
- } else {
770
- filter_map[$(this)[0].name] = "off";
771
- }
772
- } else {
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,7 @@
1
+ .lv-item.p-20.bgm-lightgray.m-b-5
2
+ .media
3
+ .pull-left
4
+ i.zmdi.zmdi-hc-3x.zmdi-alert-circle-o.c-gray
5
+ .media-body
6
+ .lv-title.c-gray #{title}
7
+ small.lv-small.c-gray #{message}
@@ -0,0 +1,7 @@
1
+ .lv-item.p-20.bgm-red.m-b-5
2
+ .media
3
+ .pull-left
4
+ i.zmdi.zmdi-hc-3x.zmdi-alert-octagon.c-white
5
+ .media-body
6
+ .lv-title.c-white #{title}
7
+ small.lv-small.c-white #{message}
@@ -0,0 +1,7 @@
1
+ .lv-item.p-20.bgm-blue.m-b-5
2
+ .media
3
+ .pull-left
4
+ i.zmdi.zmdi-hc-3x.zmdi-info.c-white
5
+ .media-body
6
+ .lv-title.c-white #{title}
7
+ small.lv-small.c-white #{message}
@@ -0,0 +1,7 @@
1
+ .lv-item.p-20.bgm-orange.m-b-5
2
+ .media
3
+ .pull-left
4
+ i.zmdi.zmdi-hc-3x.zmdi-alert-triangle.c-white
5
+ .media-body
6
+ .lv-title.c-white #{title}
7
+ small.lv-small.c-white #{message}
@@ -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
+ }