ultimate-base 0.3.1.1 → 0.3.2
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/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(/^(.*\/)?(.+)?$/)
|