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.
Files changed (58) hide show
  1. data/.gitignore +5 -0
  2. data/.rvmrc +2 -0
  3. data/.rvmrc.example +2 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +14 -0
  6. data/LICENSE +5 -0
  7. data/README.md +1 -0
  8. data/Rakefile +1 -0
  9. data/app/assets/javascripts/backbone/backbone.js +1452 -0
  10. data/app/assets/javascripts/backbone/ultimate/app.js.coffee +25 -0
  11. data/app/assets/javascripts/backbone/ultimate/collection.js.coffee +12 -0
  12. data/app/assets/javascripts/backbone/ultimate/model.js.coffee +12 -0
  13. data/app/assets/javascripts/backbone/ultimate/router.js.coffee +13 -0
  14. data/app/assets/javascripts/backbone/ultimate/view.js.coffee +96 -0
  15. data/app/assets/javascripts/ultimate/base.js.coffee +103 -0
  16. data/app/assets/javascripts/ultimate/bus.js.coffee +57 -0
  17. data/app/assets/javascripts/ultimate/devise.js.coffee +18 -0
  18. data/app/assets/javascripts/ultimate/experimental/_inflections/dzone.inflections.js +154 -0
  19. data/app/assets/javascripts/ultimate/experimental/_inflections/inflections.js.coffee +2 -0
  20. data/app/assets/javascripts/ultimate/experimental/_inflections/plur.js +29 -0
  21. data/app/assets/javascripts/ultimate/experimental/_inflections/underscore.inflection.js +175 -0
  22. data/app/assets/javascripts/ultimate/experimental/fuzzy-json-generator.js.coffee +48 -0
  23. data/app/assets/javascripts/ultimate/helpers/array.js.coffee +63 -0
  24. data/app/assets/javascripts/ultimate/helpers/asset_tag.js.coffee +63 -0
  25. data/app/assets/javascripts/ultimate/helpers/decor.js.coffee +14 -0
  26. data/app/assets/javascripts/ultimate/helpers/forms.js.coffee +0 -0
  27. data/app/assets/javascripts/ultimate/helpers/tags.js.coffee +70 -0
  28. data/app/assets/javascripts/ultimate/helpers.js.coffee +149 -0
  29. data/app/assets/javascripts/ultimate/improves/datepicker.js.coffee +34 -0
  30. data/app/assets/javascripts/ultimate/improves/form-errors.js.coffee +146 -0
  31. data/app/assets/javascripts/ultimate/improves/form.js.coffee +155 -0
  32. data/app/assets/javascripts/ultimate/improves/magic-radios.js.coffee +41 -0
  33. data/app/assets/javascripts/ultimate/improves/tablesorter.js +59 -0
  34. data/app/assets/javascripts/ultimate/improves/typed-field.js.coffee +98 -0
  35. data/app/assets/javascripts/ultimate/underscore/underscore.js +1059 -0
  36. data/app/assets/javascripts/ultimate/underscore/underscore.string.js +480 -0
  37. data/app/assets/javascripts/ultimate/widgets/dock.js.coffee +70 -0
  38. data/app/assets/javascripts/ultimate/widgets/gear.js.coffee +84 -0
  39. data/app/assets/javascripts/ultimate/widgets/jquery-ext.js.coffee +104 -0
  40. data/app/assets/javascripts/ultimate/widgets/jquery.adapter.js.coffee +62 -0
  41. data/app/assets/javascripts/ultimate/widgets/widget.js.coffee +115 -0
  42. data/app/assets/stylesheets/polyfills/PIE.htc +96 -0
  43. data/app/assets/stylesheets/polyfills/boxsizing.htc +300 -0
  44. data/app/assets/stylesheets/ultimate/mixins/_routines.css.scss +95 -0
  45. data/app/assets/stylesheets/ultimate/mixins/_vendors.css.scss +34 -0
  46. data/app/assets/stylesheets/ultimate/mixins/css3/_text-shadow.scss +37 -0
  47. data/app/assets/stylesheets/ultimate/mixins/css3.css.scss +328 -0
  48. data/app/assets/stylesheets/ultimate/mixins/decor.css.scss +86 -0
  49. data/app/assets/stylesheets/ultimate/mixins/fonts.css.scss +100 -0
  50. data/app/assets/stylesheets/ultimate/mixins/microstructures.css.scss +188 -0
  51. data/app/assets/stylesheets/ultimate/structures/slider.css.scss +53 -0
  52. data/lib/ultimate-base/engine.rb +6 -0
  53. data/lib/ultimate-base/extensions/directive_processor.rb +64 -0
  54. data/lib/ultimate-base/extensions/sass_script_functions.rb +39 -0
  55. data/lib/ultimate-base/version.rb +5 -0
  56. data/lib/ultimate-base.rb +10 -0
  57. data/ultimate-base.gemspec +25 -0
  58. metadata +102 -0
