active-list 4.0.0
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.
- data/LICENSE +20 -0
- data/README.rdoc +46 -0
- data/VERSION +1 -0
- data/lib/active-list.rb +37 -0
- data/lib/active-list/action_pack.rb +48 -0
- data/lib/active-list/columns/action_column.rb +70 -0
- data/lib/active-list/columns/data_column.rb +138 -0
- data/lib/active-list/columns/field_column.rb +29 -0
- data/lib/active-list/compass/stylesheets/_active-list.scss +7 -0
- data/lib/active-list/compass/stylesheets/active-list/_background.scss +37 -0
- data/lib/active-list/compass/stylesheets/active-list/_minimal.scss +89 -0
- data/lib/active-list/compass/stylesheets/active-list/_theme.scss +161 -0
- data/lib/active-list/definition.rb +103 -0
- data/lib/active-list/exporters.rb +71 -0
- data/lib/active-list/exporters/csv_exporter.rb +30 -0
- data/lib/active-list/exporters/excel_csv_exporter.rb +36 -0
- data/lib/active-list/exporters/open_document_spreadsheet_exporter.rb +81 -0
- data/lib/active-list/finder.rb +133 -0
- data/lib/active-list/generator.rb +88 -0
- data/lib/active-list/rails/engine.rb +11 -0
- data/lib/active-list/renderers.rb +28 -0
- data/lib/active-list/renderers/simple_renderer.rb +333 -0
- data/lib/assets/images/active-list.png +0 -0
- data/lib/assets/javascripts/active-list.jquery.js +128 -0
- data/lib/assets/stylesheets/active-list.css.scss +7 -0
- metadata +156 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2012 Brice Texier
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
= ActiveList
|
2
|
+
|
3
|
+
ActiveList is a simple list widget. It permits to create a controller
|
4
|
+
method and view helper to displays lists.
|
5
|
+
|
6
|
+
The first need was to have a simple component to build easily HTML
|
7
|
+
tables. No scaffolds, only listings.
|
8
|
+
|
9
|
+
ActiveList works only with Rails ≥ 3.1.
|
10
|
+
|
11
|
+
== Quick start
|
12
|
+
|
13
|
+
First, the JS code must be added to the pipeline in app/assets/javascripts/application.js:
|
14
|
+
|
15
|
+
//= require active-list.jquery
|
16
|
+
|
17
|
+
And get a better, you can add in app/assets/stylesheets/application.css:
|
18
|
+
|
19
|
+
*= require active-list
|
20
|
+
|
21
|
+
The simple way to use it is to write in our controller:
|
22
|
+
|
23
|
+
class PeopleController < ApplicationController
|
24
|
+
list
|
25
|
+
|
26
|
+
def index
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
And in the view app/views/people/index.html.erb:
|
31
|
+
|
32
|
+
<%=list-%>
|
33
|
+
|
34
|
+
== Build Status {<img src="https://secure.travis-ci.org/burisu/active-list.png"/>}[http://travis-ci.org/burisu/active-list]
|
35
|
+
|
36
|
+
== To do
|
37
|
+
|
38
|
+
* Provides styles as @mixins for a better customization
|
39
|
+
* Adds support for Prototype JS
|
40
|
+
* Adds implicit exporters JSON, XML,
|
41
|
+
|
42
|
+
== License
|
43
|
+
|
44
|
+
ActiveList is released under the MIT license:
|
45
|
+
|
46
|
+
* http://www.opensource.org/licenses/MIT
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
4.0.0
|
data/lib/active-list.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'fastercsv'
|
2
|
+
require 'csv'
|
3
|
+
require 'action_dispatch'
|
4
|
+
require 'rails'
|
5
|
+
require 'compass'
|
6
|
+
|
7
|
+
module ActiveList #:nodoc:
|
8
|
+
|
9
|
+
|
10
|
+
CSV = (::CSV.const_defined?(:Reader) ? ::FasterCSV : ::CSV).freeze
|
11
|
+
|
12
|
+
def self.version
|
13
|
+
v = nil
|
14
|
+
File.open(File.join(File.dirname(__FILE__), "..", "VERSION")) {|f| v = f.read.strip}
|
15
|
+
return v
|
16
|
+
end
|
17
|
+
VERSION = self.version.freeze
|
18
|
+
|
19
|
+
def self.assets_path
|
20
|
+
File.join(File.dirname(__FILE__), "assets", "images")
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.compass_extension_path
|
24
|
+
File.join(File.dirname(__FILE__), "active-list", "compass")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# Compass registration
|
30
|
+
Compass::Frameworks.register('active-list', :path => ActiveList.compass_extension_path)
|
31
|
+
|
32
|
+
require "active-list/definition"
|
33
|
+
require "active-list/generator"
|
34
|
+
require "active-list/action_pack"
|
35
|
+
require "active-list/rails/engine"
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'action_view'
|
3
|
+
|
4
|
+
module ActiveList
|
5
|
+
|
6
|
+
module ActionController
|
7
|
+
|
8
|
+
def self.included(base) #:nodoc:
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# Permits to define and generate methods to manage dynamic
|
14
|
+
# table ActiveList
|
15
|
+
def list(*args, &block)
|
16
|
+
name, options = nil, {}
|
17
|
+
name = args[0] if args[0].is_a? Symbol
|
18
|
+
options = args[-1] if args[-1].is_a? Hash
|
19
|
+
name ||= self.controller_name.to_sym
|
20
|
+
model = (options[:model]||name).to_s.classify.constantize
|
21
|
+
options[:controller_method_name] = "list#{'_'+name.to_s if name != self.controller_name.to_sym}"
|
22
|
+
options[:view_method_name] = "_#{self.controller_name}_list_#{name}_tag"
|
23
|
+
options[:records_variable_name] = "@#{name}"
|
24
|
+
table = ActiveList::Table.new(name, model, options)
|
25
|
+
if block_given?
|
26
|
+
yield table
|
27
|
+
else
|
28
|
+
table.load_default_columns
|
29
|
+
end
|
30
|
+
|
31
|
+
class_eval(table.send(:generate_controller_method_code), __FILE__, __LINE__)
|
32
|
+
ActionView::Base.send(:class_eval, table.send(:generate_view_method_code), __FILE__, __LINE__)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module ViewsHelper
|
40
|
+
def list(*args, &block)
|
41
|
+
name, options = nil, {}
|
42
|
+
name = args[0] if args[0].is_a? Symbol
|
43
|
+
options = args[-1] if args[-1].is_a? Hash
|
44
|
+
self.send("_#{options[:controller]||self.controller_name}_#{__method__}_#{name||self.controller_name}_tag", &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module ActiveList
|
3
|
+
|
4
|
+
class Table
|
5
|
+
|
6
|
+
# Add a new method in Table which permit to define data columns
|
7
|
+
def action(name, options={})
|
8
|
+
@columns << ActionColumn.new(self, name, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class ActionColumn < Column
|
14
|
+
|
15
|
+
def header_code
|
16
|
+
"'ƒ'"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def operation(record='record')
|
21
|
+
link_options = ""
|
22
|
+
link_options += ", :confirm=>::I18n.translate('labels.#{@options[:confirm]}')" unless @options[:confirm].nil?
|
23
|
+
link_options += ", :method=>#{@options[:method].inspect}" if @options[:method].is_a? Symbol
|
24
|
+
action = @name
|
25
|
+
format = @options[:format] ? ", :format=>'#{@options[:format]}'" : ""
|
26
|
+
if @options[:remote]
|
27
|
+
raise Exception.new("Sure to use :remote ?")
|
28
|
+
remote_options = @options.dup
|
29
|
+
remote_options[:confirm] = ::I18n.translate('labels.'+@options[:confirm].to_s) unless @options[:confirm].nil?
|
30
|
+
remote_options.delete :remote
|
31
|
+
remote_options.delete :image
|
32
|
+
remote_options = remote_options.inspect.to_s
|
33
|
+
remote_options = remote_options[1..-2]
|
34
|
+
code = "link_to_remote(#{image}"
|
35
|
+
code += ", {:url=>{:action=>:"+@name.to_s+", :id=>"+record+".id"+format+"}"
|
36
|
+
code += ", "+remote_options+"}"
|
37
|
+
code += ", {:title=>::I18n.translate('labels.#{action}')}"
|
38
|
+
code += ")"
|
39
|
+
elsif @options[:actions]
|
40
|
+
raise Exception.new("options[:actions] have to be a Hash.") unless @options[:actions].is_a? Hash
|
41
|
+
cases = []
|
42
|
+
for a in @options[:actions]
|
43
|
+
v = a[1][:action].to_s.split('_')[-1]
|
44
|
+
cases << record+"."+@name.to_s+".to_s=="+a[0].inspect+"\nlink_to(::I18n.translate('labels.#{v}')"+
|
45
|
+
", {"+(a[1][:controller] ? ':controller=>:'+a[1][:controller].to_s+', ' : '')+":action=>'"+a[1][:action].to_s+"', :id=>"+record+".id"+format+"}"+
|
46
|
+
", {:id=>'"+@name.to_s+"_'+"+record+".id.to_s"+link_options+", :title=>::I18n.translate('labels.#{v}')}"+
|
47
|
+
")\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
code = "if "+cases.join("elsif ")+"end"
|
51
|
+
else
|
52
|
+
url = @options[:url] ||= {}
|
53
|
+
url[:controller] ||= @options[:controller]||self.table.model.name.underscore.pluralize.to_sym
|
54
|
+
url[:action] ||= @name
|
55
|
+
url[:id] ||= "RECORD.id"
|
56
|
+
url.delete_if{|k, v| v.nil?}
|
57
|
+
url = "{"+url.collect{|k, v| ":#{k}=>"+(v.is_a?(String) ? v.gsub(/RECORD/, record) : v.inspect)}.join(", ")+format+"}"
|
58
|
+
code = "{:id=>'"+@name.to_s+"_'+"+record+".id.to_s"+link_options+", :title=>::I18n.translate('labels.#{action}')}"
|
59
|
+
code = "link_to(::I18n.translate('labels.#{action}'), "+url+", "+code+")"
|
60
|
+
end
|
61
|
+
code = "if ("+@options[:if].gsub('RECORD', record)+")\n"+code+"\n end" if @options[:if]
|
62
|
+
code
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
class Table
|
4
|
+
|
5
|
+
# Retrieves all columns in database
|
6
|
+
def table_columns
|
7
|
+
cols = self.model_columns.collect{|c| c.name}
|
8
|
+
@columns.select{|c| c.is_a? DataColumn and cols.include? c.name.to_s}
|
9
|
+
end
|
10
|
+
|
11
|
+
def data_columns
|
12
|
+
@columns.select{|c| c.is_a? DataColumn}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Add a new method in Table which permit to define data columns
|
16
|
+
def column(name, options={})
|
17
|
+
@columns << DataColumn.new(self, name, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class DataColumn < Column
|
23
|
+
|
24
|
+
def header_code
|
25
|
+
if @options[:label].is_a? String
|
26
|
+
"::I18n.translate('labels.#{@options[:label].strip}')"
|
27
|
+
elsif through = @options[:through]
|
28
|
+
through = [through] unless through.is_a? Array
|
29
|
+
model, reflection = @table.model, nil
|
30
|
+
for ref in through
|
31
|
+
unless reflection.nil?
|
32
|
+
model = reflection.class_name.constantize rescue nil
|
33
|
+
end
|
34
|
+
raise Exception.new("Unknown model #{reflection.class_name}") if model.nil?
|
35
|
+
reflection = model.reflections[ref]
|
36
|
+
raise Exception.new("Unknown reflection :#{ref} (#{through.inspect}) for the ActiveRecord: "+model.name) if reflection.nil?
|
37
|
+
end
|
38
|
+
"#{model.name}.human_attribute_name('#{reflection.name}')"
|
39
|
+
else
|
40
|
+
"#{@table.model.name}.human_attribute_name('#{@name}')"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Code for rows
|
46
|
+
def datum_code(record='rekord', child = false)
|
47
|
+
code = if child and @options[:children].is_a? Symbol
|
48
|
+
"#{record}.#{@options[:children]}"
|
49
|
+
elsif child and @options[:children].is_a? FalseClass
|
50
|
+
"nil"
|
51
|
+
elsif through = @options[:through] and !child
|
52
|
+
through = [through] unless through.is_a?(Array)
|
53
|
+
foreign_record = record
|
54
|
+
through.each { |x| foreign_record += '.'+x.to_s }
|
55
|
+
"(#{foreign_record}.#{@name} rescue nil)"
|
56
|
+
else
|
57
|
+
"#{record}.#{@name}"
|
58
|
+
end
|
59
|
+
return code
|
60
|
+
end
|
61
|
+
|
62
|
+
# Code for exportation
|
63
|
+
def exporting_datum_code(record='rekord', noview=false)
|
64
|
+
datum = self.datum_code(record)
|
65
|
+
if self.datatype == :boolean
|
66
|
+
datum = "(#{datum} ? ::I18n.translate('list.export.true_value') : ::I18n.translate('list.export.false_value'))"
|
67
|
+
elsif self.datatype == :date
|
68
|
+
datum = "(#{datum}.nil? ? '' : ::I18n.localize(#{datum}))"
|
69
|
+
elsif self.datatype == :decimal and not noview
|
70
|
+
currency = nil
|
71
|
+
if currency = self.options[:currency]
|
72
|
+
currency = currency[:body] if currency.is_a?(Hash)
|
73
|
+
currency = :currency if currency.is_a?(TrueClass)
|
74
|
+
currency = "RECORD.#{currency}" if currency.is_a?(Symbol)
|
75
|
+
raise Exception.new("Option :currency is not valid. Hash, Symbol or true/false") unless currency.is_a?(String)
|
76
|
+
end
|
77
|
+
datum = "(#{datum}.nil? ? '' : ::I18n.localize(#{datum}#{', :currency=>'+currency.gsub(/RECORD/, record) if currency}))"
|
78
|
+
elsif @name.to_s.match(/(^|\_)currency$/) and self.datatype == :string and self.limit == 3
|
79
|
+
datum = "(#{datum}.nil? ? '' : ::I18n.currency_label(#{datum}))"
|
80
|
+
elsif @name==:country and self.datatype == :string and self.limit == 2
|
81
|
+
datum = "(#{datum}.nil? ? '' : ::I18n.translate('countries.'+#{datum}))"
|
82
|
+
elsif @name==:language and self.datatype == :string and self.limit <= 8
|
83
|
+
datum = "(#{datum}.nil? ? '' : ::I18n.translate('languages.'+#{datum}))"
|
84
|
+
end
|
85
|
+
return datum
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the data type of the column if the column is in the database
|
89
|
+
def datatype
|
90
|
+
@options[:datatype] || (@column ? @column.type : nil)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def numeric?
|
95
|
+
[:decimal, :integer, :float, :numeric].include? self.datatype
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns the size/length of the column if the column is in the database
|
99
|
+
def limit
|
100
|
+
@column.limit if @column
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# Returns the class name of the used model
|
105
|
+
def class_name
|
106
|
+
klass = self.table.model
|
107
|
+
if through = @options[:through]
|
108
|
+
through = [through] unless through.is_a? Array
|
109
|
+
for ref in through
|
110
|
+
klass = klass.reflections[ref].class_name.constantize
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return klass.name
|
114
|
+
end
|
115
|
+
|
116
|
+
# Defines if column is exportable
|
117
|
+
def exportable?
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
# Check if a column is sortable
|
122
|
+
def sortable?
|
123
|
+
#not self.action? and
|
124
|
+
not self.options[:through] and not @column.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
# Generate code in order to get the (foreign) record of the column
|
128
|
+
def record_expr(record='record')
|
129
|
+
if @options[:through]
|
130
|
+
return ([record]+[@options[:through]]).flatten.join(".")
|
131
|
+
else
|
132
|
+
return record
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActiveList
|
2
|
+
|
3
|
+
class Table
|
4
|
+
|
5
|
+
# Add a new method in Table which permit to define text_field columns
|
6
|
+
def text_field(name, options={})
|
7
|
+
@columns << TextFieldColumn.new(self, name, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Add a new method in Table which permit to define check_box columns
|
11
|
+
def check_box(name, options={})
|
12
|
+
@columns << CheckBoxColumn.new(self, name, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class FieldColumn < Column
|
18
|
+
def header_code
|
19
|
+
"#{@table.model.name}.human_attribute_name('#{@name}')"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TextFieldColumn < FieldColumn
|
24
|
+
end
|
25
|
+
|
26
|
+
class CheckBoxColumn < FieldColumn
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
// Provides mixin to generate colors for cells backgrounds
|
2
|
+
//
|
3
|
+
|
4
|
+
@function merge-color($color-1, $color-2) {
|
5
|
+
$col2: rgb(red($color-2), green($color-2), blue($color-2));
|
6
|
+
$percent: 100*alpha($color-2);
|
7
|
+
@return mix($col2, $color-1, $percent);
|
8
|
+
}
|
9
|
+
|
10
|
+
@function merge-colors($color, $color-1: rgba(0, 0, 0, 0), $color-2: rgba(0, 0, 0, 0), $color-3: rgba(0, 0, 0, 0), $color-4: rgba(0, 0, 0, 0), $color-5: rgba(0, 0, 0, 0), $color-6: rgba(0, 0, 0, 0), $color-7: rgba(0, 0, 0, 0), $color-8: rgba(0, 0, 0, 0), $color-9: rgba(0, 0, 0, 0), $color-10: rgba(0, 0, 0, 0)) {
|
11
|
+
@return merge-color(merge-color(merge-color(merge-color(merge-color(merge-color(merge-color(merge-color(merge-color(merge-color($color, $color-1), $color-2), $color-3), $color-4), $color-5), $color-6), $color-7), $color-8), $color-9), $color-10);
|
12
|
+
}
|
13
|
+
|
14
|
+
$list-line-backgrounds: ("" rgba(255, 255, 255, 0)) (".odd" rgba(255, 255, 255, 0.5)) (".even" rgba(255, 255, 255, 0.5));
|
15
|
+
$list-column-backgrounds: ("" rgba(255, 255, 255, 0)) (".act" rgba(255, 134, 0, 0)) (".sor" rgba(0, 18, 132, 0.05));
|
16
|
+
$list-hover-backgrounds: ("" rgba(255, 255, 255, 0)) (":hover" rgba(209, 218, 255, 0.3));
|
17
|
+
|
18
|
+
@mixin list-colors($bgcolor: #000000, $selector: '&') {
|
19
|
+
tr {
|
20
|
+
#{$selector} {
|
21
|
+
@each $line-background in $list-line-backgrounds {
|
22
|
+
&#{nth($line-background, 1)} {
|
23
|
+
@each $hover-background in $list-hover-backgrounds {
|
24
|
+
&#{nth($hover-background, 1)} {
|
25
|
+
@each $col-background in $list-column-backgrounds {
|
26
|
+
td#{nth($col-background, 1)} {
|
27
|
+
background-color: merge-colors($bgcolor, nth($line-background, 2), nth($col-background, 2), nth($hover-background, 2));
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
// Minimal style to get a working ActiveList
|
2
|
+
|
3
|
+
div[data-list-source] {
|
4
|
+
table.list {
|
5
|
+
thead {
|
6
|
+
tr {
|
7
|
+
th {
|
8
|
+
&[data-list-column-sort] {
|
9
|
+
cursor: pointer;
|
10
|
+
}
|
11
|
+
|
12
|
+
&.spe {
|
13
|
+
padding: 0;
|
14
|
+
.list-menu {
|
15
|
+
position: relative;
|
16
|
+
a { cursor: pointer; }
|
17
|
+
.list-menu-start {
|
18
|
+
display: block;
|
19
|
+
height: 16px;
|
20
|
+
padding: 2px;
|
21
|
+
}
|
22
|
+
&:hover {
|
23
|
+
.list-menu-start { z-index:5000; position: relative; top: 0px; }
|
24
|
+
& > ul { display: block; }
|
25
|
+
}
|
26
|
+
ul {
|
27
|
+
display: none;
|
28
|
+
position:absolute;
|
29
|
+
top: 20px;
|
30
|
+
padding: 1px;
|
31
|
+
margin:0;
|
32
|
+
html[dir="ltr"] & { right: -1px;}
|
33
|
+
html[dir="rtl"] & { left: -1px;}
|
34
|
+
li {
|
35
|
+
&[data-list-change-page-size], &[data-list-toggle-column] {
|
36
|
+
cursor: pointer;
|
37
|
+
display: block;
|
38
|
+
padding: 0.3ex;
|
39
|
+
}
|
40
|
+
list-style-type: none;
|
41
|
+
width: 25ex;
|
42
|
+
position: relative;
|
43
|
+
a {
|
44
|
+
display: block;
|
45
|
+
padding: 0.3ex;
|
46
|
+
}
|
47
|
+
ul {
|
48
|
+
display: none;
|
49
|
+
position: absolute;
|
50
|
+
top: -2px;
|
51
|
+
html[dir="ltr"] & { right: 25ex; }
|
52
|
+
html[dir="rtl"] & { left: 25ex; }
|
53
|
+
&:hover { display:block; }
|
54
|
+
}
|
55
|
+
&:hover ul { display:block; }
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
&.hidden {
|
62
|
+
display: none;
|
63
|
+
}
|
64
|
+
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
tbody {
|
70
|
+
tr {
|
71
|
+
td.hidden {
|
72
|
+
display: none;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
}
|
78
|
+
|
79
|
+
div.extras {
|
80
|
+
.pagination {
|
81
|
+
a[data-list-move-to-page] {
|
82
|
+
cursor: pointer;
|
83
|
+
}
|
84
|
+
a[data-list-move-to-page][disabled] {
|
85
|
+
cursor: default;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|