ultimate-base 0.2.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/.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,25 @@
|
|
1
|
+
Backbone.Ultimate ||= {}
|
2
|
+
|
3
|
+
class Backbone.Ultimate.App
|
4
|
+
@App: null
|
5
|
+
|
6
|
+
name: null
|
7
|
+
|
8
|
+
Models: {}
|
9
|
+
Collections: {}
|
10
|
+
Routers: {}
|
11
|
+
Views: {}
|
12
|
+
|
13
|
+
scopes: ["Models", "Collections", "Routers", "Views"]
|
14
|
+
|
15
|
+
constructor: (name = null) ->
|
16
|
+
if @constructor.App
|
17
|
+
throw new Error("Can't create new Backbone.Ultimate.App because the single instance has already been created");
|
18
|
+
else
|
19
|
+
@constructor.App = @
|
20
|
+
@name = name
|
21
|
+
_.extend @[scope], Backbone.Events for scope in @scopes
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
_.extend Backbone.Ultimate.App::, Backbone.Events
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Backbone.Ultimate ||= {}
|
2
|
+
|
3
|
+
class Backbone.Ultimate.Collection extends Backbone.Collection
|
4
|
+
|
5
|
+
ready: (callback, context = @) ->
|
6
|
+
unless @length
|
7
|
+
@readyDeferred ||= $.Deferred()
|
8
|
+
@readyDeferred.done =>
|
9
|
+
callback.apply context, [@]
|
10
|
+
@fetch success: (=> @readyDeferred.resolve()), silent: true
|
11
|
+
else
|
12
|
+
callback.apply context, [@]
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Backbone.Ultimate ||= {}
|
2
|
+
|
3
|
+
class Backbone.Ultimate.Model extends Backbone.Model
|
4
|
+
|
5
|
+
ready: (callback, context = @) ->
|
6
|
+
if _.isEmpty(@attributes)
|
7
|
+
@readyDeferred ||= $.Deferred()
|
8
|
+
@readyDeferred.done =>
|
9
|
+
callback.apply context, [@]
|
10
|
+
@fetch success: (=> @readyDeferred.resolve()), silent: true
|
11
|
+
else
|
12
|
+
callback.apply context, [@]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Backbone.Ultimate ||= {}
|
2
|
+
|
3
|
+
class Backbone.Ultimate.Router extends Backbone.Router
|
4
|
+
|
5
|
+
namedParam = /:\w+/g
|
6
|
+
splatParam = /\*\w+/g
|
7
|
+
escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g
|
8
|
+
|
9
|
+
_routeToRegExp: (route) ->
|
10
|
+
route = route.replace(escapeRegExp, '\\$&')
|
11
|
+
.replace(namedParam, '([^\/]+)')
|
12
|
+
.replace(splatParam, '(.*?)')
|
13
|
+
new RegExp("^\/?#{route}\/?$")
|
@@ -0,0 +1,96 @@
|
|
1
|
+
Backbone.Ultimate ||= {}
|
2
|
+
|
3
|
+
class Backbone.Ultimate.View extends Backbone.View
|
4
|
+
|
5
|
+
viewOptions: []
|
6
|
+
|
7
|
+
loadingState: null
|
8
|
+
loadingWidthMethodName: "innerWidth"
|
9
|
+
loadingHeightMethodName: "innerHeight"
|
10
|
+
loadingStateClass: "loading"
|
11
|
+
loadingOverlayClass: "loading-overlay"
|
12
|
+
|
13
|
+
constructor: ->
|
14
|
+
super
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
# Overload parent method Backbone.View.setElement() as hook for findNodes().
|
19
|
+
setElement: (element, delegate) ->
|
20
|
+
super
|
21
|
+
@findNodes()
|
22
|
+
@
|
23
|
+
|
24
|
+
findNodes: (jRoot = @$el, nodes = @nodes) ->
|
25
|
+
jNodes = {}
|
26
|
+
nodes = nodes() if _.isFunction(nodes)
|
27
|
+
if _.isObject(nodes)
|
28
|
+
for nodeName, selector of nodes
|
29
|
+
_isObject = _.isObject(selector)
|
30
|
+
if _isObject
|
31
|
+
nestedNodes = selector
|
32
|
+
selector = _delete(nestedNodes, "selector")
|
33
|
+
jNodes[nodeName] = @[nodeName] = jRoot.find(selector)
|
34
|
+
if _isObject
|
35
|
+
_.extend jNodes, @findNodes(jNodes[nodeName], nestedNodes)
|
36
|
+
jNodes
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
# Overload and proxy parent method Backbone.View.delegateEvents() as hook for normalizeEvents().
|
41
|
+
delegateEvents: (events) ->
|
42
|
+
args = []
|
43
|
+
Array::push.apply args, arguments if arguments.length > 0
|
44
|
+
args[0] = @normalizeEvents(events)
|
45
|
+
super args...
|
46
|
+
|
47
|
+
# Cached regex to split keys for `delegate`, from backbone.js.
|
48
|
+
delegateEventSplitter = /^(\S+)\s*(.*)$/
|
49
|
+
|
50
|
+
normalizeEvents: (events) ->
|
51
|
+
events = getValue(@, "events") unless events
|
52
|
+
if events
|
53
|
+
normalizedEvents = {}
|
54
|
+
for key, method of events
|
55
|
+
[[], eventName, selector] = key.match(delegateEventSplitter)
|
56
|
+
jObj = @[selector]
|
57
|
+
if jObj instanceof jQuery and _.isString(jObj.selector)
|
58
|
+
key = "#{eventName} #{jObj.selector}"
|
59
|
+
normalizedEvents[key] = method
|
60
|
+
events = normalizedEvents
|
61
|
+
events
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
# Overload parent method Backbone.View._configure() as hook for reflectOptions().
|
66
|
+
_configure: (options) ->
|
67
|
+
super
|
68
|
+
@reflectOptions()
|
69
|
+
|
70
|
+
reflectOptions: (viewOptions = @viewOptions, options = @options) ->
|
71
|
+
@[attr] = options[attr] for attr in viewOptions when options[attr]
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
# Overloadable getter for jQuery-container that will be blocked.
|
76
|
+
getJLoadingContainer: -> @$el
|
77
|
+
|
78
|
+
loading: (state, text = "", circle = true) ->
|
79
|
+
jLoadingContainer = @getJLoadingContainer()
|
80
|
+
if jLoadingContainer and jLoadingContainer.length
|
81
|
+
jLoadingContainer.removeClass @loadingStateClass
|
82
|
+
jLoadingContainer.children(".#{@loadingOverlayClass}").remove()
|
83
|
+
if @loadingState = state
|
84
|
+
jLoadingContainer.addClass @loadingStateClass
|
85
|
+
width = jLoadingContainer[@loadingWidthMethodName]()
|
86
|
+
height = jLoadingContainer[@loadingHeightMethodName]()
|
87
|
+
text = "<span class=\"text\">#{text}</span>" if text
|
88
|
+
circle = "<span class=\"circle\"></span>" if circle
|
89
|
+
style = "width: #{width}px; height: #{height}px; line-height: #{height}px;"
|
90
|
+
jLoadingContainer.append "<div class=\"#{@loadingOverlayClass}\" style=\"#{style}\">#{circle}#{text}</div>"
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
# Improve templating.
|
95
|
+
jst: (name, context = @) ->
|
96
|
+
JST["backbone/templates/#{name}"] context
|
@@ -0,0 +1,103 @@
|
|
1
|
+
###
|
2
|
+
* front-end ui-components routines
|
3
|
+
*
|
4
|
+
* @version 0.5.5.alpha / 2010-2011
|
5
|
+
* @author Karpunin Dmitry / Evrone.com
|
6
|
+
* @email koderfunk_at_gmail_dot_com
|
7
|
+
*
|
8
|
+
* TODO register components
|
9
|
+
* TODO using underscore.js
|
10
|
+
*
|
11
|
+
###
|
12
|
+
|
13
|
+
# TODO do ($ = jQuery) =>
|
14
|
+
( ($) =>
|
15
|
+
|
16
|
+
$.regexp ||= {}
|
17
|
+
|
18
|
+
$.regexp.rorId ||= /(\w+)_(\d+)$/
|
19
|
+
|
20
|
+
@ror_id = (jObjOrString) ->
|
21
|
+
if isJQ jObjOrString
|
22
|
+
id = jObjOrString.data 'rorId'
|
23
|
+
unless id
|
24
|
+
id = jObjOrString.attr 'id'
|
25
|
+
if id
|
26
|
+
matchResult = id.match $.regexp.rorId
|
27
|
+
id = if matchResult then matchResult[2] else ''
|
28
|
+
jObjOrString.data 'rorId', id
|
29
|
+
else
|
30
|
+
id = ''
|
31
|
+
else
|
32
|
+
matchResult = jObjOrString.match $.regexp.rorId
|
33
|
+
id = if matchResult then matchResult[2] else ''
|
34
|
+
id
|
35
|
+
|
36
|
+
$.fn.rorId = ->
|
37
|
+
if arguments.length
|
38
|
+
id = arguments[0]
|
39
|
+
word = 'ror_id'
|
40
|
+
thisId = @attr 'id'
|
41
|
+
if thisId
|
42
|
+
word = matchResult[1] if matchResult = thisId.match $.regexp.rorId
|
43
|
+
@data('rorId', id).attr 'id', word + '_' + id
|
44
|
+
@
|
45
|
+
else
|
46
|
+
ror_id @
|
47
|
+
|
48
|
+
$.fn.getClasses = ->
|
49
|
+
return [] unless @length
|
50
|
+
classAttr = $.trim @attr 'class'
|
51
|
+
if classAttr then classAttr.split(/\s+/) else []
|
52
|
+
|
53
|
+
# Get hash of html-dom attributes from first matched element or false, if no elements
|
54
|
+
$.fn.getAttributes = ->
|
55
|
+
if @length
|
56
|
+
attrs = {}
|
57
|
+
#TRY attrs[attr.nodeName] = attr.nodeValue for attr in this[0].attributes
|
58
|
+
$.each this[0].attributes, (index, attr) ->
|
59
|
+
attrs[attr.nodeName] = attr.nodeValue
|
60
|
+
attrs
|
61
|
+
else
|
62
|
+
false
|
63
|
+
|
64
|
+
# [showOrHide[, duration[, callback]]]
|
65
|
+
$.fn.slideToggleByState = ->
|
66
|
+
if @length
|
67
|
+
if arguments.length > 0
|
68
|
+
a = args arguments
|
69
|
+
if a.shift()
|
70
|
+
@slideDown.apply @, a
|
71
|
+
else
|
72
|
+
@slideUp.apply @, a
|
73
|
+
else
|
74
|
+
@slideToggle()
|
75
|
+
@
|
76
|
+
|
77
|
+
# TODO replace usages to underscore methods and using distribution
|
78
|
+
unless $.isRegExp
|
79
|
+
$.isRegExp = (candidate) ->
|
80
|
+
deprecate '$.isRegExp', '_.isRegExp'
|
81
|
+
typeof candidate is "object" and typeof candidate.test is "function"
|
82
|
+
|
83
|
+
unless $.isBoolean
|
84
|
+
$.isBoolean = (v) ->
|
85
|
+
deprecate '$.isBoolean', '_.isBoolean'
|
86
|
+
typeof v is "boolean"
|
87
|
+
|
88
|
+
unless $.isString
|
89
|
+
$.isString = (v) ->
|
90
|
+
deprecate '$.isString', '_.isString'
|
91
|
+
typeof v is "string"
|
92
|
+
|
93
|
+
unless $.isHTML
|
94
|
+
$.regexp.HTML = new RegExp "^\\s*<(\\w+)[\\S\\s]*</(\\w+)>\\s*$"
|
95
|
+
$.isHTML = (v) ->
|
96
|
+
matches = $.regexp.HTML.exec v
|
97
|
+
matches and matches[1] is matches[2]
|
98
|
+
|
99
|
+
if typeof $.isEmptyString is "undefined"
|
100
|
+
$.isEmptyString = (v) ->
|
101
|
+
regexpSpace.test v
|
102
|
+
|
103
|
+
)( jQuery )
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# TODO bus as class
|
2
|
+
# TODO may be, settable maxInstances
|
3
|
+
# TODO tree presentative logic in eventName syntax provided by ':', '.', ...
|
4
|
+
# require underscore
|
5
|
+
|
6
|
+
class EventBus
|
7
|
+
|
8
|
+
events: {}
|
9
|
+
|
10
|
+
#constructor: ->
|
11
|
+
|
12
|
+
bind: (eventName, callback) ->
|
13
|
+
if @events[eventName]
|
14
|
+
@events[eventName].push callback
|
15
|
+
else
|
16
|
+
@events[eventName] = [callback]
|
17
|
+
true
|
18
|
+
|
19
|
+
# TODO simplify logic
|
20
|
+
unbind: (eventName, callback = null) ->
|
21
|
+
if eventName
|
22
|
+
if eventsHeap = @events[eventName]
|
23
|
+
if callback
|
24
|
+
i = _.indexOf eventsHeap, callback
|
25
|
+
if i >= 0
|
26
|
+
eventsHeap.splice i, 1
|
27
|
+
true
|
28
|
+
else
|
29
|
+
false
|
30
|
+
else
|
31
|
+
delete @events[eventName]
|
32
|
+
else
|
33
|
+
false
|
34
|
+
else
|
35
|
+
if callback
|
36
|
+
# TODO return boolean
|
37
|
+
@unbind eventName, callback for eventName, eventsHeap of @events
|
38
|
+
else
|
39
|
+
false
|
40
|
+
|
41
|
+
has: (eventName, callback = null) ->
|
42
|
+
if eventsHeap = @events[eventName]
|
43
|
+
if callback
|
44
|
+
_.include eventsHeap, callback
|
45
|
+
else
|
46
|
+
true
|
47
|
+
else
|
48
|
+
false
|
49
|
+
|
50
|
+
trigger: (eventName, callbackArguments...) ->
|
51
|
+
for callback in @events[eventName] or []
|
52
|
+
callback.apply(@, callbackArguments)
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
# transitional instance
|
57
|
+
@bus = new EventBus
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$ ->
|
2
|
+
|
3
|
+
jBody = $ 'body'
|
4
|
+
|
5
|
+
# fixes on sessions/new form, because devise don't return errors on fields
|
6
|
+
jBody.on 'ajax:error', 'form.sessions-new', ->
|
7
|
+
$(@).find(':input:visible').filter(-> not @value).closestEdge().setErrors()
|
8
|
+
false
|
9
|
+
|
10
|
+
# if devise form success, then open root path
|
11
|
+
jBody.on 'ajax:success', 'form.user[data-remote="true"]', (event, data, textStatus, jqXHR) ->
|
12
|
+
jForm = $ @
|
13
|
+
if jForm.hasClass('users-new')
|
14
|
+
getWidget('AccountPanel').showConfirmationInfo(jForm, data)
|
15
|
+
else if jForm.hasClass('password-recovery')
|
16
|
+
getWidget('AccountPanel').showConfirmationInfo(jForm, data)
|
17
|
+
else unless jForm.hasClass('status')
|
18
|
+
window.location = jqXHR.getResponseHeader('Location') or '/'
|
@@ -0,0 +1,154 @@
|
|
1
|
+
//pluralize(9) // "9th"
|
2
|
+
//'dog'.pluralize() // "dogs"
|
3
|
+
//'dog'.pluralize(4) // "4 dogs"
|
4
|
+
//'dog'.pluralize(2, 'dogs too many') // "2 dogs too many"
|
5
|
+
//'dogs'.singularize() // "dog"
|
6
|
+
//'dogs'.singularize(1) // "1 dog"
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
//Dogs suck! CATS FOREVER!
|
11
|
+
|
12
|
+
Inflector = {
|
13
|
+
Inflections: {
|
14
|
+
plural: [
|
15
|
+
[/(quiz)$/i, "$1zes" ],
|
16
|
+
[/^(ox)$/i, "$1en" ],
|
17
|
+
[/([m|l])ouse$/i, "$1ice" ],
|
18
|
+
[/(matr|vert|ind)ix|ex$/i, "$1ices" ],
|
19
|
+
[/(x|ch|ss|sh)$/i, "$1es" ],
|
20
|
+
[/([^aeiouy]|qu)y$/i, "$1ies" ],
|
21
|
+
[/(hive)$/i, "$1s" ],
|
22
|
+
[/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
|
23
|
+
[/sis$/i, "ses" ],
|
24
|
+
[/([ti])um$/i, "$1a" ],
|
25
|
+
[/(buffal|tomat)o$/i, "$1oes" ],
|
26
|
+
[/(bu)s$/i, "$1ses" ],
|
27
|
+
[/(alias|status)$/i, "$1es" ],
|
28
|
+
[/(octop|vir)us$/i, "$1i" ],
|
29
|
+
[/(ax|test)is$/i, "$1es" ],
|
30
|
+
[/s$/i, "s" ],
|
31
|
+
[/$/, "s" ]
|
32
|
+
],
|
33
|
+
singular: [
|
34
|
+
[/(quiz)zes$/i, "$1" ],
|
35
|
+
[/(matr)ices$/i, "$1ix" ],
|
36
|
+
[/(vert|ind)ices$/i, "$1ex" ],
|
37
|
+
[/^(ox)en/i, "$1" ],
|
38
|
+
[/(alias|status)es$/i, "$1" ],
|
39
|
+
[/(octop|vir)i$/i, "$1us" ],
|
40
|
+
[/(cris|ax|test)es$/i, "$1is" ],
|
41
|
+
[/(shoe)s$/i, "$1" ],
|
42
|
+
[/(o)es$/i, "$1" ],
|
43
|
+
[/(bus)es$/i, "$1" ],
|
44
|
+
[/([m|l])ice$/i, "$1ouse" ],
|
45
|
+
[/(x|ch|ss|sh)es$/i, "$1" ],
|
46
|
+
[/(m)ovies$/i, "$1ovie" ],
|
47
|
+
[/(s)eries$/i, "$1eries"],
|
48
|
+
[/([^aeiouy]|qu)ies$/i, "$1y" ],
|
49
|
+
[/([lr])ves$/i, "$1f" ],
|
50
|
+
[/(tive)s$/i, "$1" ],
|
51
|
+
[/(hive)s$/i, "$1" ],
|
52
|
+
[/([^f])ves$/i, "$1fe" ],
|
53
|
+
[/(^analy)ses$/i, "$1sis" ],
|
54
|
+
[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"],
|
55
|
+
[/([ti])a$/i, "$1um" ],
|
56
|
+
[/(n)ews$/i, "$1ews" ],
|
57
|
+
[/s$/i, "" ]
|
58
|
+
],
|
59
|
+
irregular: [
|
60
|
+
['move', 'moves' ],
|
61
|
+
['sex', 'sexes' ],
|
62
|
+
['child', 'children'],
|
63
|
+
['man', 'men' ],
|
64
|
+
['person', 'people' ]
|
65
|
+
],
|
66
|
+
uncountable: [
|
67
|
+
"sheep",
|
68
|
+
"fish",
|
69
|
+
"series",
|
70
|
+
"species",
|
71
|
+
"money",
|
72
|
+
"rice",
|
73
|
+
"information",
|
74
|
+
"equipment"
|
75
|
+
]
|
76
|
+
},
|
77
|
+
ordinalize: function(number) {
|
78
|
+
if (11 <= parseInt(number) % 100 && parseInt(number) % 100 <= 13) {
|
79
|
+
return number + "th";
|
80
|
+
} else {
|
81
|
+
switch (parseInt(number) % 10) {
|
82
|
+
case 1: return number + "st";
|
83
|
+
case 2: return number + "nd";
|
84
|
+
case 3: return number + "rd";
|
85
|
+
default: return number + "th";
|
86
|
+
}
|
87
|
+
}
|
88
|
+
},
|
89
|
+
pluralize: function(word) {
|
90
|
+
for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) {
|
91
|
+
var uncountable = Inflector.Inflections.uncountable[i];
|
92
|
+
if (word.toLowerCase == uncountable) {
|
93
|
+
return uncountable;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
for (var i = 0; i < Inflector.Inflections.irregular.length; i++) {
|
97
|
+
var singular = Inflector.Inflections.irregular[i][0];
|
98
|
+
var plural = Inflector.Inflections.irregular[i][1];
|
99
|
+
if ((word.toLowerCase == singular) || (word == plural)) {
|
100
|
+
return plural;
|
101
|
+
}
|
102
|
+
}
|
103
|
+
for (var i = 0; i < Inflector.Inflections.plural.length; i++) {
|
104
|
+
var regex = Inflector.Inflections.plural[i][0];
|
105
|
+
var replace_string = Inflector.Inflections.plural[i][1];
|
106
|
+
if (regex.test(word)) {
|
107
|
+
return word.replace(regex, replace_string);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
},
|
111
|
+
singularize: function(word) {
|
112
|
+
for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) {
|
113
|
+
var uncountable = Inflector.Inflections.uncountable[i];
|
114
|
+
if (word.toLowerCase == uncountable) {
|
115
|
+
return uncountable;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
for (var i = 0; i < Inflector.Inflections.irregular.length; i++) {
|
119
|
+
var singular = Inflector.Inflections.irregular[i][0];
|
120
|
+
var plural = Inflector.Inflections.irregular[i][1];
|
121
|
+
if ((word.toLowerCase == singular) || (word == plural)) {
|
122
|
+
return plural;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
for (var i = 0; i < Inflector.Inflections.singular.length; i++) {
|
126
|
+
var regex = Inflector.Inflections.singular[i][0];
|
127
|
+
var replace_string = Inflector.Inflections.singular[i][1];
|
128
|
+
if (regex.test(word)) {
|
129
|
+
return word.replace(regex, replace_string);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
function ordinalize(number) {
|
136
|
+
return Inflector.ordinalize(number);
|
137
|
+
}
|
138
|
+
|
139
|
+
Object.extend(String.prototype, {
|
140
|
+
pluralize: function(count, plural) {
|
141
|
+
if (typeof count == 'undefined') {
|
142
|
+
return Inflector.pluralize(this);
|
143
|
+
} else {
|
144
|
+
return count + ' ' + (1 == parseInt(count) ? this : plural || Inflector.pluralize(this));
|
145
|
+
}
|
146
|
+
},
|
147
|
+
singularize: function(count) {
|
148
|
+
if (typeof count == 'undefined') {
|
149
|
+
return Inflector.singularize(this);
|
150
|
+
} else {
|
151
|
+
return count + " " + Inflector.singularize(this);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
});
|
@@ -0,0 +1,29 @@
|
|
1
|
+
// pluralize(12, 'коров', 'корова', 'коровы')
|
2
|
+
function pluralize(num, zero, one, two) {
|
3
|
+
num = Math.abs(num);
|
4
|
+
if ( (num >= 5) && (num <= 20) ) return zero;
|
5
|
+
num = num % 10;
|
6
|
+
if ( num == 1 ) return one;
|
7
|
+
if ( (num >= 2) && (num <= 4) ) return two;
|
8
|
+
return zero;
|
9
|
+
}
|
10
|
+
|
11
|
+
function limitField(field_selector, limit, info_selector) {
|
12
|
+
var jInfo = $(info_selector);
|
13
|
+
var jField = $(field_selector);
|
14
|
+
var text_buffer = jField.val();
|
15
|
+
jField.bind('keyup change', function () {
|
16
|
+
var text = jField.val();
|
17
|
+
var text_length = text.length;
|
18
|
+
if (text_length > limit) {
|
19
|
+
jInfo.html('<span style="color: red;">Не может быть длиннее ' + limit + ' символов!</span>');
|
20
|
+
jField.val(text_buffer);
|
21
|
+
return false;
|
22
|
+
} else {
|
23
|
+
text_buffer = text;
|
24
|
+
var rest = limit - text_length;
|
25
|
+
jInfo.html('Остал' + pluralize(rest, 'ось', 'ся', 'ось') + ' ' + rest + ' символ' + pluralize(rest, 'ов', '', 'а') + '.');
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
} ).change();
|
29
|
+
}
|