ultimate-base 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rvmrc +2 -0
- data/.rvmrc.example +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE +5 -0
- data/README.md +1 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/backbone/backbone.js +1452 -0
- data/app/assets/javascripts/backbone/ultimate/app.js.coffee +25 -0
- data/app/assets/javascripts/backbone/ultimate/collection.js.coffee +12 -0
- data/app/assets/javascripts/backbone/ultimate/model.js.coffee +12 -0
- data/app/assets/javascripts/backbone/ultimate/router.js.coffee +13 -0
- data/app/assets/javascripts/backbone/ultimate/view.js.coffee +96 -0
- data/app/assets/javascripts/ultimate/base.js.coffee +103 -0
- data/app/assets/javascripts/ultimate/bus.js.coffee +57 -0
- data/app/assets/javascripts/ultimate/devise.js.coffee +18 -0
- data/app/assets/javascripts/ultimate/experimental/_inflections/dzone.inflections.js +154 -0
- data/app/assets/javascripts/ultimate/experimental/_inflections/inflections.js.coffee +2 -0
- data/app/assets/javascripts/ultimate/experimental/_inflections/plur.js +29 -0
- data/app/assets/javascripts/ultimate/experimental/_inflections/underscore.inflection.js +175 -0
- data/app/assets/javascripts/ultimate/experimental/fuzzy-json-generator.js.coffee +48 -0
- data/app/assets/javascripts/ultimate/helpers/array.js.coffee +63 -0
- data/app/assets/javascripts/ultimate/helpers/asset_tag.js.coffee +63 -0
- data/app/assets/javascripts/ultimate/helpers/decor.js.coffee +14 -0
- data/app/assets/javascripts/ultimate/helpers/forms.js.coffee +0 -0
- data/app/assets/javascripts/ultimate/helpers/tags.js.coffee +70 -0
- data/app/assets/javascripts/ultimate/helpers.js.coffee +149 -0
- data/app/assets/javascripts/ultimate/improves/datepicker.js.coffee +34 -0
- data/app/assets/javascripts/ultimate/improves/form-errors.js.coffee +146 -0
- data/app/assets/javascripts/ultimate/improves/form.js.coffee +155 -0
- data/app/assets/javascripts/ultimate/improves/magic-radios.js.coffee +41 -0
- data/app/assets/javascripts/ultimate/improves/tablesorter.js +59 -0
- data/app/assets/javascripts/ultimate/improves/typed-field.js.coffee +98 -0
- data/app/assets/javascripts/ultimate/underscore/underscore.js +1059 -0
- data/app/assets/javascripts/ultimate/underscore/underscore.string.js +480 -0
- data/app/assets/javascripts/ultimate/widgets/dock.js.coffee +70 -0
- data/app/assets/javascripts/ultimate/widgets/gear.js.coffee +84 -0
- data/app/assets/javascripts/ultimate/widgets/jquery-ext.js.coffee +104 -0
- data/app/assets/javascripts/ultimate/widgets/jquery.adapter.js.coffee +62 -0
- data/app/assets/javascripts/ultimate/widgets/widget.js.coffee +115 -0
- data/app/assets/stylesheets/polyfills/PIE.htc +96 -0
- data/app/assets/stylesheets/polyfills/boxsizing.htc +300 -0
- data/app/assets/stylesheets/ultimate/mixins/_routines.css.scss +95 -0
- data/app/assets/stylesheets/ultimate/mixins/_vendors.css.scss +34 -0
- data/app/assets/stylesheets/ultimate/mixins/css3/_text-shadow.scss +37 -0
- data/app/assets/stylesheets/ultimate/mixins/css3.css.scss +328 -0
- data/app/assets/stylesheets/ultimate/mixins/decor.css.scss +86 -0
- data/app/assets/stylesheets/ultimate/mixins/fonts.css.scss +100 -0
- data/app/assets/stylesheets/ultimate/mixins/microstructures.css.scss +188 -0
- data/app/assets/stylesheets/ultimate/structures/slider.css.scss +53 -0
- data/lib/ultimate-base/engine.rb +6 -0
- data/lib/ultimate-base/extensions/directive_processor.rb +64 -0
- data/lib/ultimate-base/extensions/sass_script_functions.rb +39 -0
- data/lib/ultimate-base/version.rb +5 -0
- data/lib/ultimate-base.rb +10 -0
- data/ultimate-base.gemspec +25 -0
- metadata +102 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
# TODO this is part of custom forms
|
2
|
+
# TODO registrable
|
3
|
+
# TODO may be, replace "clear immune" technique with something more effective, ex. additional class
|
4
|
+
|
5
|
+
( ( $ ) ->
|
6
|
+
|
7
|
+
$.errorableFields = {}
|
8
|
+
$.errorableFieldsSelector = ''
|
9
|
+
|
10
|
+
$.registerErrorableField = (selector, events, errorCleaner) ->
|
11
|
+
$.errorableFields[selector.split(/\s+/)[0]] = arguments
|
12
|
+
$.errorableFieldsSelector = _.keys($.errorableFields).join(', ')
|
13
|
+
true
|
14
|
+
|
15
|
+
$.fieldWithErrorsWrapperClass = 'field_with_errors'
|
16
|
+
$.fieldWithClearImmuneWrapperClass = 'immune'
|
17
|
+
$.labelForFieldWithErrorClass = 'with-error'
|
18
|
+
|
19
|
+
# [ selector: String = '.g-select, .g-text-field, .g-text-area' ]
|
20
|
+
# [ [, ]errors: Array = [] ]
|
21
|
+
# [ [, ]clearImmune: Boolean = false ]
|
22
|
+
$.fn.setFormErrors = ->
|
23
|
+
# dafault parameters
|
24
|
+
selector = $.errorableFieldsSelector # '.g-select, .g-text-field, .g-text-area'
|
25
|
+
errors = []
|
26
|
+
clearImmune = false
|
27
|
+
# parsing arguments
|
28
|
+
# TODO liquid arguments parser ( by arguments info, ex: {selector: String, errors: Array, clearImmune: Boolean} )
|
29
|
+
a = args arguments
|
30
|
+
if a.length
|
31
|
+
first = a.shift()
|
32
|
+
if _.isString first
|
33
|
+
selector = first
|
34
|
+
if a.length
|
35
|
+
first = a.shift()
|
36
|
+
if _.isString first
|
37
|
+
first = [first]
|
38
|
+
if _.isArray first
|
39
|
+
errors = _.uniq first
|
40
|
+
if a.length
|
41
|
+
first = a.shift()
|
42
|
+
if _.isBoolean first
|
43
|
+
clearImmune = first
|
44
|
+
# ui process
|
45
|
+
@clearFormErrors selector, clearImmune
|
46
|
+
wrapperSelector = ".#{$.fieldWithErrorsWrapperClass}"
|
47
|
+
if clearImmune
|
48
|
+
wrapperSelector += ".#{$.fieldWithClearImmuneWrapperClass}"
|
49
|
+
jErrorWrappers = @find(selector).wrap(selectorToHtml wrapperSelector).parent()
|
50
|
+
jErrorWrappers.append (for err in errors then content_tag('div', err, class: 'error')).join("\n")
|
51
|
+
jErrorWrappers.closestLabel().addClass($.labelForFieldWithErrorClass)
|
52
|
+
|
53
|
+
$.fn.setErrors = ->
|
54
|
+
deprecate('jQ.setErrors(...)', 'jQ.setFormErrors(...)')
|
55
|
+
@setFormErrors.apply(@, arguments)
|
56
|
+
|
57
|
+
# [selector]
|
58
|
+
# [clearImmune]
|
59
|
+
$.fn.clearFormErrors = ->
|
60
|
+
selector = $.errorableFieldsSelector # '.g-select, .g-text-field, .g-text-area'
|
61
|
+
clearImmune = false
|
62
|
+
# parsing arguments
|
63
|
+
# TODO liquid arguments parser ( by arguments info, ex: {selector: String, clearImmune: Boolean} )
|
64
|
+
a = args arguments
|
65
|
+
if a.length
|
66
|
+
first = a.shift()
|
67
|
+
if _.isString first
|
68
|
+
selector = first
|
69
|
+
if a.length
|
70
|
+
first = a.shift()
|
71
|
+
if _.isBoolean(first)
|
72
|
+
clearImmune = first
|
73
|
+
wrapperSelector = ".#{$.fieldWithErrorsWrapperClass}"
|
74
|
+
if clearImmune
|
75
|
+
wrapperSelector += ".#{$.fieldWithClearImmuneWrapperClass}"
|
76
|
+
else
|
77
|
+
wrapperSelector += ":not(.#{$.fieldWithClearImmuneWrapperClass})"
|
78
|
+
fullSelector = "#{wrapperSelector}:has(#{selector})"
|
79
|
+
jErrorWrappers = @find fullSelector
|
80
|
+
jErrorWrappers = @closest fullSelector unless jErrorWrappers.length
|
81
|
+
if jErrorWrappers.length
|
82
|
+
jErrorWrappers.closestLabel().removeClass($.labelForFieldWithErrorClass)
|
83
|
+
jErrorWrappers.children('.error').remove()
|
84
|
+
jErrorWrappers.children(selector).unwrap()
|
85
|
+
@
|
86
|
+
|
87
|
+
$.fn.clearFromErrors = ->
|
88
|
+
deprecate('jQ.clearFromErrors(...)', 'jQ.clearFormErrors(...)')
|
89
|
+
@clearFormErrors.apply(@, arguments)
|
90
|
+
|
91
|
+
$.ujsAjaxError = (event, jqXHR) ->
|
92
|
+
jForm = $(@).clearFormErrors()
|
93
|
+
try
|
94
|
+
responseJSON = $.parseJSON jqXHR.responseText
|
95
|
+
errors = responseJSON['errors'] or responseJSON
|
96
|
+
if errors
|
97
|
+
jFields = jForm.find '[name*="["]:input:visible' # TODO research without :visible, because has custom elements
|
98
|
+
if jFields.length
|
99
|
+
for fieldErrors, fieldName of errors
|
100
|
+
jField = jFields.filter "[name$=\"[#{fieldName}]\"]"
|
101
|
+
if jField.length
|
102
|
+
jField.closestEdge().setErrors fieldErrors
|
103
|
+
catch e
|
104
|
+
# nop
|
105
|
+
true
|
106
|
+
|
107
|
+
|
108
|
+
$.fn.customErrorsHandler = (suspend = true, eventName = 'ajax:error', selector = 'form[data-remote="true"]') ->
|
109
|
+
if @length
|
110
|
+
if @is 'form'
|
111
|
+
jForms = @filter selector
|
112
|
+
jForms.off eventName, $.ujsAjaxError
|
113
|
+
jForms.on eventName, $.ujsAjaxError if suspend
|
114
|
+
else
|
115
|
+
@off eventName, selector, $.ujsAjaxError
|
116
|
+
@on eventName, selector, $.ujsAjaxError if suspend
|
117
|
+
@
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
$.fn.errorCleaners = (suspend = true) ->
|
123
|
+
if @length
|
124
|
+
jDocks = if @is ':input' then @closestEdge() else @
|
125
|
+
for fieldWrapperSelector, [selector, events, errorCleaner] of $.errorableFields
|
126
|
+
fullSelector = ".#{$.fieldWithErrorsWrapperClass} > #{selector}"
|
127
|
+
jDocks.off events, fullSelector
|
128
|
+
jDocks.on events, fullSelector, errorCleaner if suspend
|
129
|
+
@
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
$.registerErrorableField '.g-text-field input:visible', 'change keyup', ->
|
134
|
+
# text-fields error cleaner
|
135
|
+
jTextField = $ @
|
136
|
+
unless jTextField.val() is '' # TODO may be use isEmptyString()
|
137
|
+
jTextField.clearFormErrors('.g-text-field').clearFormErrors('.g-text-field', true)
|
138
|
+
jTextField.change().focus() # unwraping break change, and there changing continue
|
139
|
+
|
140
|
+
$.registerErrorableField '.g-select select', 'change', ->
|
141
|
+
# selects error cleaner
|
142
|
+
jSelect = $ @
|
143
|
+
unless jSelect.val() is '' # TODO may be use isEmptyString()
|
144
|
+
jSelect.clearFormErrors('.g-select').clearFormErrors('.g-select', true)
|
145
|
+
|
146
|
+
)( jQuery )
|
@@ -0,0 +1,155 @@
|
|
1
|
+
( ( $ ) ->
|
2
|
+
|
3
|
+
# TODO try optimize, excepting Edge and search in siblings for next cycle
|
4
|
+
$.fn.nearestFind = (selector, extremeEdgeSelector = 'form, body') ->
|
5
|
+
jEdge = @
|
6
|
+
jResult = jEdge.find selector
|
7
|
+
until jResult.length or jEdge.is extremeEdgeSelector
|
8
|
+
jEdge = jEdge.parent()
|
9
|
+
jResult = jEdge.find selector
|
10
|
+
jResult
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
$.fn.closestEdge = (edgeSelector = '.input-line, .field, .field-line, tr, li, fieldset, .g-box, form') ->
|
15
|
+
# TODO remove and extract edgeSelector, else undeprecate
|
16
|
+
deprecate 'closestEdge', '$().closest(\'your selector\')'
|
17
|
+
@closest edgeSelector
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
# @param strongById: Boolean = false
|
22
|
+
$.fn.closestLabel = ( strongById = false, passCache = false ) ->
|
23
|
+
(if @is(':input') then @ else @find(':input')).filter(':not(input[type="hidden"])').map ->
|
24
|
+
jInput = $ @
|
25
|
+
jLabel = jInput.data 'closestLabel' unless passCache
|
26
|
+
unless jLabel
|
27
|
+
if jLabel is false
|
28
|
+
return null
|
29
|
+
else
|
30
|
+
jLabel = {length: 0}
|
31
|
+
jEdge = jInput.closestEdge() # TODO may be need params
|
32
|
+
inputId = jInput.attr 'id'
|
33
|
+
if inputId
|
34
|
+
# try search label by id linkage
|
35
|
+
labelSelectorByFor = "label[for=\"#{inputId}\"]"
|
36
|
+
# at first search in the edge area
|
37
|
+
jLabel = jEdge.find labelSelectorByFor
|
38
|
+
unless jLabel.length
|
39
|
+
# try search in the closest form
|
40
|
+
jLabel = jInput.closest('form').find labelSelectorByFor
|
41
|
+
# trust only unique label on the form
|
42
|
+
jLabel = {length: 0} if jLabel.length > 1
|
43
|
+
# try get first labet in the edge area
|
44
|
+
jLabel = jEdge.find('label:first') unless jLabel.length
|
45
|
+
# taken!
|
46
|
+
if jLabel.length
|
47
|
+
# oh, this label already linked
|
48
|
+
if jLabel.data 'closestInput'
|
49
|
+
jLabel = {length: 0}
|
50
|
+
else
|
51
|
+
jLabel.data 'closestInput', jInput
|
52
|
+
jInput.data 'closestLabel', jLabel
|
53
|
+
if jLabel.length
|
54
|
+
if strongById and jLabel.attr('for') isnt jInput.attr('id')
|
55
|
+
null
|
56
|
+
else
|
57
|
+
jLabel[0]
|
58
|
+
else
|
59
|
+
null
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
$.linkedLabelsClick = ->
|
64
|
+
jLabel = $ @
|
65
|
+
jInput = jLabel.data 'closestInput'
|
66
|
+
|
67
|
+
unless jInput
|
68
|
+
attrFor = jLabel.attr 'for'
|
69
|
+
jInput = jLabel.nearestFind ":input##{attrFor}"
|
70
|
+
jInput = jLabel.nearestFind ':input' unless jInput.length is 1
|
71
|
+
jLabel.data 'closestInput', jInput if jInput.length
|
72
|
+
|
73
|
+
if jInput and jInput.length is 1
|
74
|
+
if jInput.is 'input:checkbox, input:radio'
|
75
|
+
jInput.click()
|
76
|
+
else if jInput.is 'select'
|
77
|
+
# TODO try: jInput.click() в любом случае свести к универсальносит
|
78
|
+
jInput.closest('.g-select').click()
|
79
|
+
else
|
80
|
+
jInput.focus()
|
81
|
+
false
|
82
|
+
|
83
|
+
# Cacheble bulletproof labels
|
84
|
+
# example: $('body').linkedLabels();
|
85
|
+
$.fn.linkedLabels = (suspend = true, eventName = 'click.linked-labels') ->
|
86
|
+
if @is 'label'
|
87
|
+
jLabels = @filter 'label'
|
88
|
+
jLabels.off eventName
|
89
|
+
jLabels.on eventName, $.linkedLabelsClick if suspend
|
90
|
+
else
|
91
|
+
@off eventName, 'label'
|
92
|
+
@on eventName, 'label', $.linkedLabelsClick if suspend
|
93
|
+
@
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
# [ additionAttr: String = 'data-nested-addition' ]
|
98
|
+
$.fn.setNestedAdditions = (additionAttr = 'data-nested-addition') ->
|
99
|
+
@find(":input[#{additionAttr}]").each ->
|
100
|
+
jInput = $ @
|
101
|
+
inputId = jInput.attr 'id'
|
102
|
+
if inputId
|
103
|
+
newId = "#{inputId}_#{jInput.attr additionAttr}"
|
104
|
+
jInput.attr 'id', newId
|
105
|
+
jLabel = jInput.closestLabel(true)
|
106
|
+
jLabel.attr 'for', newId if jLabel.length
|
107
|
+
jInput.removeAttr additionAttr
|
108
|
+
@
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
# setNestedIndex(params = {nestedField: index || [index, old_index]})
|
113
|
+
# setNestedIndex(nestedField, index, [old_index])
|
114
|
+
$.fn.setNestedIndex = ->
|
115
|
+
params = {}
|
116
|
+
if arguments.length is 1
|
117
|
+
params = arguments[0]
|
118
|
+
else
|
119
|
+
params[arguments[0]] = (if arguments.length > 2 then [arguments[1], arguments[2]] else arguments[1])
|
120
|
+
replacers =
|
121
|
+
name: []
|
122
|
+
id: []
|
123
|
+
for nestedField, index of params
|
124
|
+
if $.isArray index
|
125
|
+
[index, oldIndex] = index
|
126
|
+
else
|
127
|
+
oldIndex = '\\d*'
|
128
|
+
replacers['id'].push [ (new RegExp "_#{nestedField}_#{oldIndex}"), "_#{nestedField}_#{index}" ]
|
129
|
+
replacers['name'].push [ (new RegExp "\\[#{nestedField}\\]\\[#{oldIndex}\\]"), "[#{nestedField}][#{index}]" ]
|
130
|
+
( if @is(':input') then @filter('[name]') else @find(':input[name]') ).map ->
|
131
|
+
jInput = $ @
|
132
|
+
for replacerAttr, replacerPairs of replacers
|
133
|
+
# if extract attribute
|
134
|
+
if attr = jInput.attr replacerAttr
|
135
|
+
# dup attr
|
136
|
+
newAttr = attr
|
137
|
+
for pair in replacerPairs
|
138
|
+
newAttr = newAttr.replace pair[0], pair[1]
|
139
|
+
if newAttr isnt attr
|
140
|
+
jInput.closestLabel(true).attr('for', newAttr) if replacerAttr is 'id'
|
141
|
+
jInput.attr replacerAttr, newAttr
|
142
|
+
@
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
$.fillTabIndexesCounter = 0
|
147
|
+
|
148
|
+
# TODO this may be .is 'input'
|
149
|
+
$.fn.fillTabIndexes = (onlyVisible = false) ->
|
150
|
+
if @length
|
151
|
+
@find("input:not([readonly])#{if onlyVisible then ':visible' else ''}").each ->
|
152
|
+
$(@).attr 'tabindex', ++$.fillTabIndexesCounter
|
153
|
+
@
|
154
|
+
|
155
|
+
)( jQuery )
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#
|
2
|
+
# Magic Radios
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# = f.radio_button :main_addr_same_as_jur, true, data: {disable: ".main-addr"}
|
6
|
+
# = f.radio_button :main_addr_same_as_jur, false, data: {enable: ".main-addr"}
|
7
|
+
# = f.text_field :main_addr, :disabled => @profile.main_addr_same_as_jur, :class => "main-addr"
|
8
|
+
# javascript:
|
9
|
+
# $('.some form').magicRadios();
|
10
|
+
|
11
|
+
( ( $ ) ->
|
12
|
+
|
13
|
+
$.fn.magicRadios = (suspend = true, closestDock = 'fieldset, form, body', eventName = 'change.magic-radios') ->
|
14
|
+
if @length
|
15
|
+
jDocks = if @is 'input:radio' then @closest closestDock else @
|
16
|
+
jDocks.off eventName
|
17
|
+
if suspend
|
18
|
+
jDocks.on eventName, 'input:radio', (event) ->
|
19
|
+
jDock = $ event.delegateTarget
|
20
|
+
rules = [
|
21
|
+
['enable', 'disabled', false, true]
|
22
|
+
['check', 'checked', true]
|
23
|
+
['uncheck', 'checked', false]
|
24
|
+
['disable', 'disabled', true]
|
25
|
+
['writable', 'readonly', false, true]
|
26
|
+
['readonly', 'readonly', true]
|
27
|
+
]
|
28
|
+
for rule in rules
|
29
|
+
[dataParam, propName, propValue, focusFirst] = rule
|
30
|
+
linkedFields = $(@).data dataParam
|
31
|
+
if linkedFields
|
32
|
+
jFounded = jDock.find linkedFields
|
33
|
+
jFields = jFounded.filter ':input'
|
34
|
+
jFields = jFounded.find ':input' unless jFields.length
|
35
|
+
if jFields.length
|
36
|
+
jFields.prop propName, propValue
|
37
|
+
jFields.first().focus() if focusFirst
|
38
|
+
true
|
39
|
+
@
|
40
|
+
|
41
|
+
)( jQuery )
|
@@ -0,0 +1,59 @@
|
|
1
|
+
/**
|
2
|
+
* Декорирование таблиц с данными + добавление сортировки + доп. обработка таблиц с checkable строками
|
3
|
+
*
|
4
|
+
* @param {jQuery} jRoot корневые jQuery объекты, в которых будет осуществляться поиск table.tablesorter:not(.decorated)
|
5
|
+
* @returns {Number} count >= 0 количество продекорированных таблиц
|
6
|
+
*/
|
7
|
+
function decor_tables(jRoot) {
|
8
|
+
var jTables = jRoot.find('table.tablesorter:not(.decorated)'),
|
9
|
+
jTablesHeaders = jTables.find('thead th:not([colspan])'),
|
10
|
+
ts_initData = {};
|
11
|
+
if ( arguments.length > 1 ) ts_initData.sortList = arguments[1];
|
12
|
+
jTablesHeaders.prepend('<div class="bullet-wrapper"><div class="bullet"></div></div>');
|
13
|
+
jTables.find('thead')
|
14
|
+
.find('tr:first th:first').addClass('first-child')
|
15
|
+
.prepend('<div class="corner-wrapper"><div class="corner left"></div></div>')
|
16
|
+
.end().find('tr th:last-child').addClass('last-child').first()
|
17
|
+
.prepend('<div class="corner-wrapper"><div class="corner right"></div></div>');
|
18
|
+
jTables.find('td:last-child').addClass('last-child');
|
19
|
+
jTables.each( function () {
|
20
|
+
var jTable = $(this),
|
21
|
+
jTFoot = jTable.children('tfoot');
|
22
|
+
if ( !jTFoot.length ) jTFoot = $('<tfoot></tfoot>').appendTo(jTable);
|
23
|
+
var jRow = $('<tr></tr>').appendTo(jTFoot);
|
24
|
+
$('<td colspan="' + jTable.find('thead th').length + '" class="border-bottom"></td>').appendTo(jRow)
|
25
|
+
.append('<div class="corner-wrapper"><div class="corner left"></div><div class="corner right"></div></div>');
|
26
|
+
} )
|
27
|
+
.addClass('decorated')
|
28
|
+
.tablesorter(ts_initData);
|
29
|
+
jTables.filter('.checkable').tablesorter({headers: { 0: { sorter: false}}})
|
30
|
+
.find('thead th.first-child').removeClass('header')
|
31
|
+
.find('.bullet-wrapper').remove();
|
32
|
+
return jTables.length;
|
33
|
+
}
|
34
|
+
|
35
|
+
$('table.checkable thead th:first input:checkbox').live('change', function () {
|
36
|
+
var jThis = $(this),
|
37
|
+
jTable = jThis.closest('table.checkable'),
|
38
|
+
jCheckboxes = jTable.find('tbody input:checkbox');
|
39
|
+
jCheckboxes.prop('checked', jThis.prop('checked'));
|
40
|
+
refresh_states(jTable);
|
41
|
+
} );
|
42
|
+
|
43
|
+
$('table.checkable tbody td:first-child input:checkbox').live('change', function () {
|
44
|
+
var jTable = $(this).closest('table.checkable');
|
45
|
+
jTable.find('input:checkbox#select_all').prop('checked', jTable.find('tbody input:checkbox:not(:checked)').length === 0);
|
46
|
+
refresh_states(jTable);
|
47
|
+
} );
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
$( function () {
|
52
|
+
|
53
|
+
if ( $.tablesorter ) {
|
54
|
+
$.tablesorter.defaults.widgets = ['zebra'];
|
55
|
+
}
|
56
|
+
|
57
|
+
//decor_tables($('body'));
|
58
|
+
|
59
|
+
} );
|
@@ -0,0 +1,98 @@
|
|
1
|
+
( ( $ ) ->
|
2
|
+
|
3
|
+
# ========= max & min =========
|
4
|
+
$('input:text[data-gte], input:text[data-lte]').live 'change focusout blur', ->
|
5
|
+
jField = $ @
|
6
|
+
realValue = jField.val()
|
7
|
+
if realValue isnt ''
|
8
|
+
min = parseFloat jField.data('gte')
|
9
|
+
max = parseFloat jField.data('lte')
|
10
|
+
oldValue = parseFloat realValue
|
11
|
+
v = oldValue
|
12
|
+
v = 0 if isNaN v
|
13
|
+
v = min if not isNaN(min) and v < min
|
14
|
+
v = max if not isNaN(max) and v > max
|
15
|
+
jField.val(v).change() unless v is oldValue
|
16
|
+
|
17
|
+
$.fn.setFieldBounds = (min, max) ->
|
18
|
+
@filter('input:text')
|
19
|
+
.attr
|
20
|
+
'data-gte': min
|
21
|
+
'data-lte': max
|
22
|
+
.data
|
23
|
+
'gte': min
|
24
|
+
'lte': max
|
25
|
+
|
26
|
+
# ========= regexpMask =========
|
27
|
+
|
28
|
+
$.regexp = {} unless $.regexp
|
29
|
+
$.regexp.typedField =
|
30
|
+
'integer' : /^$|^\d+$/
|
31
|
+
'float' : /^$|^\d+(\.\d*)?$/
|
32
|
+
'currency' : /^$|^\d+(\.\d{0,2})?$/
|
33
|
+
'text' : /^.*$/
|
34
|
+
|
35
|
+
$.fn.getRegExpMask = ->
|
36
|
+
mask = @data 'regexpMask'
|
37
|
+
if _.isString(mask)
|
38
|
+
try
|
39
|
+
mask = new RegExp mask
|
40
|
+
@data 'regexpMask', mask
|
41
|
+
catch e
|
42
|
+
# nop
|
43
|
+
else
|
44
|
+
dataType = @data 'dataType'
|
45
|
+
mask = $.regexp.typedField[dataType] if dataType
|
46
|
+
unless mask
|
47
|
+
@val 'unknown dataType'
|
48
|
+
mask = $.regexp.typedField['text']
|
49
|
+
mask
|
50
|
+
|
51
|
+
$.fn.dropRegExpMask = ->
|
52
|
+
@
|
53
|
+
.removeAttr('data-regexp-mask')
|
54
|
+
.removeData('regexpMask')
|
55
|
+
.removeData('value')
|
56
|
+
|
57
|
+
$.fn.setRegExpMask = (mask) ->
|
58
|
+
stringMask = 'true'
|
59
|
+
if _.isString mask
|
60
|
+
stringMask = mask
|
61
|
+
try
|
62
|
+
mask = new RegExp mask
|
63
|
+
catch e
|
64
|
+
# nop
|
65
|
+
if _.isRegExp mask
|
66
|
+
@
|
67
|
+
.dropRegExpMask()
|
68
|
+
.attr('data-regexp-mask', stringMask)
|
69
|
+
.data('regexpMask', mask)
|
70
|
+
.change()
|
71
|
+
@
|
72
|
+
|
73
|
+
$.fn.observeTypedFields = (selector = 'input:text[data-data-type], input:text[data-regexp-mask]') ->
|
74
|
+
return @ unless @length
|
75
|
+
|
76
|
+
@on 'keypress', selector, (event) ->
|
77
|
+
if event.metaKey
|
78
|
+
$(@).trigger 'paste', arguments
|
79
|
+
return true
|
80
|
+
return true unless event.charCode
|
81
|
+
jThis = $ @
|
82
|
+
oldValue = jThis.val()
|
83
|
+
newValue = oldValue.substring(0, @selectionStart) + String.fromCharCode(event.charCode) + oldValue.substring(@selectionEnd)
|
84
|
+
return false unless jThis.getRegExpMask().test(newValue)
|
85
|
+
jThis.data 'value', newValue
|
86
|
+
|
87
|
+
@on 'change', selector, ->
|
88
|
+
jThis = $ @
|
89
|
+
if jThis.getRegExpMask().test(jThis.val())
|
90
|
+
jThis.data 'value', jThis.val()
|
91
|
+
else
|
92
|
+
jThis.val jThis.data('value')
|
93
|
+
|
94
|
+
@on 'paste drop', selector, ->
|
95
|
+
jThis = $ @
|
96
|
+
setTimeout ( -> jThis.trigger 'change', arguments ), 100
|
97
|
+
|
98
|
+
)( jQuery )
|