ultimate-base 0.3.1.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +15 -15
- data/app/assets/javascripts/ultimate/backbone/lib/backbone.js +70 -56
- data/app/assets/javascripts/ultimate/backbone/model.js.coffee +2 -2
- data/app/assets/javascripts/ultimate/backbone/view.js.coffee +5 -4
- data/app/assets/javascripts/ultimate/backbone/views/typed-fields.js.coffee +1 -1
- data/app/assets/javascripts/ultimate/helpers/asset_tag.js.coffee +21 -19
- data/app/assets/javascripts/ultimate/helpers/form_options.js.coffee +65 -0
- data/app/assets/javascripts/ultimate/helpers/form_tag.js.coffee +177 -0
- data/app/assets/javascripts/ultimate/helpers/javascript.js.coffee +31 -0
- data/app/assets/javascripts/ultimate/helpers/record_tag.js.coffee +29 -15
- data/app/assets/javascripts/ultimate/helpers/tag.js.coffee +7 -3
- data/app/assets/javascripts/ultimate/helpers/url.js.coffee +62 -7
- data/app/assets/javascripts/ultimate/jquery-plugin-adapter.js.coffee +1 -0
- data/app/assets/javascripts/ultimate/jquery-plugin-class.js.coffee +35 -16
- data/app/assets/javascripts/ultimate/jquery.base.js.coffee +1 -1
- data/app/assets/javascripts/ultimate/underscore/underscore.js +292 -192
- data/app/assets/javascripts/ultimate/underscore/underscore.outcasts.js.coffee +27 -2
- data/app/assets/javascripts/ultimate/underscore/underscore.string.js +4 -4
- data/app/assets/stylesheets/polyfills/PIE.htc +81 -81
- data/app/assets/stylesheets/polyfills/boxsizing.htc +255 -54
- data/app/assets/stylesheets/ultimate/mixins/_vendors.scss +9 -0
- data/app/assets/stylesheets/ultimate/mixins/css3.scss +39 -28
- data/app/assets/stylesheets/ultimate/mixins/microstructures.scss +32 -6
- data/lib/ultimate/base/version.rb +1 -1
- data/test/javascripts/tests/helpers/asset_tag_test.js.coffee +1 -1
- data/test/javascripts/tests/helpers/form_options_test.js.coffee +96 -0
- data/test/javascripts/tests/helpers/form_tag_test.js.coffee +225 -0
- data/test/javascripts/tests/helpers/javascript_test.js.coffee +25 -0
- data/test/javascripts/tests/helpers/record_tag_test.js.coffee +5 -3
- data/test/javascripts/tests/helpers/tag_test.js.coffee +22 -17
- data/test/javascripts/tests/helpers/url_test.js.coffee +50 -6
- data/test/javascripts/tests/underscore/underscore.outcasts.test.js.coffee +9 -0
- metadata +8 -4
- data/app/assets/javascripts/ultimate/helpers/translation.js.coffee +0 -97
- data/test/javascripts/tests/helpers/translation_test.js.coffee +0 -140
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ultimate-base (0.3.
|
4
|
+
ultimate-base (0.3.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
@@ -34,7 +34,7 @@ GEM
|
|
34
34
|
i18n (~> 0.6)
|
35
35
|
multi_json (~> 1.0)
|
36
36
|
arel (3.0.2)
|
37
|
-
builder (3.0.
|
37
|
+
builder (3.0.3)
|
38
38
|
coffee-rails (3.2.2)
|
39
39
|
coffee-script (>= 2.2.0)
|
40
40
|
railties (~> 3.2.0)
|
@@ -45,16 +45,16 @@ GEM
|
|
45
45
|
erubis (2.7.0)
|
46
46
|
execjs (1.4.0)
|
47
47
|
multi_json (~> 1.0)
|
48
|
-
haml (3.1.
|
49
|
-
haml-rails (0.3.
|
50
|
-
actionpack (
|
51
|
-
activesupport (
|
52
|
-
haml (~> 3.
|
53
|
-
railties (
|
48
|
+
haml (3.1.7)
|
49
|
+
haml-rails (0.3.5)
|
50
|
+
actionpack (>= 3.1, < 4.1)
|
51
|
+
activesupport (>= 3.1, < 4.1)
|
52
|
+
haml (~> 3.1)
|
53
|
+
railties (>= 3.1, < 4.1)
|
54
54
|
hike (1.2.1)
|
55
|
-
i18n (0.6.
|
55
|
+
i18n (0.6.1)
|
56
56
|
journey (1.0.4)
|
57
|
-
jquery-rails (2.1.
|
57
|
+
jquery-rails (2.1.3)
|
58
58
|
railties (>= 3.1.0, < 5.0)
|
59
59
|
thor (~> 0.14)
|
60
60
|
json (1.7.5)
|
@@ -65,8 +65,8 @@ GEM
|
|
65
65
|
mime-types (1.19)
|
66
66
|
multi_json (1.3.6)
|
67
67
|
polyglot (0.3.3)
|
68
|
-
quiet_assets (1.0.
|
69
|
-
|
68
|
+
quiet_assets (1.0.1)
|
69
|
+
railties (~> 3.1)
|
70
70
|
qunit-rails (0.0.2)
|
71
71
|
railties (~> 3.2.3)
|
72
72
|
rack (1.4.1)
|
@@ -74,7 +74,7 @@ GEM
|
|
74
74
|
rack (>= 0.4)
|
75
75
|
rack-ssl (1.3.2)
|
76
76
|
rack
|
77
|
-
rack-test (0.6.
|
77
|
+
rack-test (0.6.2)
|
78
78
|
rack (>= 1.0)
|
79
79
|
rails (3.2.8)
|
80
80
|
actionmailer (= 3.2.8)
|
@@ -94,8 +94,8 @@ GEM
|
|
94
94
|
rake (0.9.2.2)
|
95
95
|
rdoc (3.12)
|
96
96
|
json (~> 1.4)
|
97
|
-
sass (3.1
|
98
|
-
sass-rails (3.2.
|
97
|
+
sass (3.2.1)
|
98
|
+
sass-rails (3.2.5)
|
99
99
|
railties (~> 3.2.0)
|
100
100
|
sass (>= 3.1.10)
|
101
101
|
tilt (~> 1.3)
|
@@ -183,22 +183,22 @@
|
|
183
183
|
// is automatically generated and assigned for you.
|
184
184
|
var Model = Backbone.Model = function(attributes, options) {
|
185
185
|
var defaults;
|
186
|
-
|
186
|
+
var attrs = attributes || {};
|
187
187
|
if (options && options.collection) this.collection = options.collection;
|
188
188
|
if (options && options.parse) attributes = this.parse(attributes);
|
189
189
|
if (defaults = _.result(this, 'defaults')) {
|
190
|
-
|
190
|
+
attrs = _.extend({}, defaults, attrs);
|
191
191
|
}
|
192
192
|
this.attributes = {};
|
193
193
|
this._escapedAttributes = {};
|
194
194
|
this.cid = _.uniqueId('c');
|
195
195
|
this.changed = {};
|
196
|
-
this.
|
196
|
+
this._changes = {};
|
197
197
|
this._pending = {};
|
198
|
-
this.set(
|
198
|
+
this.set(attrs, {silent: true});
|
199
199
|
// Reset change tracking.
|
200
200
|
this.changed = {};
|
201
|
-
this.
|
201
|
+
this._changes = {};
|
202
202
|
this._pending = {};
|
203
203
|
this._previousAttributes = _.clone(this.attributes);
|
204
204
|
this.initialize.apply(this, arguments);
|
@@ -210,14 +210,18 @@
|
|
210
210
|
// A hash of attributes whose current and previous value differ.
|
211
211
|
changed: null,
|
212
212
|
|
213
|
-
// A hash of attributes that have
|
214
|
-
//
|
215
|
-
|
213
|
+
// A hash of attributes that have changed since the last time `change`
|
214
|
+
// was called.
|
215
|
+
_changes: null,
|
216
216
|
|
217
|
-
// A hash of attributes that have changed since the last `
|
217
|
+
// A hash of attributes that have changed since the last `change` event
|
218
218
|
// began.
|
219
219
|
_pending: null,
|
220
220
|
|
221
|
+
// A hash of attributes with the current model state to determine if
|
222
|
+
// a `change` should be recorded within a nested `change` block.
|
223
|
+
_changing : null,
|
224
|
+
|
221
225
|
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
|
222
226
|
// CouchDB users may want to set this to `"_id"`.
|
223
227
|
idAttribute: 'id',
|
@@ -257,23 +261,22 @@
|
|
257
261
|
|
258
262
|
// Set a hash of model attributes on the object, firing `"change"` unless
|
259
263
|
// you choose to silence it.
|
260
|
-
set: function(
|
261
|
-
var
|
264
|
+
set: function(attrs, options) {
|
265
|
+
var attr, key, val;
|
266
|
+
if (attrs == null) return this;
|
262
267
|
|
263
268
|
// Handle both `"key", value` and `{key: value}` -style arguments.
|
264
|
-
if (_.isObject(
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
attrs = {};
|
269
|
-
attrs[key] = value;
|
269
|
+
if (!_.isObject(attrs)) {
|
270
|
+
key = attrs;
|
271
|
+
(attrs = {})[key] = options;
|
272
|
+
options = arguments[2];
|
270
273
|
}
|
271
274
|
|
272
275
|
// Extract attributes and options.
|
273
|
-
|
274
|
-
|
276
|
+
var silent = options && options.silent;
|
277
|
+
var unset = options && options.unset;
|
275
278
|
if (attrs instanceof Model) attrs = attrs.attributes;
|
276
|
-
if (
|
279
|
+
if (unset) for (attr in attrs) attrs[attr] = void 0;
|
277
280
|
|
278
281
|
// Run validation.
|
279
282
|
if (!this._validate(attrs, options)) return false;
|
@@ -281,7 +284,7 @@
|
|
281
284
|
// Check for changes of `id`.
|
282
285
|
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
283
286
|
|
284
|
-
var
|
287
|
+
var changing = this._changing;
|
285
288
|
var now = this.attributes;
|
286
289
|
var escaped = this._escapedAttributes;
|
287
290
|
var prev = this._previousAttributes || {};
|
@@ -291,27 +294,30 @@
|
|
291
294
|
val = attrs[attr];
|
292
295
|
|
293
296
|
// If the new and current value differ, record the change.
|
294
|
-
if (!_.isEqual(now[attr], val) || (
|
297
|
+
if (!_.isEqual(now[attr], val) || (unset && _.has(now, attr))) {
|
295
298
|
delete escaped[attr];
|
296
|
-
|
299
|
+
this._changes[attr] = true;
|
297
300
|
}
|
298
301
|
|
299
302
|
// Update or delete the current value.
|
300
|
-
|
303
|
+
unset ? delete now[attr] : now[attr] = val;
|
301
304
|
|
302
305
|
// If the new and previous value differ, record the change. If not,
|
303
306
|
// then remove changes for this attribute.
|
304
307
|
if (!_.isEqual(prev[attr], val) || (_.has(now, attr) !== _.has(prev, attr))) {
|
305
308
|
this.changed[attr] = val;
|
306
|
-
if (!
|
309
|
+
if (!silent) this._pending[attr] = true;
|
307
310
|
} else {
|
308
311
|
delete this.changed[attr];
|
309
312
|
delete this._pending[attr];
|
313
|
+
if (!changing) delete this._changes[attr];
|
310
314
|
}
|
315
|
+
|
316
|
+
if (changing && _.isEqual(now[attr], changing[attr])) delete this._changes[attr];
|
311
317
|
}
|
312
318
|
|
313
319
|
// Fire the `"change"` events.
|
314
|
-
if (!
|
320
|
+
if (!silent) this.change(options);
|
315
321
|
return this;
|
316
322
|
},
|
317
323
|
|
@@ -346,16 +352,14 @@
|
|
346
352
|
// Set a hash of model attributes, and sync the model to the server.
|
347
353
|
// If the server returns an attributes hash that differs, the model's
|
348
354
|
// state will be `set` again.
|
349
|
-
save: function(
|
350
|
-
var
|
355
|
+
save: function(attrs, options) {
|
356
|
+
var key, current, done;
|
351
357
|
|
352
|
-
// Handle both `
|
353
|
-
if (_.isObject(
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
attrs = {};
|
358
|
-
attrs[key] = value;
|
358
|
+
// Handle both `"key", value` and `{key: value}` -style arguments.
|
359
|
+
if (attrs != null && !_.isObject(attrs)) {
|
360
|
+
key = attrs;
|
361
|
+
(attrs = {})[key] = options;
|
362
|
+
options = arguments[2];
|
359
363
|
}
|
360
364
|
options = options ? _.clone(options) : {};
|
361
365
|
|
@@ -372,7 +376,7 @@
|
|
372
376
|
}
|
373
377
|
|
374
378
|
// Do not persist invalid models.
|
375
|
-
if (!attrs && !this.
|
379
|
+
if (!attrs && !this._validate(null, options)) return false;
|
376
380
|
|
377
381
|
// After a successful server-side save, the client is (optionally)
|
378
382
|
// updated with the server-side state.
|
@@ -455,18 +459,25 @@
|
|
455
459
|
// a `"change:attribute"` event for each changed attribute.
|
456
460
|
// Calling this will cause all objects observing the model to update.
|
457
461
|
change: function(options) {
|
458
|
-
options || (options = {});
|
459
462
|
var changing = this._changing;
|
460
|
-
this._changing =
|
463
|
+
var current = this._changing = {};
|
461
464
|
|
462
465
|
// Silent changes become pending changes.
|
463
|
-
for (var attr in this.
|
466
|
+
for (var attr in this._changes) this._pending[attr] = true;
|
467
|
+
|
468
|
+
// Trigger 'change:attr' for any new or silent changes.
|
469
|
+
var changes = this._changes;
|
470
|
+
this._changes = {};
|
464
471
|
|
465
|
-
//
|
466
|
-
var
|
467
|
-
this._silent = {};
|
472
|
+
// Set the correct state for this._changing values
|
473
|
+
var triggers = [];
|
468
474
|
for (var attr in changes) {
|
469
|
-
|
475
|
+
current[attr] = this.get(attr);
|
476
|
+
triggers.push(attr);
|
477
|
+
}
|
478
|
+
|
479
|
+
for (var i=0, l=triggers.length; i < l; i++) {
|
480
|
+
this.trigger('change:' + triggers[i], this, current[triggers[i]], options);
|
470
481
|
}
|
471
482
|
if (changing) return this;
|
472
483
|
|
@@ -476,13 +487,13 @@
|
|
476
487
|
this.trigger('change', this, options);
|
477
488
|
// Pending and silent changes still remain.
|
478
489
|
for (var attr in this.changed) {
|
479
|
-
if (this._pending[attr] || this.
|
490
|
+
if (this._pending[attr] || this._changes[attr]) continue;
|
480
491
|
delete this.changed[attr];
|
481
492
|
}
|
482
493
|
this._previousAttributes = _.clone(this.attributes);
|
483
494
|
}
|
484
495
|
|
485
|
-
this._changing =
|
496
|
+
this._changing = null;
|
486
497
|
return this;
|
487
498
|
},
|
488
499
|
|
@@ -532,7 +543,7 @@
|
|
532
543
|
// returning `true` if all is well. If a specific `error` callback has
|
533
544
|
// been passed, call that instead of firing the general `"error"` event.
|
534
545
|
_validate: function(attrs, options) {
|
535
|
-
if (options.silent || !this.validate) return true;
|
546
|
+
if (options && options.silent || !this.validate) return true;
|
536
547
|
attrs = _.extend({}, this.attributes, attrs);
|
537
548
|
var error = this.validate(attrs, options);
|
538
549
|
if (!error) return true;
|
@@ -894,9 +905,10 @@
|
|
894
905
|
|
895
906
|
// Cached regular expressions for matching named param parts and splatted
|
896
907
|
// parts of route strings.
|
908
|
+
var optionalParam = /\((.*?)\)/g;
|
897
909
|
var namedParam = /:\w+/g;
|
898
910
|
var splatParam = /\*\w+/g;
|
899
|
-
var escapeRegExp = /[-[\]
|
911
|
+
var escapeRegExp = /[-{}[\]+?.,\\^$|#\s]/g;
|
900
912
|
|
901
913
|
// Set up all inheritable **Backbone.Router** properties and methods.
|
902
914
|
_.extend(Router.prototype, Events, {
|
@@ -926,6 +938,7 @@
|
|
926
938
|
// Simple proxy to `Backbone.history` to save a fragment into the history.
|
927
939
|
navigate: function(fragment, options) {
|
928
940
|
Backbone.history.navigate(fragment, options);
|
941
|
+
return this;
|
929
942
|
},
|
930
943
|
|
931
944
|
// Bind all defined routes to `Backbone.history`. We have to reverse the
|
@@ -946,6 +959,7 @@
|
|
946
959
|
// against the current location hash.
|
947
960
|
_routeToRegExp: function(route) {
|
948
961
|
route = route.replace(escapeRegExp, '\\$&')
|
962
|
+
.replace(optionalParam, '(?:$1)?')
|
949
963
|
.replace(namedParam, '([^\/]+)')
|
950
964
|
.replace(splatParam, '(.*?)');
|
951
965
|
return new RegExp('^' + route + '$');
|
@@ -1058,7 +1072,7 @@
|
|
1058
1072
|
// opened by a non-pushState browser.
|
1059
1073
|
this.fragment = fragment;
|
1060
1074
|
var loc = this.location;
|
1061
|
-
var atRoot =
|
1075
|
+
var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
|
1062
1076
|
|
1063
1077
|
// If we've started off with a route from a `pushState`-enabled browser,
|
1064
1078
|
// but we're currently in a browser that doesn't support it...
|
@@ -1072,7 +1086,7 @@
|
|
1072
1086
|
// in a browser where it could be `pushState`-based instead...
|
1073
1087
|
} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
|
1074
1088
|
this.fragment = this.getHash().replace(routeStripper, '');
|
1075
|
-
this.history.replaceState({}, document.title, this.root + this.fragment);
|
1089
|
+
this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
|
1076
1090
|
}
|
1077
1091
|
|
1078
1092
|
if (!this.options.silent) return this.loadUrl();
|
@@ -1220,8 +1234,8 @@
|
|
1220
1234
|
// memory leaks.
|
1221
1235
|
dispose: function() {
|
1222
1236
|
this.undelegateEvents();
|
1223
|
-
if (this.model) this.model.off(null, null, this);
|
1224
|
-
if (this.collection) this.collection.off(null, null, this);
|
1237
|
+
if (this.model && this.model.off) this.model.off(null, null, this);
|
1238
|
+
if (this.collection && this.collection.off) this.collection.off(null, null, this);
|
1225
1239
|
return this;
|
1226
1240
|
},
|
1227
1241
|
|
@@ -1319,7 +1333,7 @@
|
|
1319
1333
|
if (this.className) attrs['class'] = _.result(this, 'className');
|
1320
1334
|
this.setElement(this.make(_.result(this, 'tagName'), attrs), false);
|
1321
1335
|
} else {
|
1322
|
-
this.setElement(this
|
1336
|
+
this.setElement(_.result(this, 'el'), false);
|
1323
1337
|
}
|
1324
1338
|
}
|
1325
1339
|
|
@@ -1434,9 +1448,12 @@
|
|
1434
1448
|
child = function(){ parent.apply(this, arguments); };
|
1435
1449
|
}
|
1436
1450
|
|
1451
|
+
// Add static properties to the constructor function, if supplied.
|
1452
|
+
_.extend(child, parent, staticProps);
|
1453
|
+
|
1437
1454
|
// Set the prototype chain to inherit from `parent`, without calling
|
1438
1455
|
// `parent`'s constructor function.
|
1439
|
-
|
1456
|
+
var Surrogate = function(){ this.constructor = child; };
|
1440
1457
|
Surrogate.prototype = parent.prototype;
|
1441
1458
|
child.prototype = new Surrogate;
|
1442
1459
|
|
@@ -1444,9 +1461,6 @@
|
|
1444
1461
|
// if supplied.
|
1445
1462
|
if (protoProps) _.extend(child.prototype, protoProps);
|
1446
1463
|
|
1447
|
-
// Add static properties to the constructor function, if supplied.
|
1448
|
-
_.extend(child, parent, staticProps);
|
1449
|
-
|
1450
1464
|
// Set a convenience property in case the parent's prototype is needed
|
1451
1465
|
// later.
|
1452
1466
|
child.__super__ = parent.prototype;
|
@@ -18,5 +18,5 @@ class Ultimate.Backbone.Model extends Backbone.Model
|
|
18
18
|
callback.apply context, [@]
|
19
19
|
|
20
20
|
singular: ->
|
21
|
-
|
22
|
-
(
|
21
|
+
modelName = @constructor.modelName or @modelName or @className or @constructor.name or 'Model'
|
22
|
+
_.singularize(_.string.underscored(modelName))
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# * Require ./../underscore/underscore.outcasts
|
2
|
+
# * Require ./../underscore/underscore.string
|
2
3
|
#= require ./base
|
3
4
|
|
4
5
|
class Ultimate.Backbone.View extends Backbone.View
|
@@ -42,7 +43,7 @@ class Ultimate.Backbone.View extends Backbone.View
|
|
42
43
|
|
43
44
|
findNodes: (jRoot = @$el, nodes = @nodes) ->
|
44
45
|
jNodes = {}
|
45
|
-
nodes = nodes()
|
46
|
+
nodes = if _.isFunction(nodes) then @nodes.call(@) else _.clone(nodes)
|
46
47
|
if _.isObject(nodes)
|
47
48
|
for nodeName, selector of nodes
|
48
49
|
_isObject = _.isObject(selector)
|
@@ -58,8 +59,7 @@ class Ultimate.Backbone.View extends Backbone.View
|
|
58
59
|
|
59
60
|
# Overload and proxy parent method Backbone.View.delegateEvents() as hook for normalizeEvents().
|
60
61
|
delegateEvents: (events) ->
|
61
|
-
args =
|
62
|
-
Array::push.apply args, arguments if arguments.length > 0
|
62
|
+
args = _.toArray(arguments)
|
63
63
|
args[0] = @normalizeEvents(events)
|
64
64
|
super args...
|
65
65
|
|
@@ -73,8 +73,9 @@ class Ultimate.Backbone.View extends Backbone.View
|
|
73
73
|
for key, method of events
|
74
74
|
[[], eventName, selector] = key.match(delegateEventSplitter)
|
75
75
|
selector = _.result(@, selector)
|
76
|
-
selector = selector.selector
|
76
|
+
selector = selector.selector if selector instanceof jQuery
|
77
77
|
if _.isString(selector)
|
78
|
+
selector = selector.replace(@$el.selector, '') if _.string.startsWith(selector, @$el.selector)
|
78
79
|
key = "#{eventName} #{selector}"
|
79
80
|
normalizedEvents[key] = method
|
80
81
|
events = normalizedEvents
|
@@ -4,7 +4,7 @@
|
|
4
4
|
@Ultimate.Helpers.AssetTag =
|
5
5
|
|
6
6
|
favicon_link_tag: (source = 'favicon.ico', options = {}) ->
|
7
|
-
tag 'link', _.extend
|
7
|
+
tag 'link', _.extend
|
8
8
|
rel: 'shortcut icon'
|
9
9
|
type: 'image/vnd.microsoft.icon'
|
10
10
|
href: @path_to_image(source)
|
@@ -13,7 +13,7 @@
|
|
13
13
|
image_path: (source) ->
|
14
14
|
if source then @compute_public_path(source, 'images') else ''
|
15
15
|
|
16
|
-
path_to_image:
|
16
|
+
path_to_image: -> @image_path arguments... # aliased to avoid conflicts with an image_path named route
|
17
17
|
|
18
18
|
image_tag: (source, options = {}) ->
|
19
19
|
src = options['src'] = @path_to_image(source)
|
@@ -23,10 +23,12 @@
|
|
23
23
|
if matches = size.match(/^(\d+)x(\d+)$/)
|
24
24
|
options['width'] = matches[1]
|
25
25
|
options['height'] = matches[2]
|
26
|
+
else if /^(\d+)$/.test(size)
|
27
|
+
options['width'] = options['height'] = size
|
26
28
|
Ultimate.Helpers.Tag.tag('img', options)
|
27
29
|
|
28
30
|
image_alt: (src) ->
|
29
|
-
_.string.capitalize @
|
31
|
+
_.string.capitalize @_without_extension(@_basename(src)).replace(/-[A-Fa-f0-9]{32}/, '')
|
30
32
|
|
31
33
|
|
32
34
|
|
@@ -41,40 +43,40 @@
|
|
41
43
|
|
42
44
|
compute_public_path: (source, dir, options = {}) ->
|
43
45
|
return source if @is_uri(source)
|
44
|
-
source = @
|
45
|
-
source = @
|
46
|
-
source = @
|
46
|
+
source = @_rewrite_extension(source, options['ext']) if options['ext']
|
47
|
+
source = @_rewrite_asset_path(source, dir)
|
48
|
+
source = @_rewrite_relative_url_root(source, @RELATIVE_URL_ROOT)
|
47
49
|
source
|
48
50
|
|
49
|
-
|
50
|
-
"#{@
|
51
|
+
_rewrite_extension: (source, ext) ->
|
52
|
+
"#{@_without_extension(source)}.#{ext}"
|
51
53
|
|
52
|
-
|
54
|
+
_without_extension: (source) ->
|
53
55
|
source.replace(/^(.+)(\.\w+)$/, '$1')
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
+
_ASSET_ID: ''
|
58
|
+
_asset_ids_cache: {}
|
57
59
|
# Use the ASSET_ID inscope variable or the random hash as its cache-busting asset id.
|
58
|
-
|
59
|
-
if _.isString(@
|
60
|
-
@
|
60
|
+
_asset_id: (source) ->
|
61
|
+
if _.isString(@_ASSET_ID)
|
62
|
+
@_ASSET_ID
|
61
63
|
else
|
62
|
-
@
|
64
|
+
@_asset_ids_cache[source] or (@_asset_ids_cache[source] = 10000000 + Math.floor(Math.random() * 90000000))
|
63
65
|
|
64
66
|
# Break out the asset path rewrite in case plugins wish to put the asset id
|
65
67
|
# someplace other than the query string.
|
66
|
-
|
68
|
+
_rewrite_asset_path: (source, dir) ->
|
67
69
|
source = "/#{dir}/#{source}" unless source[0] is '/'
|
68
|
-
if id = @
|
70
|
+
if id = @_asset_id(source)
|
69
71
|
"#{source}?#{id}"
|
70
72
|
else
|
71
73
|
source
|
72
74
|
|
73
|
-
|
75
|
+
_rewrite_relative_url_root: (source, relative_url_root) ->
|
74
76
|
if relative_url_root and not _.startsWith(source, "#{relative_url_root}/")
|
75
77
|
"#{relative_url_root}#{source}"
|
76
78
|
else
|
77
79
|
source
|
78
80
|
|
79
|
-
|
81
|
+
_basename: (source) ->
|
80
82
|
source = matches[2] if matches = source.match(/^(.*\/)?(.+)?$/)
|