@@ -0,0 +1,480 @@
1
+ // Underscore.string
2
+ // (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
3
+ // Underscore.strings is freely distributable under the terms of the MIT license.
4
+ // Documentation: https://github.com/epeli/underscore.string
5
+ // Some code is borrowed from MooTools and Alexandru Marasteanu.
6
+
7
+ // Version 2.0.0
8
+
9
+ (function(root){
10
+ 'use strict';
11
+
12
+ // Defining helper functions.
13
+
14
+ var nativeTrim = String.prototype.trim;
15
+
16
+ var parseNumber = function(source) { return source * 1 || 0; };
17
+
18
+ var strRepeat = function(i, m) {
19
+ for (var o = []; m > 0; o[--m] = i) {}
20
+ return o.join('');
21
+ };
22
+
23
+ var slice = function(a){
24
+ return Array.prototype.slice.call(a);
25
+ };
26
+
27
+ var defaultToWhiteSpace = function(characters){
28
+ if (characters) {
29
+ return _s.escapeRegExp(characters);
30
+ }
31
+ return '\\s';
32
+ };
33
+
34
+ var sArgs = function(method){
35
+ return function(){
36
+ var args = slice(arguments);
37
+ for(var i=0; i<args.length; i++)
38
+ args[i] = args[i] == null ? '' : '' + args[i];
39
+ return method.apply(null, args);
40
+ };
41
+ };
42
+
43
+ // sprintf() for JavaScript 0.7-beta1
44
+ // http://www.diveintojavascript.com/projects/javascript-sprintf
45
+ //
46
+ // Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
47
+ // All rights reserved.
48
+
49
+ var sprintf = (function() {
50
+ function get_type(variable) {
51
+ return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
52
+ }
53
+
54
+ var str_repeat = strRepeat;
55
+
56
+ var str_format = function() {
57
+ if (!str_format.cache.hasOwnProperty(arguments[0])) {
58
+ str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
59
+ }
60
+ return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
61
+ };
62
+
63
+ str_format.format = function(parse_tree, argv) {
64
+ var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
65
+ for (i = 0; i < tree_length; i++) {
66
+ node_type = get_type(parse_tree[i]);
67
+ if (node_type === 'string') {
68
+ output.push(parse_tree[i]);
69
+ }
70
+ else if (node_type === 'array') {
71
+ match = parse_tree[i]; // convenience purposes only
72
+ if (match[2]) { // keyword argument
73
+ arg = argv[cursor];
74
+ for (k = 0; k < match[2].length; k++) {
75
+ if (!arg.hasOwnProperty(match[2][k])) {
76
+ throw(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
77
+ }
78
+ arg = arg[match[2][k]];
79
+ }
80
+ } else if (match[1]) { // positional argument (explicit)
81
+ arg = argv[match[1]];
82
+ }
83
+ else { // positional argument (implicit)
84
+ arg = argv[cursor++];
85
+ }
86
+
87
+ if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
88
+ throw(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
89
+ }
90
+ switch (match[8]) {
91
+ case 'b': arg = arg.toString(2); break;
92
+ case 'c': arg = String.fromCharCode(arg); break;
93
+ case 'd': arg = parseInt(arg, 10); break;
94
+ case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
95
+ case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
96
+ case 'o': arg = arg.toString(8); break;
97
+ case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
98
+ case 'u': arg = Math.abs(arg); break;
99
+ case 'x': arg = arg.toString(16); break;
100
+ case 'X': arg = arg.toString(16).toUpperCase(); break;
101
+ }
102
+ arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
103
+ pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
104
+ pad_length = match[6] - String(arg).length;
105
+ pad = match[6] ? str_repeat(pad_character, pad_length) : '';
106
+ output.push(match[5] ? arg + pad : pad + arg);
107
+ }
108
+ }
109
+ return output.join('');
110
+ };
111
+
112
+ str_format.cache = {};
113
+
114
+ str_format.parse = function(fmt) {
115
+ var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
116
+ while (_fmt) {
117
+ if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
118
+ parse_tree.push(match[0]);
119
+ }
120
+ else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
121
+ parse_tree.push('%');
122
+ }
123
+ else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
124
+ if (match[2]) {
125
+ arg_names |= 1;
126
+ var field_list = [], replacement_field = match[2], field_match = [];
127
+ if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
128
+ field_list.push(field_match[1]);
129
+ while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
130
+ if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
131
+ field_list.push(field_match[1]);
132
+ }
133
+ else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
134
+ field_list.push(field_match[1]);
135
+ }
136
+ else {
137
+ throw('[_.sprintf] huh?');
138
+ }
139
+ }
140
+ }
141
+ else {
142
+ throw('[_.sprintf] huh?');
143
+ }
144
+ match[2] = field_list;
145
+ }
146
+ else {
147
+ arg_names |= 2;
148
+ }
149
+ if (arg_names === 3) {
150
+ throw('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
151
+ }
152
+ parse_tree.push(match);
153
+ }
154
+ else {
155
+ throw('[_.sprintf] huh?');
156
+ }
157
+ _fmt = _fmt.substring(match[0].length);
158
+ }
159
+ return parse_tree;
160
+ };
161
+
162
+ return str_format;
163
+ })();
164
+
165
+
166
+
167
+ // Defining underscore.string
168
+
169
+ var _s = {
170
+
171
+ VERSION: '2.0.0',
172
+
173
+ isBlank: sArgs(function(str){
174
+ return (/^\s*$/).test(str);
175
+ }),
176
+
177
+ stripTags: sArgs(function(str){
178
+ return str.replace(/<\/?[^>]+>/ig, '');
179
+ }),
180
+
181
+ capitalize : sArgs(function(str) {
182
+ return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
183
+ }),
184
+
185
+ chop: sArgs(function(str, step){
186
+ step = parseNumber(step) || str.length;
187
+ var arr = [];
188
+ for (var i = 0; i < str.length;) {
189
+ arr.push(str.slice(i,i + step));
190
+ i = i + step;
191
+ }
192
+ return arr;
193
+ }),
194
+
195
+ clean: sArgs(function(str){
196
+ return _s.strip(str.replace(/\s+/g, ' '));
197
+ }),
198
+
199
+ count: sArgs(function(str, substr){
200
+ var count = 0, index;
201
+ for (var i=0; i < str.length;) {
202
+ index = str.indexOf(substr, i);
203
+ index >= 0 && count++;
204
+ i = i + (index >= 0 ? index : 0) + substr.length;
205
+ }
206
+ return count;
207
+ }),
208
+
209
+ chars: sArgs(function(str) {
210
+ return str.split('');
211
+ }),
212
+
213
+ escapeHTML: sArgs(function(str) {
214
+ return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
215
+ .replace(/"/g, '&quot;').replace(/'/g, "&apos;");
216
+ }),
217
+
218
+ unescapeHTML: sArgs(function(str) {
219
+ return str.replace(/&lt;/g, '<').replace(/&gt;/g, '>')
220
+ .replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, '&');
221
+ }),
222
+
223
+ escapeRegExp: sArgs(function(str){
224
+ // From MooTools core 1.2.4
225
+ return str.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
226
+ }),
227
+
228
+ insert: sArgs(function(str, i, substr){
229
+ var arr = str.split('');
230
+ arr.splice(parseNumber(i), 0, substr);
231
+ return arr.join('');
232
+ }),
233
+
234
+ include: sArgs(function(str, needle){
235
+ return str.indexOf(needle) !== -1;
236
+ }),
237
+
238
+ join: sArgs(function(sep) {
239
+ var args = slice(arguments);
240
+ return args.join(args.shift());
241
+ }),
242
+
243
+ lines: sArgs(function(str) {
244
+ return str.split("\n");
245
+ }),
246
+
247
+ reverse: sArgs(function(str){
248
+ return Array.prototype.reverse.apply(String(str).split('')).join('');
249
+ }),
250
+
251
+ splice: sArgs(function(str, i, howmany, substr){
252
+ var arr = str.split('');
253
+ arr.splice(parseNumber(i), parseNumber(howmany), substr);
254
+ return arr.join('');
255
+ }),
256
+
257
+ startsWith: sArgs(function(str, starts){
258
+ return str.length >= starts.length && str.substring(0, starts.length) === starts;
259
+ }),
260
+
261
+ endsWith: sArgs(function(str, ends){
262
+ return str.length >= ends.length && str.substring(str.length - ends.length) === ends;
263
+ }),
264
+
265
+ succ: sArgs(function(str){
266
+ var arr = str.split('');
267
+ arr.splice(str.length-1, 1, String.fromCharCode(str.charCodeAt(str.length-1) + 1));
268
+ return arr.join('');
269
+ }),
270
+
271
+ titleize: sArgs(function(str){
272
+ var arr = str.split(' '),
273
+ word;
274
+ for (var i=0; i < arr.length; i++) {
275
+ word = arr[i].split('');
276
+ if(typeof word[0] !== 'undefined') word[0] = word[0].toUpperCase();
277
+ i+1 === arr.length ? arr[i] = word.join('') : arr[i] = word.join('') + ' ';
278
+ }
279
+ return arr.join('');
280
+ }),
281
+
282
+ camelize: sArgs(function(str){
283
+ return _s.trim(str).replace(/(\-|_|\s)+(.)?/g, function(match, separator, chr) {
284
+ return chr ? chr.toUpperCase() : '';
285
+ });
286
+ }),
287
+
288
+ underscored: function(str){
289
+ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-|\s+/g, '_').toLowerCase();
290
+ },
291
+
292
+ dasherize: function(str){
293
+ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1-$2').replace(/^([A-Z]+)/, '-$1').replace(/\_|\s+/g, '-').toLowerCase();
294
+ },
295
+
296
+ humanize: function(str){
297
+ return _s.capitalize(this.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
298
+ },
299
+
300
+ trim: sArgs(function(str, characters){
301
+ if (!characters && nativeTrim) {
302
+ return nativeTrim.call(str);
303
+ }
304
+ characters = defaultToWhiteSpace(characters);
305
+ return str.replace(new RegExp('\^[' + characters + ']+|[' + characters + ']+$', 'g'), '');
306
+ }),
307
+
308
+ ltrim: sArgs(function(str, characters){
309
+ characters = defaultToWhiteSpace(characters);
310
+ return str.replace(new RegExp('\^[' + characters + ']+', 'g'), '');
311
+ }),
312
+
313
+ rtrim: sArgs(function(str, characters){
314
+ characters = defaultToWhiteSpace(characters);
315
+ return str.replace(new RegExp('[' + characters + ']+$', 'g'), '');
316
+ }),
317
+
318
+ truncate: sArgs(function(str, length, truncateStr){
319
+ truncateStr = truncateStr || '...';
320
+ length = parseNumber(length);
321
+ return str.length > length ? str.slice(0,length) + truncateStr : str;
322
+ }),
323
+
324
+ /**
325
+ * _s.prune: a more elegant version of truncate
326
+ * prune extra chars, never leaving a half-chopped word.
327
+ * @author github.com/sergiokas
328
+ */
329
+ prune: sArgs(function(str, length, pruneStr){
330
+ // Function to check word/digit chars including non-ASCII encodings.
331
+ var isWordChar = function(c) { return ((c.toUpperCase() != c.toLowerCase()) || /[-_\d]/.test(c)); }
332
+
333
+ var template = '';
334
+ var pruned = '';
335
+ var i = 0;
336
+
337
+ // Set default values
338
+ pruneStr = pruneStr || '...';
339
+ length = parseNumber(length);
340
+
341
+ // Convert to an ASCII string to avoid problems with unicode chars.
342
+ for (i in str) {
343
+ template += (isWordChar(str[i]))?'A':' ';
344
+ }
345
+
346
+ // Check if we're in the middle of a word
347
+ if( template.substring(length-1, length+1).search(/^\w\w$/) === 0 )
348
+ pruned = _s.rtrim(template.slice(0,length).replace(/([\W][\w]*)$/,''));
349
+ else
350
+ pruned = _s.rtrim(template.slice(0,length));
351
+
352
+ pruned = pruned.replace(/\W+$/,'');
353
+
354
+ return (pruned.length+pruneStr.length>str.length) ? str : str.substring(0, pruned.length)+pruneStr;
355
+ }),
356
+
357
+ words: function(str, delimiter) {
358
+ return String(str).split(delimiter || " ");
359
+ },
360
+
361
+ pad: sArgs(function(str, length, padStr, type) {
362
+ var padding = '',
363
+ padlen = 0;
364
+
365
+ length = parseNumber(length);
366
+
367
+ if (!padStr) { padStr = ' '; }
368
+ else if (padStr.length > 1) { padStr = padStr.charAt(0); }
369
+ switch(type) {
370
+ case 'right':
371
+ padlen = (length - str.length);
372
+ padding = strRepeat(padStr, padlen);
373
+ str = str+padding;
374
+ break;
375
+ case 'both':
376
+ padlen = (length - str.length);
377
+ padding = {
378
+ 'left' : strRepeat(padStr, Math.ceil(padlen/2)),
379
+ 'right': strRepeat(padStr, Math.floor(padlen/2))
380
+ };
381
+ str = padding.left+str+padding.right;
382
+ break;
383
+ default: // 'left'
384
+ padlen = (length - str.length);
385
+ padding = strRepeat(padStr, padlen);;
386
+ str = padding+str;
387
+ }
388
+ return str;
389
+ }),
390
+
391
+ lpad: function(str, length, padStr) {
392
+ return _s.pad(str, length, padStr);
393
+ },
394
+
395
+ rpad: function(str, length, padStr) {
396
+ return _s.pad(str, length, padStr, 'right');
397
+ },
398
+
399
+ lrpad: function(str, length, padStr) {
400
+ return _s.pad(str, length, padStr, 'both');
401
+ },
402
+
403
+ sprintf: sprintf,
404
+
405
+ vsprintf: function(fmt, argv){
406
+ argv.unshift(fmt);
407
+ return sprintf.apply(null, argv);
408
+ },
409
+
410
+ toNumber: function(str, decimals) {
411
+ var num = parseNumber(parseNumber(str).toFixed(parseNumber(decimals)));
412
+ return (!(num === 0 && (str !== "0" && str !== 0))) ? num : Number.NaN;
413
+ },
414
+
415
+ strRight: sArgs(function(sourceStr, sep){
416
+ var pos = (!sep) ? -1 : sourceStr.indexOf(sep);
417
+ return (pos != -1) ? sourceStr.slice(pos+sep.length, sourceStr.length) : sourceStr;
418
+ }),
419
+
420
+ strRightBack: sArgs(function(sourceStr, sep){
421
+ var pos = (!sep) ? -1 : sourceStr.lastIndexOf(sep);
422
+ return (pos != -1) ? sourceStr.slice(pos+sep.length, sourceStr.length) : sourceStr;
423
+ }),
424
+
425
+ strLeft: sArgs(function(sourceStr, sep){
426
+ var pos = (!sep) ? -1 : sourceStr.indexOf(sep);
427
+ return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr;
428
+ }),
429
+
430
+ strLeftBack: sArgs(function(sourceStr, sep){
431
+ var pos = sourceStr.lastIndexOf(sep);
432
+ return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr;
433
+ }),
434
+
435
+ exports: function() {
436
+ var result = {};
437
+
438
+ for (var prop in this) {
439
+ if (!this.hasOwnProperty(prop) || prop == 'include' || prop == 'contains' || prop == 'reverse') continue;
440
+ result[prop] = this[prop];
441
+ }
442
+
443
+ return result;
444
+ }
445
+
446
+ };
447
+
448
+ // Aliases
449
+
450
+ _s.strip = _s.trim;
451
+ _s.lstrip = _s.ltrim;
452
+ _s.rstrip = _s.rtrim;
453
+ _s.center = _s.lrpad;
454
+ _s.ljust = _s.lpad;
455
+ _s.rjust = _s.rpad;
456
+ _s.contains = _s.include;
457
+
458
+ // CommonJS module is defined
459
+ if (typeof exports !== 'undefined') {
460
+ if (typeof module !== 'undefined' && module.exports) {
461
+ // Export module
462
+ module.exports = _s;
463
+ }
464
+ exports._s = _s;
465
+
466
+ // Integrate with Underscore.js
467
+ } else if (typeof root._ !== 'undefined') {
468
+ // root._.mixin(_s);
469
+ root._.string = _s;
470
+ root._.str = root._.string;
471
+
472
+ // Or define it
473
+ } else {
474
+ root._ = {
475
+ string: _s,
476
+ str: _s
477
+ };
478
+ }
479
+
480
+ }(this || window));
@@ -0,0 +1,70 @@
1
+ @Ultimate =
2
+ Proto: {}
3
+ Widgets: {}
4
+ LazyWidgets: {}
5
+ Observers: {}
6
+ Plugins: {}
7
+
8
+ scopes: {}
9
+
10
+ widgetsHeap: []
11
+
12
+ initialize: ->
13
+ @scopes =
14
+ Proto : @Proto
15
+ Widgets : @Widgets
16
+ LazyWidgets : @LazyWidgets
17
+ Observers : @Observers
18
+ Plugins : @Plugins
19
+ @distributeClassNames()
20
+
21
+ # get last instance by default
22
+ getWidgetByName: (widgetClassName, instanceIndex = -1) ->
23
+ if widgetClass = @Widgets[widgetClassName] or @LazyWidgets[widgetClassName]
24
+ if _.isArray(widgetClass.instances)
25
+ instanceIndex += widgetClass.instances.length if instanceIndex < 0
26
+ widgetClass.instances[instanceIndex]
27
+
28
+ gcWidgets: ->
29
+ newHeap = []
30
+ garbage = []
31
+ for widget in @widgetsHeap
32
+ if widget.isGarbage()
33
+ instances = widget.constructor.instances
34
+ i = _.indexOf instances, widget
35
+ instances.splice i, 1 if i >= 0
36
+ garbage.push widget
37
+ else
38
+ widget.heapIndex = newHeap.push widget
39
+ @widgetsHeap = newHeap if garbage.length
40
+ garbage
41
+
42
+ isWidget: (candidate) ->
43
+ candidate instanceof @Proto.Widget
44
+
45
+ isWidgetClass: (candidate) ->
46
+ (candidate::) instanceof @Proto.Widget
47
+
48
+ # This is the best way to create an instance of the widget.
49
+ createWidget: (widgetClass, jContainer, options = {}) ->
50
+ widget = null
51
+ if widgetClass.canCreateInstance()
52
+ unless jContainer.hasWidget widgetClass
53
+ widget = new widgetClass jContainer, options
54
+ widget.heapIndex = @widgetsHeap.push widget
55
+ else
56
+ warning "Ultimate.createWidget() can't create widget on passed jContainer, because it already has widget #{widgetClass.className}"
57
+ else
58
+ warning "Ultimate.createWidget() can't create widget, because blocked by widgetClass.canCreateInstance()"
59
+ widget
60
+
61
+ distributeClassNames: (widgetClassesOrScopes = @scopes, deep = true) ->
62
+ if deep
63
+ for scopeName, scope of widgetClassesOrScopes
64
+ @distributeClassNames scope, false
65
+ else
66
+ for widgetName, widgetClass of widgetClassesOrScopes
67
+ widgetClass.className = widgetName
68
+
69
+ #
70
+ _.bindAll Ultimate
@@ -0,0 +1,84 @@
1
+ # Ultimate base object
2
+ # * base OOP improves
3
+ # * instances controls
4
+ # * options and settings controls
5
+ # * translations
6
+
7
+ console.log 'Ultimate.Proto.Gear', Ultimate if console?
8
+
9
+ class Ultimate.Proto.Gear
10
+
11
+ @className: 'Gear'
12
+
13
+ # commented because must be uniq for independent widgets
14
+ #@instances: []
15
+ @maxInstances: Infinity # 0 for intrfaces, 1 for singleton
16
+
17
+ @canCreateInstance = ->
18
+ cout 'info', 'Gear.canCreateInstance', @name, @instances, @maxInstances
19
+ (@instances or []).length < @maxInstances
20
+
21
+ @pushInstance = (instance) ->
22
+ @instances ||= []
23
+ @instances.push instance
24
+
25
+
26
+
27
+ @defaults:
28
+ constants: {}
29
+ locales:
30
+ 'en':
31
+ description: 'Base Ultimate js Class'
32
+ 'ru':
33
+ description: 'Базовай Ultimate js-класс'
34
+ options:
35
+ locale: 'en'
36
+ translations: {}
37
+
38
+ settings: {}
39
+
40
+ uniqId: null
41
+
42
+ debugMode: false
43
+
44
+ constructor: (options = {}) ->
45
+ @uniqId = _.uniqueId @constructor.className
46
+ @constructor.pushInstance @
47
+ @updateSettings @constructor.defaults.options
48
+ @updateSettings @initTranslations(options)
49
+ @debug "#{@constructor.className}.constructor()", @uniqId, options
50
+
51
+ # use I18n, and modify locale and translations in options
52
+ # modify and return merged data
53
+ initTranslations: (options) ->
54
+ # if global compatible I18n
55
+ if I18n? and I18n.locale and I18n.t
56
+ options['locale'] ?= I18n.locale
57
+ if options['locale'] is I18n.locale
58
+ # pointing to defaults locales of language specified in I18n
59
+ _defaultLocales = @constructor.defaults.locales[I18n.locale]
60
+ unless _defaultLocales['loaded']
61
+ _defaultLocales['loaded'] = true
62
+ # try read localized strings
63
+ if _localesFromI18n = I18n.t options['i18nKey'] or _.underscored(@constructor.className)
64
+ # fill it from I18n
65
+ _defaultLocales[_.camelize key] = value for key, value of _localesFromI18n
66
+ options
67
+
68
+ getSettings: ->
69
+ @settings
70
+
71
+ setSettings: (settings) ->
72
+ @settings = settings
73
+
74
+ updateSettings: (options) ->
75
+ cout 'updateSettings', options
76
+ for optionsKey, optionsValue of options when optionsKey in @ then @[optionsKey] = optionsValue
77
+ translations = if (l = options['locale']) then @constructor.defaults.locales[l] or {} else {}
78
+ $.extend true, @settings, translations: translations, options
79
+
80
+ debug: ->
81
+ if @settings.debugMode
82
+ a = ["DEBUG | #{@constructor.className} >>> "]
83
+ Array::push.apply a, arguments
84
+ cout.apply @, a