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,175 @@
|
|
1
|
+
// Underscore.inflection.js
|
2
|
+
// (c) 2011 Jeremy Ruppel
|
3
|
+
// Underscore.inflection is freely distributable under the MIT license.
|
4
|
+
// Portions of Underscore.inflection are inspired or borrowed from ActiveSupport
|
5
|
+
// Version 1.0.0
|
6
|
+
|
7
|
+
( function( _, undefined )
|
8
|
+
{
|
9
|
+
/**
|
10
|
+
* Inflector
|
11
|
+
*/
|
12
|
+
var inflector = {
|
13
|
+
|
14
|
+
plurals : [ ],
|
15
|
+
|
16
|
+
singulars : [ ],
|
17
|
+
|
18
|
+
uncountables : [ ],
|
19
|
+
|
20
|
+
gsub : function( word, rule, replacement )
|
21
|
+
{
|
22
|
+
var pattern = new RegExp( rule.source || rule, 'gi' );
|
23
|
+
|
24
|
+
return pattern.test( word ) ? word.replace( pattern, replacement ) : null;
|
25
|
+
},
|
26
|
+
|
27
|
+
plural : function( rule, replacement )
|
28
|
+
{
|
29
|
+
this.plurals.unshift( [ rule, replacement ] );
|
30
|
+
},
|
31
|
+
|
32
|
+
pluralize : function( word, count, includeNumber )
|
33
|
+
{
|
34
|
+
var result;
|
35
|
+
|
36
|
+
if( count !== undefined )
|
37
|
+
{
|
38
|
+
result = ( count === 1 ) ? this.singularize( word ) : this.pluralize( word );
|
39
|
+
result = ( includeNumber ) ? [ count, result ].join( ' ' ) : result;
|
40
|
+
}
|
41
|
+
else
|
42
|
+
{
|
43
|
+
if( _( this.uncountables ).include( word ) )
|
44
|
+
{
|
45
|
+
return word;
|
46
|
+
}
|
47
|
+
|
48
|
+
result = word;
|
49
|
+
|
50
|
+
_( this.plurals ).detect( function( rule )
|
51
|
+
{
|
52
|
+
var gsub = this.gsub( word, rule[ 0 ], rule[ 1 ] );
|
53
|
+
|
54
|
+
return gsub ? ( result = gsub ) : false;
|
55
|
+
},
|
56
|
+
this );
|
57
|
+
}
|
58
|
+
|
59
|
+
return result;
|
60
|
+
},
|
61
|
+
|
62
|
+
singular : function( rule, replacement )
|
63
|
+
{
|
64
|
+
this.singulars.unshift( [ rule, replacement ] );
|
65
|
+
},
|
66
|
+
|
67
|
+
singularize : function( word )
|
68
|
+
{
|
69
|
+
if( _( this.uncountables ).include( word ) )
|
70
|
+
{
|
71
|
+
return word;
|
72
|
+
}
|
73
|
+
|
74
|
+
var result = word;
|
75
|
+
|
76
|
+
_( this.singulars ).detect( function( rule )
|
77
|
+
{
|
78
|
+
var gsub = this.gsub( word, rule[ 0 ], rule[ 1 ] );
|
79
|
+
|
80
|
+
return gsub ? ( result = gsub ) : false;
|
81
|
+
},
|
82
|
+
this );
|
83
|
+
|
84
|
+
return result;
|
85
|
+
},
|
86
|
+
|
87
|
+
irregular : function( singular, plural )
|
88
|
+
{
|
89
|
+
this.plural( singular, plural );
|
90
|
+
this.singular( plural, singular );
|
91
|
+
},
|
92
|
+
|
93
|
+
uncountable : function( word )
|
94
|
+
{
|
95
|
+
this.uncountables.unshift( word );
|
96
|
+
},
|
97
|
+
|
98
|
+
resetInflections : function( )
|
99
|
+
{
|
100
|
+
this.plurals = [ ];
|
101
|
+
this.singulars = [ ];
|
102
|
+
this.uncountables = [ ];
|
103
|
+
|
104
|
+
this.plural( /$/, 's' );
|
105
|
+
this.plural( /s$/, 's' );
|
106
|
+
this.plural( /(ax|test)is$/, '$1es' );
|
107
|
+
this.plural( /(octop|vir)us$/, '$1i' );
|
108
|
+
this.plural( /(octop|vir)i$/, '$1i' );
|
109
|
+
this.plural( /(alias|status)$/, '$1es' );
|
110
|
+
this.plural( /(bu)s$/, '$1ses' );
|
111
|
+
this.plural( /(buffal|tomat)o$/, '$1oes' );
|
112
|
+
this.plural( /([ti])um$/, '$1a' );
|
113
|
+
this.plural( /([ti])a$/, '$1a' );
|
114
|
+
this.plural( /sis$/, 'ses' );
|
115
|
+
this.plural( /(?:([^f])fe|([lr])f)$/, '$1$2ves' );
|
116
|
+
this.plural( /(hive)$/, '$1s' );
|
117
|
+
this.plural( /([^aeiouy]|qu)y$/, '$1ies' );
|
118
|
+
this.plural( /(x|ch|ss|sh)$/, '$1es' );
|
119
|
+
this.plural( /(matr|vert|ind)(?:ix|ex)$/, '$1ices' );
|
120
|
+
this.plural( /([m|l])ouse$/, '$1ice' );
|
121
|
+
this.plural( /([m|l])ice$/, '$1ice' );
|
122
|
+
this.plural( /^(ox)$/, '$1en' );
|
123
|
+
this.plural( /^(oxen)$/, '$1' );
|
124
|
+
this.plural( /(quiz)$/, '$1zes' );
|
125
|
+
|
126
|
+
this.singular( /s$/, '' );
|
127
|
+
this.singular( /(n)ews$/, '$1ews' );
|
128
|
+
this.singular( /([ti])a$/, '$1um' );
|
129
|
+
this.singular( /((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/, '$1$2sis' );
|
130
|
+
this.singular( /(^analy)ses$/, '$1sis' );
|
131
|
+
this.singular( /([^f])ves$/, '$1fe' );
|
132
|
+
this.singular( /(hive)s$/, '$1' );
|
133
|
+
this.singular( /(tive)s$/, '$1' );
|
134
|
+
this.singular( /([lr])ves$/, '$1f' );
|
135
|
+
this.singular( /([^aeiouy]|qu)ies$/, '$1y' );
|
136
|
+
this.singular( /(s)eries$/, '$1eries' );
|
137
|
+
this.singular( /(m)ovies$/, '$1ovie' );
|
138
|
+
this.singular( /(x|ch|ss|sh)es$/, '$1' );
|
139
|
+
this.singular( /([m|l])ice$/, '$1ouse' );
|
140
|
+
this.singular( /(bus)es$/, '$1' );
|
141
|
+
this.singular( /(o)es$/, '$1' );
|
142
|
+
this.singular( /(shoe)s$/, '$1' );
|
143
|
+
this.singular( /(cris|ax|test)es$/, '$1is' );
|
144
|
+
this.singular( /(octop|vir)i$/, '$1us' );
|
145
|
+
this.singular( /(alias|status)es$/, '$1' );
|
146
|
+
this.singular( /^(ox)en/, '$1' );
|
147
|
+
this.singular( /(vert|ind)ices$/, '$1ex' );
|
148
|
+
this.singular( /(matr)ices$/, '$1ix' );
|
149
|
+
this.singular( /(quiz)zes$/, '$1' );
|
150
|
+
this.singular( /(database)s$/, '$1' );
|
151
|
+
|
152
|
+
this.irregular( 'person', 'people' );
|
153
|
+
this.irregular( 'man', 'men' );
|
154
|
+
this.irregular( 'child', 'children' );
|
155
|
+
this.irregular( 'sex', 'sexes' );
|
156
|
+
this.irregular( 'move', 'moves' );
|
157
|
+
this.irregular( 'cow', 'kine' );
|
158
|
+
|
159
|
+
_( 'equipment information rice money species series fish sheep jeans'.split( /\s+/ ) ).each( function( word )
|
160
|
+
{
|
161
|
+
this.uncountable( word );
|
162
|
+
},
|
163
|
+
this );
|
164
|
+
|
165
|
+
return this;
|
166
|
+
}
|
167
|
+
|
168
|
+
};
|
169
|
+
|
170
|
+
/**
|
171
|
+
* Underscore integration
|
172
|
+
*/
|
173
|
+
_.mixin( inflector.resetInflections( ) );
|
174
|
+
|
175
|
+
} )( _ );
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class FuzzyJsonGenerator
|
2
|
+
|
3
|
+
@idCounter: 0
|
4
|
+
|
5
|
+
constructor: ->
|
6
|
+
# nop
|
7
|
+
|
8
|
+
nextId: ->
|
9
|
+
@constructor.idCounter++
|
10
|
+
|
11
|
+
# overload this method
|
12
|
+
generateOne: ->
|
13
|
+
id: @nextId()
|
14
|
+
|
15
|
+
generateMany: (count, base = 0) ->
|
16
|
+
count = @getRandom(count, base) if base > 0
|
17
|
+
@generateOne() for i in [0..count]
|
18
|
+
|
19
|
+
getRandom: (arrayOrCount, base = 0) ->
|
20
|
+
rand = Math.random()
|
21
|
+
if _.isArray arrayOrCount
|
22
|
+
arrayOrCount[Math.floor rand * arrayOrCount.length]
|
23
|
+
else if _.isNumber arrayOrCount
|
24
|
+
base + Math.floor rand * arrayOrCount
|
25
|
+
else
|
26
|
+
rand
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
@Generators ||= {}
|
31
|
+
|
32
|
+
class Generators.Offers extends FuzzyJsonGenerator
|
33
|
+
|
34
|
+
citiesFrom: ['Москва', 'Воронеж', 'Санкт-Петербург']
|
35
|
+
citiesTo: ['Хошимин', 'Брюссель', 'Лондон', 'Нью-Йорк', 'Париж', 'Мадрид', 'Берлин']
|
36
|
+
|
37
|
+
generateOne: ->
|
38
|
+
fromDate = new Date
|
39
|
+
fromDate.setTime(fromDate.getTime() + 1000 * 60 * 60 * 24 * @getRandom(30))
|
40
|
+
toDate = new Date
|
41
|
+
toDate.setTime(fromDate.getTime() + 1000 * 60 * 60 * 24 * @getRandom(30))
|
42
|
+
id: @nextId()
|
43
|
+
city_from : @getRandom(@citiesFrom)
|
44
|
+
city_to : @getRandom(@citiesTo)
|
45
|
+
date_from : Globalize.format(fromDate, "yyyy-MM-dd")
|
46
|
+
date_to : Globalize.format(toDate, "yyyy-MM-dd")
|
47
|
+
price : @getRandom(20000, 5000)
|
48
|
+
hot : @getRandom(2) is 1
|
@@ -0,0 +1,63 @@
|
|
1
|
+
@compact = (arr) ->
|
2
|
+
@deprecate 'compact(arr)', '_.compact arr'
|
3
|
+
r = []
|
4
|
+
for e in arr
|
5
|
+
r.push e if e?
|
6
|
+
r
|
7
|
+
|
8
|
+
@reverse = (arr) =>
|
9
|
+
@deprecate 'reverse(arr)', 'arr.reverse()'
|
10
|
+
_isString = _.isString arr
|
11
|
+
return arr unless _isString or $.isArray arr
|
12
|
+
if _isString then @warning 'reverse(someString)', 'STOP USE IT!' else arr.reverse()
|
13
|
+
|
14
|
+
###
|
15
|
+
Split array into slices of <number> elements.
|
16
|
+
Map result by iterator if last given.
|
17
|
+
|
18
|
+
>>> eachSlice [1..10], 3, (a) -> cout a
|
19
|
+
[1, 2, 3]
|
20
|
+
[4, 5, 6]
|
21
|
+
[7, 8, 9]
|
22
|
+
[10]
|
23
|
+
###
|
24
|
+
@eachSlice = (array, number, iterator = null) =>
|
25
|
+
size = array.length
|
26
|
+
index = 0
|
27
|
+
slices = []
|
28
|
+
while index < size
|
29
|
+
nextIndex = index + number
|
30
|
+
slices.push array.slice(index, nextIndex)
|
31
|
+
index = nextIndex
|
32
|
+
if _.isFunction iterator then _.map slices, iterator else slices
|
33
|
+
|
34
|
+
###
|
35
|
+
Splits or iterates over the array in groups of size +number+,
|
36
|
+
padding any remaining slots with +fill_with+ unless it is +false+.
|
37
|
+
|
38
|
+
>>> inGroupsOf [1..7], 3, (group) -> cout group
|
39
|
+
[1, 2, 3]
|
40
|
+
[4, 5, 6]
|
41
|
+
[7, null, null]
|
42
|
+
|
43
|
+
>>> inGroupsOf [1..3], 2, ' ', (group) -> cout group
|
44
|
+
[1, 2]
|
45
|
+
[3, " "]
|
46
|
+
|
47
|
+
>>> inGroupsOf [1..3], 2, false, (group) -> cout group
|
48
|
+
[1, 2]
|
49
|
+
[3]
|
50
|
+
###
|
51
|
+
@inGroupsOf = (array, number, fillWith = null) =>
|
52
|
+
return array if number < 1
|
53
|
+
iterator = @blockGiven arguments
|
54
|
+
unless fillWith is false
|
55
|
+
# size % number gives how many extra we have;
|
56
|
+
# subtracting from number gives how many to add;
|
57
|
+
# modulo number ensures we don't add group of just fill.
|
58
|
+
padding = (number - array.length % number) % number
|
59
|
+
if padding
|
60
|
+
fillWith = null if _.isFunction fillWith
|
61
|
+
array = array.slice()
|
62
|
+
array.push fillWith while padding-- > 0
|
63
|
+
@eachSlice array, number, iterator
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
@is_uri = (path) ->
|
3
|
+
/^[-a-z]+:\/\/|^cid:|^\/\//.test path
|
4
|
+
|
5
|
+
@without_extension = (source) ->
|
6
|
+
source.replace /^(.+)(\.\w+)$/, '$1'
|
7
|
+
|
8
|
+
@rewrite_extension = (source, ext) =>
|
9
|
+
"#{@without_extension source}.#{ext}"
|
10
|
+
|
11
|
+
@ASSET_ID = ''
|
12
|
+
@asset_ids_cache = {}
|
13
|
+
# Use the ASSET_ID inscope variable or the random hash as its cache-busting asset id.
|
14
|
+
@asset_id = (source) =>
|
15
|
+
if _.isString @ASSET_ID
|
16
|
+
@ASSET_ID
|
17
|
+
else
|
18
|
+
@asset_ids_cache[source] or (@asset_ids_cache[source] = 10000000 + Math.floor(Math.random() * 90000000))
|
19
|
+
|
20
|
+
# Break out the asset path rewrite in case plugins wish to put the asset id
|
21
|
+
# someplace other than the query string.
|
22
|
+
@rewrite_asset_path = (source, dir) =>
|
23
|
+
source = "/#{dir}/#{source}" unless source[0] is '/'
|
24
|
+
if id = @asset_id(source)
|
25
|
+
"#{source}?#{id}"
|
26
|
+
else
|
27
|
+
source
|
28
|
+
|
29
|
+
@rewrite_relative_url_root = (source, relative_url_root) ->
|
30
|
+
if relative_url_root and not _.startsWith(source, "#{relative_url_root}/")
|
31
|
+
"#{relative_url_root}#{source}"
|
32
|
+
else
|
33
|
+
source
|
34
|
+
|
35
|
+
@RELATIVE_URL_ROOT = ''
|
36
|
+
|
37
|
+
@compute_public_path = (source, dir, options = {}) =>
|
38
|
+
return source if is_uri(source)
|
39
|
+
source = @rewrite_extension(source, options['ext']) if options['ext']
|
40
|
+
source = @rewrite_asset_path(source, dir)
|
41
|
+
source = @rewrite_relative_url_root(source, @RELATIVE_URL_ROOT)
|
42
|
+
source
|
43
|
+
|
44
|
+
@image_path = (source) =>
|
45
|
+
@compute_public_path(source, 'images')
|
46
|
+
|
47
|
+
@path_to_image = @image_path # aliased to avoid conflicts with an image_path named route
|
48
|
+
|
49
|
+
@basename = (source) =>
|
50
|
+
source = matches[2] if matches = source.match /^(.*\/)?(.+)?$/
|
51
|
+
|
52
|
+
@image_alt = (src) =>
|
53
|
+
_.capitalize @without_extension(@basename(src))
|
54
|
+
|
55
|
+
@image_tag = (source, options = {}) =>
|
56
|
+
src = options['src'] = @path_to_image source
|
57
|
+
unless options['alt'] or /^cid:/.test src
|
58
|
+
options['alt'] = @image_alt(src)
|
59
|
+
if size = _delete(options, 'size')
|
60
|
+
if matches = size.match /^(\d+)x(\d+)$/
|
61
|
+
options['width'] = matches[1]
|
62
|
+
options['height'] = matches[2]
|
63
|
+
tag 'img', options
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@g_decor_body = (tag, inner) =>
|
2
|
+
@content_tag(tag, '', class: 'left') +
|
3
|
+
@content_tag(tag, '', class: 'right') +
|
4
|
+
@content_tag(tag, inner, class: 'fill')
|
5
|
+
|
6
|
+
@g_star_decor_body = (tag, inner) =>
|
7
|
+
@content_tag(tag, inner, class: 'wrapper') +
|
8
|
+
@content_tag(tag, '', class: 'corner left top') +
|
9
|
+
@content_tag(tag, '', class: 'corner right top') +
|
10
|
+
@content_tag(tag, '', class: 'corner left bottom') +
|
11
|
+
@content_tag(tag, '', class: 'corner right bottom')
|
12
|
+
|
13
|
+
@g_wrapper_decor_body = (tag, inner) =>
|
14
|
+
@content_tag tag, inner, class: 'wrapper'
|
File without changes
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# The DOM class convention is to use the singular form of an object or class. Examples:
|
2
|
+
#
|
3
|
+
# dom_class(post) # => "post"
|
4
|
+
# dom_class(Person) # => "person"
|
5
|
+
#
|
6
|
+
# If you need to address multiple instances of the same class in the same view, you can prefix the dom_class:
|
7
|
+
#
|
8
|
+
# dom_class(post, :edit) # => "edit_post"
|
9
|
+
# dom_class(Person, :edit) # => "edit_person"
|
10
|
+
@dom_class = (record_or_class, prefix = "") ->
|
11
|
+
singular = _.singular(record_or_class)
|
12
|
+
if prefix then "#{prefix}_#{singular}" else singular
|
13
|
+
|
14
|
+
# The DOM id convention is to use the singular form of an object or class with the id following an underscore.
|
15
|
+
# If no id is found, prefix with "new_" instead. Examples:
|
16
|
+
#
|
17
|
+
# dom_id(Post.find(45)) # => "post_45"
|
18
|
+
# dom_id(Post.new) # => "new_post"
|
19
|
+
#
|
20
|
+
# If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
|
21
|
+
#
|
22
|
+
# dom_id(Post.find(45), :edit) # => "edit_post_45"
|
23
|
+
# TODO sync with rorId and ror_id
|
24
|
+
@dom_id = (record, prefix = "") =>
|
25
|
+
if record_id = @record_key_for_dom_id(record)
|
26
|
+
"#{@dom_class(record, prefix)}_#{record_id}"
|
27
|
+
else
|
28
|
+
@dom_class(record, prefix or "new")
|
29
|
+
|
30
|
+
@record_key_for_dom_id = (record) ->
|
31
|
+
record = record.to_model() if _.isFunction(record.to_model)
|
32
|
+
key = record.to_key()
|
33
|
+
if key then key.join("_") else key
|
34
|
+
|
35
|
+
# TODO more zen features: +, *x, {content}
|
36
|
+
# TODO cache
|
37
|
+
@selectorToHtml = (selector) =>
|
38
|
+
if matches = selector.match(/^[\s>]*([\w\.]+)(.*)$/)
|
39
|
+
selector = matches[1]
|
40
|
+
continuation = matches[2]
|
41
|
+
classes = selector.split(".")
|
42
|
+
tag_name = classes.shift() or "div"
|
43
|
+
html_options = {}
|
44
|
+
html_options["class"] = classes.join(" ") if classes.length
|
45
|
+
if continuation
|
46
|
+
@content_tag(tag_name, @selectorToHtml(continuation), html_options)
|
47
|
+
else
|
48
|
+
@tag(tag_name, html_options)
|
49
|
+
else
|
50
|
+
""
|
51
|
+
|
52
|
+
@concat_class = =>
|
53
|
+
@warning "concat_class()", "refactoring with underscore"
|
54
|
+
@uniq(@compact(arguments).join(" ").split(/\s+/)).join(" ")
|
55
|
+
|
56
|
+
@html_options_to_s = (html_options) =>
|
57
|
+
if $.isPlainObject(html_options)
|
58
|
+
(" #{key}=\"#{value}\"" for key, value of html_options when typeof value isnt "undefined").join("")
|
59
|
+
else
|
60
|
+
""
|
61
|
+
|
62
|
+
@tag = (tag_name, html_options = {}) =>
|
63
|
+
"<#{tag_name}#{@html_options_to_s html_options} />"
|
64
|
+
|
65
|
+
@content_tag = (tag_name, content, html_options) =>
|
66
|
+
"<#{tag_name}#{@html_options_to_s html_options}>#{content}</#{tag_name}>"
|
67
|
+
|
68
|
+
@link_to = (body, url, html_options = {}) =>
|
69
|
+
html_options["href"] = url
|
70
|
+
@content_tag("a", body, html_options)
|
@@ -0,0 +1,149 @@
|
|
1
|
+
###
|
2
|
+
* front-end js helpers
|
3
|
+
* 0.3.3.alpha / 2010-2011
|
4
|
+
* Karpunin Dmitry / Evrone.com
|
5
|
+
* koderfunk_at_gmail_dot_com
|
6
|
+
###
|
7
|
+
|
8
|
+
@DEBUG_MODE ?= false
|
9
|
+
@TEST_MODE ?= false
|
10
|
+
@WARNINGS ?= true
|
11
|
+
|
12
|
+
@cout = =>
|
13
|
+
args = @args arguments
|
14
|
+
method = if args[0] in ['log', 'info', 'warn', 'error', 'assert', 'clear'] then args.shift() else 'log'
|
15
|
+
if @DEBUG_MODE and console?
|
16
|
+
method = console[method]
|
17
|
+
if method.apply?
|
18
|
+
method.apply console, args
|
19
|
+
else
|
20
|
+
method args
|
21
|
+
return args[0]
|
22
|
+
|
23
|
+
@_cout = =>
|
24
|
+
console.log arguments if console?
|
25
|
+
arguments[0]
|
26
|
+
|
27
|
+
@deprecate = (subject, instead = null) =>
|
28
|
+
@cout 'warn', "\"#{subject}\" DEPRECATED!" + if instead then " Use instead: \"#{instead}\"" else ''
|
29
|
+
return
|
30
|
+
|
31
|
+
@warning = (subject, instead = null) =>
|
32
|
+
if @WARNINGS
|
33
|
+
@cout 'warn', "\"#{subject}\" WARNING!" + if instead then " Use instead: \"#{instead}\"" else ''
|
34
|
+
return
|
35
|
+
|
36
|
+
@args = (a) ->
|
37
|
+
r = []
|
38
|
+
Array::push.apply r, a if a.length > 0
|
39
|
+
r
|
40
|
+
|
41
|
+
@blockGiven = (args) =>
|
42
|
+
l = args.length
|
43
|
+
if l
|
44
|
+
l = args[l - 1]
|
45
|
+
if _.isFunction l then l else false
|
46
|
+
else
|
47
|
+
false
|
48
|
+
|
49
|
+
@_delete = (object, key) ->
|
50
|
+
value = object[key]
|
51
|
+
delete object[key]
|
52
|
+
value
|
53
|
+
|
54
|
+
# Helper function to get a value from a object as a property or as a function.
|
55
|
+
@getValue = (object, prop) ->
|
56
|
+
return null unless object and object[prop]
|
57
|
+
return if _.isFunction(object[prop]) then object[prop]() else object[prop]
|
58
|
+
|
59
|
+
@isset = (obj) =>
|
60
|
+
@deprecate 'isset(obj)', 'obj isnt undefined" OR "obj?'
|
61
|
+
obj isnt undefined
|
62
|
+
|
63
|
+
@isString = (v) =>
|
64
|
+
@deprecate 'isString(v)', '_.isString v'
|
65
|
+
_.isString v
|
66
|
+
|
67
|
+
@isNumber = (v) =>
|
68
|
+
@deprecate 'isNumber(v)', '_.isNumber v'
|
69
|
+
not isNaN parseInt v
|
70
|
+
|
71
|
+
@isJQ = (obj) ->
|
72
|
+
@deprecate 'isJQ(obj)', 'obj instanceof jQuery'
|
73
|
+
_.isObject(obj) and _.isString obj.jquery
|
74
|
+
|
75
|
+
@uniq = (arrOrString) ->
|
76
|
+
@deprecate 'uniq(a)', '_.uniq a'
|
77
|
+
isStr = _.isString arrOrString
|
78
|
+
return arrOrString unless isStr or _.isArray arrOrString
|
79
|
+
r = []
|
80
|
+
r.push e for e in arrOrString when not _.include r, e
|
81
|
+
if isStr then r.join '' else r
|
82
|
+
|
83
|
+
@logicalXOR = (a, b) ->
|
84
|
+
( a and not b ) or ( not a and b )
|
85
|
+
|
86
|
+
@bound = (number, min, max) ->
|
87
|
+
Math.max min, Math.min number, max
|
88
|
+
|
89
|
+
@roundWithPrecision = (number, precision = 2) ->
|
90
|
+
precision = Math.pow 10, precision
|
91
|
+
Math.round(number * precision) / precision
|
92
|
+
|
93
|
+
@regexpSpace = new RegExp '^\\s*$'
|
94
|
+
@regexpTrim = new RegExp '^\\s*(.*?)\\s*$'
|
95
|
+
|
96
|
+
@strTrim = (s) =>
|
97
|
+
@deprecate "strTrim(s)", "$.trim(s)"
|
98
|
+
s.match(@regexpTrim)[1]
|
99
|
+
|
100
|
+
# !!!!!!!!!!! tags !!!!!!!!!!!!
|
101
|
+
|
102
|
+
@number_to_currency = (number, units) ->
|
103
|
+
precision = 2
|
104
|
+
s = parseFloat(number).toFixed precision
|
105
|
+
b = s.length - 1 - precision
|
106
|
+
r = s.substring b
|
107
|
+
while b > 0
|
108
|
+
a = b - 3
|
109
|
+
r = ' ' + s.substring(a, b) + r
|
110
|
+
b = a
|
111
|
+
"#{r.substring(1)} #{units}"
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
@getParams = ->
|
116
|
+
q = location.search.substring(1).split '&'
|
117
|
+
r = {}
|
118
|
+
for e in q
|
119
|
+
t = e.split '='
|
120
|
+
r[t[0]] = t[1]
|
121
|
+
r
|
122
|
+
|
123
|
+
@respondFormat = (url, format = null) ->
|
124
|
+
aq = url.split '?'
|
125
|
+
ah = aq[0].split '#'
|
126
|
+
ad = ah[0].split '.'
|
127
|
+
currentFormat = if ad.length > 1 and not /\//.test(ad[ad.length - 1]) then ad.pop() else ''
|
128
|
+
return currentFormat unless format?
|
129
|
+
return url if format is currentFormat
|
130
|
+
ad.push format if format
|
131
|
+
ah[0] = ad.join '.'
|
132
|
+
aq[0] = ah.join '#'
|
133
|
+
aq.join '?'
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
@rails_data = {}
|
138
|
+
|
139
|
+
@rails_scope = (controller_name, action_name, scopedCloasure = null, scopedCloasureArguments...) =>
|
140
|
+
return false if _.isString(controller_name) and controller_name isnt @rails_data['controller_name']
|
141
|
+
return false if _.isString(action_name) and action_name isnt @rails_data['action_name']
|
142
|
+
if _.isFunction scopedCloasure
|
143
|
+
arguments[2] scopedCloasureArguments...
|
144
|
+
true
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
$ =>
|
149
|
+
@rails_data = $('body').data()
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
@unlazy_datepickers = (jRoot) ->
|
3
|
+
jRoot.find('input.datepicker.lazy').removeClass('lazy').length
|
4
|
+
|
5
|
+
@bind_datepickers = (jRoot) ->
|
6
|
+
jRoot.find('input.datepicker:not(.lazy, .hasDatepicker)').each( ->
|
7
|
+
jThis = $ @
|
8
|
+
opts =
|
9
|
+
'showAnim' : ''
|
10
|
+
'showOn' : 'both'
|
11
|
+
'buttonImage' : '/images/forms/datepicker__icon.png' # TODO forwarding assets path
|
12
|
+
'buttonImageOnly': true
|
13
|
+
'changeMonth' : true
|
14
|
+
'changeYear' : true
|
15
|
+
'onClose' : (dateText, inst) -> $(inst.input).change().focusout()
|
16
|
+
opts[_.camelize(k)] = d for k, d of jThis.data()
|
17
|
+
jThis.datepicker opts
|
18
|
+
).length
|
19
|
+
|
20
|
+
$.fn.orig_datepicker = $.fn.datepicker
|
21
|
+
|
22
|
+
$.fn.datepicker = ->
|
23
|
+
return @ unless @length
|
24
|
+
@data('changed', true) if arguments.length and arguments[0] is 'setDate'
|
25
|
+
$.fn.orig_datepicker.apply @, arguments
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
$ ->
|
30
|
+
|
31
|
+
$('body').on 'keyup keydown', 'input.datepicker.hasDatepicker', ->
|
32
|
+
$(@).datepicker 'hide'
|
33
|
+
|
34
|
+
bind_datepickers $('body')
|