sinatra-hexacta 0.0.2 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/sinatra/extensions/antiquity.rb +34 -0
- data/lib/sinatra/extensions/date.rb +49 -0
- data/lib/sinatra/extensions/generalmail.rb +26 -0
- data/lib/sinatra/extensions/init.rb +8 -0
- data/lib/sinatra/extensions/mail.rb +35 -0
- data/lib/sinatra/extensions/mailbuilder.rb +38 -0
- data/lib/sinatra/extensions/mailsender.rb +88 -0
- data/lib/sinatra/extensions/notification.rb +44 -0
- data/lib/sinatra/handlers/errors.rb +11 -4
- 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 +21 -5
- data/lib/sinatra/helpers/init.rb +4 -0
- data/lib/sinatra/helpers/inputs.rb +3 -3
- data/lib/sinatra/helpers/libraries.rb +3 -3
- 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 +15 -9
- data/lib/sinatra/public/css/app.min.1.css +132 -6
- data/lib/sinatra/public/js/app.js +49 -42
- data/lib/sinatra/public/vendors/chartist/chartist-plugin-legend.js +237 -0
- data/lib/sinatra/public/vendors/typeahead.js/typeahead.bundle.min.js +1 -2
- 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 +30 -4
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Sinatra
|
3
|
+
module ParamsHandler
|
4
|
+
|
5
|
+
def enable_params
|
6
|
+
p "Enabling params handler..."
|
7
|
+
|
8
|
+
before "*" do
|
9
|
+
unless params.nil?
|
10
|
+
tmp = {}
|
11
|
+
for key in params.keys
|
12
|
+
value = params[key]
|
13
|
+
value = value.join(",").split(",") if value.respond_to? :join
|
14
|
+
tmp[key.to_sym] = value
|
15
|
+
end
|
16
|
+
@params.clear
|
17
|
+
@params = tmp
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
register ParamsHandler
|
26
|
+
end
|
@@ -1 +1,28 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
module Sinatra
|
3
|
+
module ReportHandler
|
4
|
+
extend Hexacta
|
5
|
+
|
6
|
+
def enable_reports
|
7
|
+
p "Enabling reports..."
|
8
|
+
before '/reports/*' do
|
9
|
+
error(403) if authenticated(User).permissions.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
get '/reports' do
|
13
|
+
slim :reports
|
14
|
+
end
|
15
|
+
|
16
|
+
get '/reports/:report_name' do |report_name|
|
17
|
+
date = Date.parse(params["date"]) unless params["date"].nil?
|
18
|
+
date ||= Date.today
|
19
|
+
headers "Content-Disposition" => "attachment;filename=#{report_name}.#{date}.xls",
|
20
|
+
"Content-Type" => "application/octet-stream"
|
21
|
+
slim "reports/#{report_name}".to_sym, locals: { :date => date }, :layout => false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
register ReportHandler
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Sinatra
|
3
|
+
module AlertHelper
|
4
|
+
extend Hexacta
|
5
|
+
|
6
|
+
def info_alert(option_hash)
|
7
|
+
slim "#{Hexacta::GEM_FILE_DIR}/alerts/info".to_sym, locals: option_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def empty_alert(option_hash)
|
11
|
+
slim "#{Hexacta::GEM_FILE_DIR}/alerts/empty".to_sym, locals: option_hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def warning_alert(option_hash)
|
15
|
+
slim "#{Hexacta::GEM_FILE_DIR}/alerts/warning".to_sym, locals: option_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def error_alert(option_hash)
|
19
|
+
slim "#{Hexacta::GEM_FILE_DIR}/alerts/error".to_sym, locals: option_hash
|
20
|
+
end
|
21
|
+
|
22
|
+
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/alerts")
|
23
|
+
copy_all_files("/lib/sinatra/views/alerts","/app/views/#{Hexacta::GEM_FILE_DIR}/alerts")
|
24
|
+
end
|
25
|
+
|
26
|
+
helpers AlertHelper
|
27
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_support/all' #bug in rubycas client requires this
|
2
|
+
require 'rubycas-client'
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
module CasHelper
|
6
|
+
|
7
|
+
CAS_CLIENT = CASClient::Client.new(:cas_base_url => ENV['CAS_BASE_URL'], :log => Logger.new(STDOUT), :ticket_store_config => {:storage_dir => ENV['TICKET_STORE_DIR']})
|
8
|
+
|
9
|
+
def need_authentication(request, session)
|
10
|
+
if session[:cas_ticket]
|
11
|
+
if request[:ticket] && session[:cas_ticket] != request[:ticket]
|
12
|
+
true
|
13
|
+
else
|
14
|
+
false
|
15
|
+
end
|
16
|
+
else
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_cas_login(request, session)
|
22
|
+
if request[:ticket] && request[:ticket] != session[:ticket]
|
23
|
+
|
24
|
+
service_url = read_service_url(request)
|
25
|
+
service_ticket = read_ticket(request[:ticket], service_url)
|
26
|
+
|
27
|
+
CAS_CLIENT.validate_service_ticket(service_ticket)
|
28
|
+
|
29
|
+
if service_ticket.success
|
30
|
+
session[:cas_ticket] = service_ticket.ticket
|
31
|
+
session[:cas_user] = service_ticket.user
|
32
|
+
else
|
33
|
+
redirect request.path_info
|
34
|
+
#raise "Service Ticket validation failed! #{st.failure_code} - #{st.failure_message}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def logged_in?(request, session)
|
41
|
+
session[:cas_ticket] && !session[:cas_ticket].empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def require_authorization(request, session)
|
45
|
+
if !logged_in?(request, session)
|
46
|
+
service_url = read_service_url(request)
|
47
|
+
url = CAS_CLIENT.add_service_to_login_url(service_url)
|
48
|
+
redirect url
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def authenticated(model)
|
53
|
+
raise 500 if session[:cas_user].nil? || session[:cas_user].empty?
|
54
|
+
model.find(:hxt_id => "#{session[:cas_user]}")
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def read_ticket(ticket_str, service_url)
|
59
|
+
return nil unless ticket_str and !ticket_str.empty?
|
60
|
+
|
61
|
+
if ticket_str =~ /^PT-/
|
62
|
+
CASClient::ProxyTicket.new(ticket_str, service_url)
|
63
|
+
else
|
64
|
+
CASClient::ServiceTicket.new(ticket_str, service_url)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_service_url(request)
|
69
|
+
service_url = url(request.path_info)
|
70
|
+
if request.GET
|
71
|
+
params = request.GET.dup
|
72
|
+
params.delete(:ticket)
|
73
|
+
if params
|
74
|
+
[service_url, Rack::Utils.build_nested_query(params)].join('?')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
return service_url
|
78
|
+
end
|
79
|
+
|
80
|
+
def logout_cas(request, session)
|
81
|
+
if logged_in?(request, session)
|
82
|
+
url = CAS_CLIENT.logout_url()
|
83
|
+
session.clear
|
84
|
+
str = request.referer
|
85
|
+
comeback = "=" + (str.include?("?")? str.slice(0..(str.index('?')-1)) : str) #Hack mal!
|
86
|
+
redirect url + (url.include?("?service")? "" : "?service") + comeback
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
helpers CasHelper
|
92
|
+
end
|
@@ -1,15 +1,31 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Sinatra
|
3
|
-
module
|
3
|
+
module ChartsHelper
|
4
4
|
extend Hexacta
|
5
5
|
|
6
|
-
def
|
7
|
-
slim "#{Hexacta::GEM_FILE_DIR}/charts/
|
6
|
+
def line_chart(option_hash)
|
7
|
+
slim "#{Hexacta::GEM_FILE_DIR}/charts/line".to_sym, locals: option_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def bar_chart(option_hash)
|
11
|
+
slim "#{Hexacta::GEM_FILE_DIR}/charts/bar".to_sym, locals: option_hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def pie_chart(option_hash)
|
15
|
+
slim "#{Hexacta::GEM_FILE_DIR}/charts/pie".to_sym, locals: option_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def gauge_chart(option_hash)
|
19
|
+
slim "#{Hexacta::GEM_FILE_DIR}/charts/gauge".to_sym, locals: option_hash
|
20
|
+
end
|
21
|
+
|
22
|
+
def stacked_bar_chart(option_hash)
|
23
|
+
slim "#{Hexacta::GEM_FILE_DIR}/charts/stacked_bar".to_sym, locals: option_hash
|
8
24
|
end
|
9
25
|
|
10
26
|
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/charts")
|
11
|
-
|
27
|
+
copy_all_files("/lib/sinatra/views/charts","/app/views/#{Hexacta::GEM_FILE_DIR}/charts")
|
12
28
|
end
|
13
29
|
|
14
|
-
helpers
|
30
|
+
helpers ChartsHelper
|
15
31
|
end
|
data/lib/sinatra/helpers/init.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Sinatra
|
3
|
-
module
|
3
|
+
module InputHelper
|
4
4
|
extend Hexacta
|
5
5
|
|
6
6
|
def date_input(option_hash)
|
@@ -40,8 +40,8 @@ module Sinatra
|
|
40
40
|
end
|
41
41
|
|
42
42
|
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/inputs")
|
43
|
-
|
43
|
+
copy_all_files("/lib/sinatra/views/inputs","/app/views/#{Hexacta::GEM_FILE_DIR}/inputs")
|
44
44
|
end
|
45
45
|
|
46
|
-
helpers
|
46
|
+
helpers InputHelper
|
47
47
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Sinatra
|
3
|
-
module
|
3
|
+
module LibrariesHelper
|
4
4
|
extend Hexacta
|
5
5
|
|
6
6
|
def include_css
|
@@ -18,8 +18,8 @@ module Sinatra
|
|
18
18
|
p "Setting up libraries directory..."
|
19
19
|
copy_dir_structure("/lib/sinatra/public","/app/public/#{Hexacta::GEM_FILE_DIR}")
|
20
20
|
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/libraries")
|
21
|
-
|
21
|
+
copy_all_files("/lib/sinatra/views/libraries","/app/views/#{Hexacta::GEM_FILE_DIR}/libraries")
|
22
22
|
end
|
23
23
|
|
24
|
-
helpers
|
24
|
+
helpers LibrariesHelper
|
25
25
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Sinatra
|
3
|
+
module ReportHelper
|
4
|
+
extend Hexacta
|
5
|
+
|
6
|
+
def pick_date_input(option_hash)
|
7
|
+
slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_date".to_sym, locals: option_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def pick_dates_input(option_hash)
|
11
|
+
slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_dates".to_sym, locals: option_hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def pick_month_input(option_hash)
|
15
|
+
slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_month".to_sym, locals: option_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
def pick_year_input(option_hash)
|
19
|
+
slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_year".to_sym, locals: option_hash
|
20
|
+
end
|
21
|
+
|
22
|
+
setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/reports")
|
23
|
+
copy_all_files("/lib/sinatra/views/reports","/app/views/#{Hexacta::GEM_FILE_DIR}/reports")
|
24
|
+
end
|
25
|
+
|
26
|
+
helpers ReportHelper
|
27
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
# encoding: utf-8
|
3
|
+
module Sinatra
|
4
|
+
module ScheduleHelper
|
5
|
+
|
6
|
+
@@scheduler = Rufus::Scheduler.new
|
7
|
+
|
8
|
+
def schedule_every(time)
|
9
|
+
@@scheduler.every time do
|
10
|
+
begin
|
11
|
+
file_path = "/tmp/schedule.lock";
|
12
|
+
f = File.open(file_path, "w+")
|
13
|
+
# if file was previosly locked then flock throw a exception
|
14
|
+
f.flock(File::LOCK_EX)
|
15
|
+
ten_minutes = 600
|
16
|
+
# if the process overcome ten minutes, the timeout api throw a exception
|
17
|
+
Timeout::timeout(ten_minutes) do
|
18
|
+
|
19
|
+
begin
|
20
|
+
yield
|
21
|
+
rescue StandardError => error
|
22
|
+
title = error.message.split(':')[0].gsub('#<','');
|
23
|
+
message = error.backtrace.join(',');
|
24
|
+
NotificationSender.instance.send_error(nil,title,message)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
ensure
|
29
|
+
unless f.nil?
|
30
|
+
f.flock(File::LOCK_UN)
|
31
|
+
f.close
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def schedule_at(cron_expression)
|
38
|
+
@@scheduler.cron cron_expression do
|
39
|
+
begin
|
40
|
+
file_path = "/tmp/schedule.lock";
|
41
|
+
f = File.open(file_path, "w+")
|
42
|
+
# if file was previosly locked then flock throw a exception
|
43
|
+
f.flock(File::LOCK_EX)
|
44
|
+
ten_minutes = 600
|
45
|
+
# if the process overcome ten minutes, the timeout api throw a exception
|
46
|
+
Timeout::timeout(ten_minutes) do
|
47
|
+
|
48
|
+
begin
|
49
|
+
yield
|
50
|
+
rescue error
|
51
|
+
title = error.message.split(':')[0].gsub('#<','');
|
52
|
+
message = error.backtrace.join(',');
|
53
|
+
NotificationSender.instance.send_error(nil,title,message)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
unless f.nil?
|
59
|
+
f.flock(File::LOCK_UN)
|
60
|
+
f.close
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
register ScheduleHelper
|
68
|
+
end
|
@@ -3,7 +3,6 @@ module Sinatra
|
|
3
3
|
module SubscriptionHelper
|
4
4
|
|
5
5
|
def notify_to(user,creator,title,message,label,link=nil)
|
6
|
-
#return if creator.id == user.id
|
7
6
|
notification = Notification.find_or_create(:user_id => user.id,
|
8
7
|
:creator_id => creator.id,
|
9
8
|
:title => title,
|
@@ -26,6 +25,7 @@ module Sinatra
|
|
26
25
|
|
27
26
|
def notify_error(creator,title,message)
|
28
27
|
Subscription.where(:label => 'error').all.each do |subscription|
|
28
|
+
creator = subscription.user if creator.nil?
|
29
29
|
notification = Notification.find(:user_id => subscription.user_id,
|
30
30
|
:creator_id => creator.id,
|
31
31
|
:title => title,
|
data/lib/sinatra/hexacta.rb
CHANGED
@@ -1,32 +1,38 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'sinatra/base'
|
3
3
|
require 'fileutils'
|
4
|
+
require 'sucker_punch'
|
5
|
+
require 'rufus-scheduler'
|
4
6
|
|
5
7
|
module Sinatra
|
8
|
+
|
6
9
|
module Hexacta
|
7
10
|
GEM_FILE_DIR = "sinatra-hexacta"
|
8
11
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
+
def gem_path
|
13
|
+
File.expand_path("../..",__dir__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def copy_file(original_path, link_path)
|
17
|
+
IO.copy_stream("#{gem_path}#{original_path}",link_path) unless File.exist?(link_path) && FileUtils.compare_file("#{gem_path}#{original_path}",link_path)
|
12
18
|
end
|
13
19
|
|
14
|
-
def
|
15
|
-
Dir.foreach("#{
|
16
|
-
|
20
|
+
def copy_all_files(original_path, link_path)
|
21
|
+
Dir.foreach("#{gem_path}#{original_path}") do |child|
|
22
|
+
copy_file("#{original_path}/#{child}","#{link_path}/#{child}") unless child == '.' || child == '..'
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def setup_dir(path)
|
21
|
-
FileUtils.mkdir_p path
|
27
|
+
FileUtils.mkdir_p path
|
22
28
|
end
|
23
29
|
|
24
30
|
def copy_dir_structure(original_path, destination_path)
|
25
|
-
FileUtils.
|
26
|
-
FileUtils.copy_entry("#{Gem.loaded_specs["sinatra-hexacta"].gem_dir}#{original_path}", destination_path)
|
31
|
+
FileUtils.copy_entry("#{gem_path}#{original_path}", destination_path)
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
36
|
require_relative 'helpers/init'
|
32
37
|
require_relative 'handlers/init'
|
38
|
+
require_relative 'extensions/init'
|
@@ -10550,10 +10550,6 @@ h6 small,
|
|
10550
10550
|
left: 0;
|
10551
10551
|
top: 0;
|
10552
10552
|
padding: 0 11px;
|
10553
|
-
transition: all .5s ease-out;
|
10554
|
-
-moz-transition: all .5s ease-out;
|
10555
|
-
-o-transition: all .5s ease-out;
|
10556
|
-
-webkit-transition: all .5s ease-out;
|
10557
10553
|
}
|
10558
10554
|
|
10559
10555
|
#header:not(.sidebar-toggled).header-up {
|
@@ -10594,8 +10590,8 @@ h6 small,
|
|
10594
10590
|
color: white;
|
10595
10591
|
}
|
10596
10592
|
|
10597
|
-
#header input[type="text"]::placeholder {
|
10598
|
-
|
10593
|
+
#header input[type="text"]::placeholder {
|
10594
|
+
color: rgba(255,255,255,0.6);;
|
10599
10595
|
}
|
10600
10596
|
|
10601
10597
|
#top-search-wrap input[type="text"] {
|
@@ -11925,6 +11921,10 @@ a.lv-footer:hover {
|
|
11925
11921
|
width: 100%;
|
11926
11922
|
}
|
11927
11923
|
|
11924
|
+
.chart-table table {
|
11925
|
+
font-size: 11px;
|
11926
|
+
}
|
11927
|
+
|
11928
11928
|
/*
|
11929
11929
|
* Sparkline Tooltip
|
11930
11930
|
*/
|
@@ -16229,3 +16229,129 @@ body.login-content:before {
|
|
16229
16229
|
.error .chosen-container-active .chosen-single:after {
|
16230
16230
|
background: #f6675d !Important;
|
16231
16231
|
}
|
16232
|
+
|
16233
|
+
svg.ct-chart-bar, svg.ct-chart-line{
|
16234
|
+
overflow: visible;
|
16235
|
+
}
|
16236
|
+
|
16237
|
+
.ct-label.ct-label.ct-horizontal.ct-end {
|
16238
|
+
position: relative;
|
16239
|
+
justify-content: flex-end;
|
16240
|
+
text-align: right;
|
16241
|
+
transform-origin: 100% 0;
|
16242
|
+
transform: translate(-100%) rotate(-45deg);
|
16243
|
+
white-space:nowrap;
|
16244
|
+
}
|
16245
|
+
|
16246
|
+
|
16247
|
+
.ct-legend {
|
16248
|
+
position: relative;
|
16249
|
+
z-index: 10;
|
16250
|
+
list-style: none;
|
16251
|
+
text-align: left;
|
16252
|
+
cursor: pointer;
|
16253
|
+
}
|
16254
|
+
|
16255
|
+
.bar-chart .ct-legend, .line-chart .ct-legend {
|
16256
|
+
text-align: center;
|
16257
|
+
}
|
16258
|
+
|
16259
|
+
.ct-legend li {
|
16260
|
+
position: relative;
|
16261
|
+
padding-left: 23px;
|
16262
|
+
margin-bottom: 3px;
|
16263
|
+
}
|
16264
|
+
|
16265
|
+
.bar-chart .ct-legend li, .line-chart .ct-legend li{
|
16266
|
+
display: inline-block;
|
16267
|
+
margin: 10px;
|
16268
|
+
}
|
16269
|
+
|
16270
|
+
.ct-legend li:before {
|
16271
|
+
width: 12px;
|
16272
|
+
height: 12px;
|
16273
|
+
position: absolute;
|
16274
|
+
left: 0;
|
16275
|
+
content: '';
|
16276
|
+
border: 3px solid transparent;
|
16277
|
+
border-radius: 2px;
|
16278
|
+
}
|
16279
|
+
|
16280
|
+
.ct-legend li.inactive:before {
|
16281
|
+
background: transparent;
|
16282
|
+
}
|
16283
|
+
|
16284
|
+
.ct-legend .ct-series-0:before {
|
16285
|
+
background-color: #d70206;
|
16286
|
+
border-color: #d70206;
|
16287
|
+
}
|
16288
|
+
|
16289
|
+
.ct-legend .ct-series-1:before {
|
16290
|
+
background-color: #f05b4f;
|
16291
|
+
border-color: #f05b4f;
|
16292
|
+
}
|
16293
|
+
|
16294
|
+
.ct-legend .ct-series-2:before {
|
16295
|
+
background-color: #f4c63d;
|
16296
|
+
border-color: #f4c63d;
|
16297
|
+
}
|
16298
|
+
|
16299
|
+
.ct-legend .ct-series-3:before {
|
16300
|
+
background-color: #d17905;
|
16301
|
+
border-color: #d17905;
|
16302
|
+
}
|
16303
|
+
|
16304
|
+
.ct-legend .ct-series-4:before {
|
16305
|
+
background-color: #453d3f;
|
16306
|
+
border-color: #453d3f;
|
16307
|
+
}
|
16308
|
+
|
16309
|
+
.ct-legend .ct-series-5:before {
|
16310
|
+
background-color: #59922b;
|
16311
|
+
border-color: #59922b;
|
16312
|
+
}
|
16313
|
+
|
16314
|
+
.ct-legend .ct-series-6:before {
|
16315
|
+
background-color: #0544d3;
|
16316
|
+
border-color: #0544d3;
|
16317
|
+
}
|
16318
|
+
|
16319
|
+
.ct-legend .ct-series-7:before {
|
16320
|
+
background-color: #6b0392;
|
16321
|
+
border-color: #6b0392;
|
16322
|
+
}
|
16323
|
+
|
16324
|
+
.ct-legend .ct-series-8:before {
|
16325
|
+
background-color: #f05b4f;
|
16326
|
+
border-color: #f05b4f;
|
16327
|
+
}
|
16328
|
+
|
16329
|
+
.ct-legend .ct-series-9:before {
|
16330
|
+
background-color: #dda458;
|
16331
|
+
border-color: #dda458;
|
16332
|
+
}
|
16333
|
+
|
16334
|
+
.ct-legend .ct-series-10:before {
|
16335
|
+
background-color: #eacf7d;
|
16336
|
+
border-color: #eacf7d;
|
16337
|
+
}
|
16338
|
+
|
16339
|
+
.ct-legend .ct-series-11:before {
|
16340
|
+
background-color: #86797d;
|
16341
|
+
border-color: #86797d;
|
16342
|
+
}
|
16343
|
+
|
16344
|
+
.ct-legend .ct-series-12:before {
|
16345
|
+
background-color: #b2c326;
|
16346
|
+
border-color: #b2c326;
|
16347
|
+
}
|
16348
|
+
|
16349
|
+
.ct-legend .ct-series-13:before {
|
16350
|
+
background-color: #6188e2;
|
16351
|
+
border-color: #6188e2;
|
16352
|
+
}
|
16353
|
+
|
16354
|
+
.ct-legend .ct-series-14:before {
|
16355
|
+
background-color: #a748ca;
|
16356
|
+
border-color: #a748ca;
|
16357
|
+
}
|