unpoly-rails 0.56.7 → 0.57.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -1
  3. data/dist/unpoly.js +1569 -793
  4. data/dist/unpoly.min.js +4 -4
  5. data/lib/assets/javascripts/unpoly.coffee +2 -0
  6. data/lib/assets/javascripts/unpoly/browser.coffee.erb +25 -41
  7. data/lib/assets/javascripts/unpoly/bus.coffee.erb +20 -6
  8. data/lib/assets/javascripts/unpoly/classes/cache.coffee +23 -13
  9. data/lib/assets/javascripts/unpoly/classes/compile_pass.coffee +87 -0
  10. data/lib/assets/javascripts/unpoly/classes/focus_tracker.coffee +29 -0
  11. data/lib/assets/javascripts/unpoly/classes/follow_variant.coffee +7 -4
  12. data/lib/assets/javascripts/unpoly/classes/record.coffee +1 -1
  13. data/lib/assets/javascripts/unpoly/classes/request.coffee +38 -45
  14. data/lib/assets/javascripts/unpoly/classes/response.coffee +16 -1
  15. data/lib/assets/javascripts/unpoly/classes/store/memory.coffee +26 -0
  16. data/lib/assets/javascripts/unpoly/classes/store/session.coffee +59 -0
  17. data/lib/assets/javascripts/unpoly/cookie.coffee +56 -0
  18. data/lib/assets/javascripts/unpoly/dom.coffee.erb +67 -39
  19. data/lib/assets/javascripts/unpoly/feedback.coffee +2 -2
  20. data/lib/assets/javascripts/unpoly/form.coffee.erb +23 -12
  21. data/lib/assets/javascripts/unpoly/history.coffee +2 -2
  22. data/lib/assets/javascripts/unpoly/layout.coffee.erb +118 -99
  23. data/lib/assets/javascripts/unpoly/link.coffee.erb +12 -5
  24. data/lib/assets/javascripts/unpoly/log.coffee +6 -5
  25. data/lib/assets/javascripts/unpoly/modal.coffee.erb +9 -2
  26. data/lib/assets/javascripts/unpoly/motion.coffee.erb +2 -6
  27. data/lib/assets/javascripts/unpoly/namespace.coffee.erb +2 -2
  28. data/lib/assets/javascripts/unpoly/params.coffee.erb +522 -0
  29. data/lib/assets/javascripts/unpoly/popup.coffee.erb +3 -3
  30. data/lib/assets/javascripts/unpoly/proxy.coffee +42 -34
  31. data/lib/assets/javascripts/unpoly/{syntax.coffee → syntax.coffee.erb} +59 -117
  32. data/lib/assets/javascripts/unpoly/{util.coffee → util.coffee.erb} +206 -171
  33. data/lib/unpoly/rails/version.rb +1 -1
  34. data/package.json +1 -1
  35. data/spec_app/Gemfile.lock +1 -1
  36. data/spec_app/app/assets/javascripts/integration_test.coffee +0 -4
  37. data/spec_app/app/assets/stylesheets/integration_test.sass +7 -1
  38. data/spec_app/app/controllers/pages_controller.rb +4 -0
  39. data/spec_app/app/views/form_test/basics/new.erb +34 -5
  40. data/spec_app/app/views/form_test/submission_result.erb +2 -2
  41. data/spec_app/app/views/form_test/uploads/new.erb +15 -2
  42. data/spec_app/app/views/hash_test/unpoly.erb +30 -0
  43. data/spec_app/app/views/pages/start.erb +2 -1
  44. data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +17 -2
  45. data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +5 -0
  46. data/spec_app/spec/javascripts/helpers/to_be_error.coffee +1 -1
  47. data/spec_app/spec/javascripts/helpers/to_match_selector.coffee +5 -0
  48. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +8 -8
  49. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +58 -20
  50. data/spec_app/spec/javascripts/up/classes/cache_spec.js.coffee +78 -0
  51. data/spec_app/spec/javascripts/up/classes/focus_tracker_spec.coffee +31 -0
  52. data/spec_app/spec/javascripts/up/classes/request_spec.coffee +50 -0
  53. data/spec_app/spec/javascripts/up/classes/store/memory_spec.js.coffee +67 -0
  54. data/spec_app/spec/javascripts/up/classes/store/session_spec.js.coffee +113 -0
  55. data/spec_app/spec/javascripts/up/dom_spec.js.coffee +133 -45
  56. data/spec_app/spec/javascripts/up/form_spec.js.coffee +13 -13
  57. data/spec_app/spec/javascripts/up/layout_spec.js.coffee +110 -26
  58. data/spec_app/spec/javascripts/up/link_spec.js.coffee +1 -1
  59. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +1 -0
  60. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +52 -51
  61. data/spec_app/spec/javascripts/up/namespace_spec.js.coffee +2 -2
  62. data/spec_app/spec/javascripts/up/params_spec.coffee +768 -0
  63. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +75 -36
  64. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +48 -15
  65. data/spec_app/spec/javascripts/up/util_spec.js.coffee +148 -131
  66. metadata +17 -5
  67. data/spec_app/spec/javascripts/up/classes/.keep +0 -0
@@ -197,9 +197,9 @@ up.util = (($) ->
197
197
  $element = $(element)
198
198
  selector = undefined
199
199
 
200
- tagName = $element.prop('tagName').toLowerCase()
201
-
202
- if upId = presence($element.attr("up-id"))
200
+ if isSingletonElement($element)
201
+ selector = elementTagName($element)
202
+ else if upId = presence($element.attr("up-id"))
203
203
  selector = attributeSelector('up-id', upId)
204
204
  else if id = presence($element.attr("id"))
205
205
  if id.match(/^[a-z0-9\-_]+$/i)
@@ -207,7 +207,7 @@ up.util = (($) ->
207
207
  else
208
208
  selector = attributeSelector('id', id)
209
209
  else if name = presence($element.attr("name"))
210
- selector = tagName + attributeSelector('name', name)
210
+ selector = elementTagName($element) + attributeSelector('name', name)
211
211
  else if classes = presence(nonUpClasses($element))
212
212
  selector = ''
213
213
  for klass in classes
@@ -215,8 +215,27 @@ up.util = (($) ->
215
215
  else if ariaLabel = presence($element.attr("aria-label"))
216
216
  selector = attributeSelector('aria-label', ariaLabel)
217
217
  else
218
- selector = tagName
219
- selector
218
+ selector = elementTagName($element)
219
+
220
+ return selector
221
+
222
+ isSingletonElement = ($element) ->
223
+ # jQuery's is() returns true if at least one element
224
+ # in the collection matches the selector
225
+ $element.is('html, body, head, title')
226
+
227
+ # isGoodSelector = (selector) ->
228
+ # selector.indexOf('#') >= -1 || selector.indexOf('[') >= -1
229
+
230
+ # defineMemoizedGetter = (obj, property, fetchFn) ->
231
+ # cacheProperty = "_#{property}Cache"
232
+ # Object.defineProperty methods, property,
233
+ # get: ->
234
+ # @[cacheProperty] ||= [fetchFn(this)]
235
+ # @[cacheProperty][0]
236
+
237
+ elementTagName = ($element) ->
238
+ $element.prop('tagName').toLowerCase()
220
239
 
221
240
  attributeSelector = (attribute, value) ->
222
241
  value = value.replace(/"/g, '\\"')
@@ -224,8 +243,8 @@ up.util = (($) ->
224
243
 
225
244
  nonUpClasses = ($element) ->
226
245
  classString = $element.attr('class') || ''
227
- classes = classString.split(' ')
228
- select classes, (klass) -> isPresent(klass) && !klass.match(/^up-/)
246
+ classes = splitValues(classString)
247
+ reject classes, (klass) -> klass.match(/^up-/)
229
248
 
230
249
  # jQuery's implementation of $(...) cannot create elements that have
231
250
  # an <html> or <body> tag. So we're using native elements.
@@ -250,6 +269,19 @@ up.util = (($) ->
250
269
  ###
251
270
  assign = Object.assign || assignPolyfill
252
271
 
272
+ valuesPolyfill = (object) ->
273
+ value for key, value of object
274
+
275
+ ###**
276
+ Returns an array of values of the given object.
277
+
278
+ @function up.util.values
279
+ @param {Object} object
280
+ @return {Array<string>}
281
+ @experimental
282
+ ###
283
+ objectValues = Object.values || valuesPolyfill
284
+
253
285
  ###**
254
286
  Returns a new string with whitespace removed from the beginning
255
287
  and end of the given string.
@@ -298,7 +330,11 @@ up.util = (($) ->
298
330
  A function that will be called with each element and (optional) iteration index.
299
331
  @stable
300
332
  ###
301
- each = map
333
+ each = map # note that the native Array.forEach is very slow (https://jsperf.com/fast-array-foreach)
334
+
335
+ eachIterator = (iterator, callback) ->
336
+ while (entry = iterator.next()) && !entry.done
337
+ callback(entry.value)
302
338
 
303
339
  ###**
304
340
  Calls the given function for the given number of times.
@@ -449,6 +485,17 @@ up.util = (($) ->
449
485
  isString = (object) ->
450
486
  typeof(object) == 'string' || object instanceof String
451
487
 
488
+ ###**
489
+ Returns whether the given argument is a boolean value.
490
+
491
+ @function up.util.isBoolean
492
+ @param object
493
+ @return {boolean}
494
+ @experimental
495
+ ###
496
+ isBoolean = (object) ->
497
+ typeof(object) == 'boolean' || object instanceof Boolean
498
+
452
499
  ###**
453
500
  Returns whether the given argument is a number.
454
501
 
@@ -475,7 +522,7 @@ up.util = (($) ->
475
522
  @internal
476
523
  ###
477
524
  isOptions = (object) ->
478
- typeof(object) == 'object' && !isNull(object) && !isJQuery(object) && !isPromise(object) && !isFormData(object) && !isArray(object)
525
+ typeof(object) == 'object' && !isNull(object) && (isUndefined(object.constructor) || object.constructor == Object)
479
526
 
480
527
  ###**
481
528
  Returns whether the given argument is an object.
@@ -569,15 +616,29 @@ up.util = (($) ->
569
616
  @return {Object|Array}
570
617
  @stable
571
618
  ###
572
- copy = (object) ->
619
+ copy = (object, deep) ->
573
620
  if isArray(object)
574
621
  object = object.slice()
575
- else if isObject(object) && !isFunction(object)
622
+ # copied = true
623
+ else if isOptions(object)
576
624
  object = assign({}, object)
577
- else
578
- up.fail('Cannot copy %o', object)
625
+ # copied = true
626
+ # if copied && deep
627
+ # for key, value of object
628
+ # object[key] = copy(value, true)
579
629
  object
580
630
 
631
+ # ###**
632
+ # Returns a deep copy of the given array or object.
633
+ #
634
+ # @function up.util.deepCopy
635
+ # @param {Object|Array} object
636
+ # @return {Object|Array}
637
+ # @internal
638
+ # ###
639
+ # deepCopy = (object) ->
640
+ # copy(object, true)
641
+
581
642
  ###**
582
643
  If given a jQuery collection, returns the first native DOM element in the collection.
583
644
  If given a string, returns the first element matching that string.
@@ -607,6 +668,33 @@ up.util = (($) ->
607
668
  merge = (sources...) ->
608
669
  assign({}, sources...)
609
670
 
671
+ # ###**
672
+ # Creates a new object by recursively merging together the properties from the given objects.
673
+ #
674
+ # @function up.util.deepMerge
675
+ # @param {Array<Object>} sources...
676
+ # @return Object
677
+ #
678
+ # @internal
679
+ # ###
680
+ # deepMerge = (sources...) ->
681
+ # deepAssign({}, sources...)
682
+ #
683
+ # ###**
684
+ # @function up.util.deepAssign
685
+ # @param {Array<Object>} sources...
686
+ # @return Object
687
+ # ###
688
+ # deepAssign = (target, sources...) ->
689
+ # for source in sources
690
+ # for key, newValue of source
691
+ # if isOptions(newValue)
692
+ # oldValue = target[key]
693
+ # if isOptions(oldValue)
694
+ # newValue = deepMerge(oldValue, newValue)
695
+ # target[key] = newValue
696
+ # target
697
+
610
698
  ###**
611
699
  Creates an options hash from the given argument and some defaults.
612
700
 
@@ -619,15 +707,13 @@ up.util = (($) ->
619
707
  @return {Object}
620
708
  @internal
621
709
  ###
622
- options = (object, defaults) ->
623
- merged = if object then copy(object) else {}
710
+ newOptions = (object, defaults) ->
624
711
  if defaults
625
- for key, defaultValue of defaults
626
- value = merged[key]
627
- if isMissing(value)
628
- value = defaultValue
629
- merged[key] = value
630
- merged
712
+ merge(defaults, object)
713
+ else if object
714
+ copy(object)
715
+ else
716
+ {}
631
717
 
632
718
  ###**
633
719
  Returns the first argument that is considered [given](/up.util.isGiven).
@@ -729,7 +815,7 @@ up.util = (($) ->
729
815
  return array if array.length < 2
730
816
  setToArray(arrayToSet(array))
731
817
 
732
- ###*
818
+ ###**
733
819
  This function is like [`uniq`](/up.util.uniq), accept that
734
820
  the given function is invoked for each element to generate the value
735
821
  for which uniquness is computed.
@@ -752,7 +838,7 @@ up.util = (($) ->
752
838
  set.add(mapped)
753
839
  true
754
840
 
755
- ###*
841
+ ###**
756
842
  @function up.util.setToArray
757
843
  @internal
758
844
  ###
@@ -761,7 +847,7 @@ up.util = (($) ->
761
847
  set.forEach (elem) -> array.push(elem)
762
848
  array
763
849
 
764
- ###*
850
+ ###**
765
851
  @function up.util.arrayToSet
766
852
  @internal
767
853
  ###
@@ -982,7 +1068,7 @@ up.util = (($) ->
982
1068
  element = getElement(element)
983
1069
  element.offsetHeight
984
1070
 
985
- ###*
1071
+ ###**
986
1072
  @function up.util.finishTransition
987
1073
  @internal
988
1074
  ###
@@ -1011,7 +1097,7 @@ up.util = (($) ->
1011
1097
  @internal
1012
1098
  ###
1013
1099
  measure = ($element, opts) ->
1014
- opts = options(opts, relative: false, inner: false, includeMargin: false)
1100
+ opts = newOptions(opts, relative: false, inner: false, includeMargin: false)
1015
1101
 
1016
1102
  if opts.relative
1017
1103
  if opts.relative == true
@@ -1111,13 +1197,24 @@ up.util = (($) ->
1111
1197
  @function up.util.castedAttr
1112
1198
  @internal
1113
1199
  ###
1114
- castedAttr = ($element, attrName) ->
1115
- value = $element.attr(attrName)
1200
+ castedAttr = ($element, attribute) ->
1201
+ value = $element.attr(attribute)
1116
1202
  switch value
1117
1203
  when 'false' then false
1118
- when 'true', '', attrName then true
1204
+ when 'true', '', attribute then true
1119
1205
  else value # other strings, undefined, null, ...
1120
1206
 
1207
+ ###**
1208
+ @function up.util.jsonAttr
1209
+ @internal
1210
+ ###
1211
+ jsonAttr = (elementOrSelector, attribute) ->
1212
+ if element = getElement(elementOrSelector)
1213
+ # The document does not respond to #getAttribute()
1214
+ json = element.getAttribute?(attribute)
1215
+ if isString(json) && trim(json) != ''
1216
+ JSON.parse(json)
1217
+
1121
1218
  # castsToTrue = (object) ->
1122
1219
  # String(object) == "true"
1123
1220
  #
@@ -1155,6 +1252,13 @@ up.util = (($) ->
1155
1252
  delete filtered[property]
1156
1253
  filtered
1157
1254
 
1255
+ # pickBy = (obj, predicate) ->
1256
+ # result = {}
1257
+ # for k, v of obj
1258
+ # if predicate(v, k)
1259
+ # result[k] = v
1260
+ # result
1261
+
1158
1262
  ###**
1159
1263
  @function up.util.isUnmodifiedKeyEvent
1160
1264
  @internal
@@ -1249,9 +1353,9 @@ up.util = (($) ->
1249
1353
  openConfig = (blueprint = {}) ->
1250
1354
  hash = {}
1251
1355
  hash.reset = ->
1252
- newOptions = blueprint
1253
- newOptions = newOptions() if isFunction(newOptions)
1254
- assign(hash, newOptions)
1356
+ opts = blueprint
1357
+ opts = opts() if isFunction(opts)
1358
+ assign(hash, opts)
1255
1359
  hash.reset()
1256
1360
  hash
1257
1361
 
@@ -1324,136 +1428,6 @@ up.util = (($) ->
1324
1428
  # else
1325
1429
  # error('Could not parse argument names of %o', fun)
1326
1430
 
1327
- ###**
1328
- Normalizes the given params object to the form returned by
1329
- [`jQuery.serializeArray`](https://api.jquery.com/serializeArray/).
1330
-
1331
- @function up.util.requestDataAsArray
1332
- @param {Object|Array|undefined|null} data
1333
- @internal
1334
- ###
1335
- requestDataAsArray = (data) ->
1336
- if isArray(data)
1337
- data
1338
- if isFormData(data)
1339
- # Until FormData#entries is implemented in all major browsers we must give up here.
1340
- # However, up.form will prefer to serialize forms as arrays, so we should be good
1341
- # in most cases. We only use FormData for forms with file inputs.
1342
- up.fail('Cannot convert FormData into an array')
1343
- else
1344
- query = requestDataAsQuery(data)
1345
- array = []
1346
- for part in query.split('&')
1347
- if isPresent(part)
1348
- pair = part.split('=')
1349
- array.push
1350
- name: decodeURIComponent(pair[0])
1351
- value: decodeURIComponent(pair[1])
1352
- array
1353
-
1354
- ###**
1355
- Returns an URL-encoded query string for the given params object.
1356
-
1357
- The returned string does **not** include a leading `?` character.
1358
-
1359
- @function up.util.requestDataAsQuery
1360
- @param {Object|Array|undefined|null} data
1361
- @internal
1362
- ###
1363
- requestDataAsQuery = (data, opts) ->
1364
- opts = options(opts, purpose: 'url')
1365
-
1366
- if isString(data)
1367
- data.replace(/^\?/, '')
1368
- else if isFormData(data)
1369
- # Until FormData#entries is implemented in all major browsers we must give up here.
1370
- # However, up.form will prefer to serialize forms as arrays, so we should be good
1371
- # in most cases. We only use FormData for forms with file inputs.
1372
- up.fail('Cannot convert FormData into a query string')
1373
- else if isPresent(data)
1374
- query = $.param(data)
1375
- switch opts.purpose
1376
- when 'url'
1377
- query = query.replace(/\+/g, '%20')
1378
- when 'form'
1379
- query = query.replace(/\%20/g, '+')
1380
- else
1381
- up.fail('Unknown purpose %o', opts.purpose)
1382
- query
1383
- else
1384
- ""
1385
-
1386
- $submittingButton = ($form) ->
1387
- submitButtonSelector = 'input[type=submit], button[type=submit], button:not([type])'
1388
- $activeElement = $(document.activeElement)
1389
- if $activeElement.is(submitButtonSelector) && $form.has($activeElement)
1390
- $activeElement
1391
- else
1392
- $form.find(submitButtonSelector).first()
1393
-
1394
- ###**
1395
- Serializes the given form into a request data representation.
1396
-
1397
- @function up.util.requestDataFromForm
1398
- @return {Array|FormData}
1399
- @internal
1400
- ###
1401
- requestDataFromForm = (form) ->
1402
- $form = $(form)
1403
- hasFileInputs = $form.find('input[type=file]').length
1404
-
1405
- $button = $submittingButton($form)
1406
- buttonName = $button.attr('name')
1407
- buttonValue = $button.val()
1408
-
1409
- # We try to stick with an array representation, whose contents we can inspect.
1410
- # We cannot inspect FormData on IE11 because it has no support for `FormData.entries`.
1411
- # Inspection is needed to generate a cache key (see `up.proxy`) and to make
1412
- # vanilla requests when `pushState` is unavailable (see `up.browser.navigate`).
1413
- data = if hasFileInputs then new FormData($form.get(0)) else $form.serializeArray()
1414
- appendRequestData(data, buttonName, buttonValue) if isPresent(buttonName)
1415
- data
1416
-
1417
-
1418
- ###**
1419
- Adds a key/value pair to the given request data representation.
1420
-
1421
- This mutates the given `data` if `data` is a `FormData`, an object
1422
- or an array. When `data` is a string a new string with the appended key/value
1423
- pair is returned.
1424
-
1425
- @function up.util.appendRequestData
1426
- @param {FormData|Object|Array|undefined|null} data
1427
- @param {string} key
1428
- @param {string|Blob|File} value
1429
- @internal
1430
- ###
1431
- appendRequestData = (data, name, value, opts) ->
1432
- data ||= []
1433
-
1434
- if isArray(data)
1435
- data.push(name: name, value: value)
1436
- else if isFormData(data)
1437
- data.append(name, value)
1438
- else if isObject(data)
1439
- data[name] = value
1440
- else if isString(data)
1441
- newPair = requestDataAsQuery([ name: name, value: value ], opts)
1442
- data = [data, newPair].join('&')
1443
- data
1444
-
1445
- ###**
1446
- Merges the request data in `source` into `target`.
1447
- Will modify the passed-in `target`.
1448
-
1449
- @return
1450
- The merged form data.
1451
- ###
1452
- mergeRequestData = (target, source) ->
1453
- each requestDataAsArray(source), (field) ->
1454
- target = appendRequestData(target, field.name, field.value)
1455
- target
1456
-
1457
1431
  ###**
1458
1432
  Throws a [JavaScript error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1459
1433
  with the given message.
@@ -1517,6 +1491,11 @@ up.util = (($) ->
1517
1491
  renameKey = (object, oldKey, newKey) ->
1518
1492
  object[newKey] = pluckKey(object, oldKey)
1519
1493
 
1494
+ deprecateRenamedKey = (object, oldKey, newKey) ->
1495
+ if isDefined(object[oldKey])
1496
+ up.warn('Deprecated: Object key { %s } has been renamed to { %s } (found in %o)', oldKey, newKey, object)
1497
+ renameKey(object, oldKey, newKey)
1498
+
1520
1499
  pluckData = (elementOrSelector, key) ->
1521
1500
  $element = $(elementOrSelector)
1522
1501
  value = $element.data(key)
@@ -1591,6 +1570,9 @@ up.util = (($) ->
1591
1570
  camelCaseKeys = (obj) ->
1592
1571
  copyWithRenamedKeys(obj, camelCase)
1593
1572
 
1573
+ # lowerCaseKeys = (obj) ->
1574
+ # copyWithRenamedKeys(obj, (key) -> key.toLowerCase())
1575
+
1594
1576
  copyWithRenamedKeys = (obj, keyTransformer) ->
1595
1577
  result = {}
1596
1578
  for k, v of obj
@@ -1621,6 +1603,15 @@ up.util = (($) ->
1621
1603
  # This is by far the fastest way to do this
1622
1604
  not $.contains(document.documentElement, element)
1623
1605
 
1606
+ # ###**
1607
+ # ###
1608
+ # parsePath = (input) ->
1609
+ # path = []
1610
+ # pattern = /([^\.\[\]\"\']+)|\[\'([^\']+?)\'\]|\[\"([^\"]+?)\"\]|\[([^\]]+?)\]/g
1611
+ # while match = pattern.exec(input)
1612
+ # path.push(match[1] || match[2] || match[3] || match[4])
1613
+ # path
1614
+
1624
1615
  ###**
1625
1616
  Given a function that will return a promise, returns a proxy function
1626
1617
  with an additional `.promise` attribute.
@@ -1856,7 +1847,7 @@ up.util = (($) ->
1856
1847
  'minWidth', 'minHeight',
1857
1848
  ]
1858
1849
 
1859
- ###*
1850
+ ###**
1860
1851
  Converts the given value to a CSS length value, adding a `px` unit if required.
1861
1852
 
1862
1853
  @function up.util.cssLength
@@ -1868,7 +1859,7 @@ up.util = (($) ->
1868
1859
  else
1869
1860
  obj
1870
1861
 
1871
- ###*
1862
+ ###**
1872
1863
  Returns whether the given element has a CSS transition set.
1873
1864
 
1874
1865
  @function up.util.hasCssTransition
@@ -1908,6 +1899,9 @@ up.util = (($) ->
1908
1899
  flattened.push(object)
1909
1900
  flattened
1910
1901
 
1902
+ flatMap = (array, block) ->
1903
+ flatten map(array, block)
1904
+
1911
1905
  ###**
1912
1906
  Returns whether the given value is truthy.
1913
1907
 
@@ -1980,6 +1974,15 @@ up.util = (($) ->
1980
1974
  catch error
1981
1975
  Promise.reject(error)
1982
1976
 
1977
+ sum = (list, block) ->
1978
+ block = listBlock(block)
1979
+ totalValue = 0
1980
+ for entry in list
1981
+ entryValue = block(entry)
1982
+ if isGiven(entryValue) # ignore undefined/null, like SQL would do
1983
+ totalValue += entryValue
1984
+ totalValue
1985
+
1983
1986
  ###**
1984
1987
  Returns whether the given element is a descendant of the `<body>` element.
1985
1988
 
@@ -1989,6 +1992,9 @@ up.util = (($) ->
1989
1992
  isBodyDescendant = (element) ->
1990
1993
  $(element).parents('body').length > 0
1991
1994
 
1995
+ isBasicObjectProperty = (k) ->
1996
+ Object.prototype.hasOwnProperty(k)
1997
+
1992
1998
  isEqual = (a, b) ->
1993
1999
  if typeof(a) != typeof(b)
1994
2000
  false
@@ -1999,11 +2005,21 @@ up.util = (($) ->
1999
2005
  else
2000
2006
  a == b
2001
2007
 
2002
- requestDataAsArray: requestDataAsArray
2003
- requestDataAsQuery: requestDataAsQuery
2004
- appendRequestData: appendRequestData
2005
- mergeRequestData: mergeRequestData
2006
- requestDataFromForm: requestDataFromForm
2008
+ splitValues = (string, separator = ' ') ->
2009
+ values = string.split(separator)
2010
+ values = map(values, trim)
2011
+ values = select(values, isPresent)
2012
+ values
2013
+
2014
+ # wrapArray = (objOrArray) ->
2015
+ # if isUndefined(objOrArray)
2016
+ # []
2017
+ # else if isArray(objOrArray)
2018
+ # objOrArray
2019
+ # else
2020
+ # [objOrArray]
2021
+
2022
+ <% if ENV['JS_KNIFE'] %>knife: eval(Knife.point)<% end %>
2007
2023
  offsetParent: offsetParent
2008
2024
  fixedToAbsolute: fixedToAbsolute
2009
2025
  isFixed: isFixed
@@ -2016,15 +2032,22 @@ up.util = (($) ->
2016
2032
  $createElementFromSelector: $createElementFromSelector
2017
2033
  $createPlaceholder: $createPlaceholder
2018
2034
  selectorForElement: selectorForElement
2035
+ # isGoodSelector: isGoodSelector
2036
+ attributeSelector: attributeSelector
2019
2037
  assign: assign
2020
2038
  assignPolyfill: assignPolyfill
2021
2039
  copy: copy
2040
+ # deepCopy: deepCopy
2022
2041
  merge: merge
2023
- options: options
2042
+ # deepAssign: deepAssign
2043
+ # deepMerge: deepMerge
2044
+ options: newOptions
2024
2045
  option: option
2025
2046
  fail: fail
2026
2047
  each: each
2048
+ eachIterator: eachIterator
2027
2049
  map: map
2050
+ flatMap: flatMap
2028
2051
  times: times
2029
2052
  any: any
2030
2053
  all: all
@@ -2047,6 +2070,7 @@ up.util = (($) ->
2047
2070
  isObject: isObject
2048
2071
  isFunction: isFunction
2049
2072
  isString: isString
2073
+ isBoolean: isBoolean
2050
2074
  isNumber: isNumber
2051
2075
  isElement: isElement
2052
2076
  isJQuery: isJQuery
@@ -2075,9 +2099,11 @@ up.util = (($) ->
2075
2099
  contains: contains
2076
2100
  toArray: toArray
2077
2101
  castedAttr: castedAttr
2102
+ jsonAttr: jsonAttr
2078
2103
  clientSize: clientSize
2079
2104
  only: only
2080
2105
  except: except
2106
+ # pickBy: pickBy
2081
2107
  trim: trim
2082
2108
  unresolvablePromise: unresolvablePromise
2083
2109
  setMissingAttrs: setMissingAttrs
@@ -2090,12 +2116,14 @@ up.util = (($) ->
2090
2116
  unwrapElement: unwrapElement
2091
2117
  camelCase: camelCase
2092
2118
  camelCaseKeys: camelCaseKeys
2119
+ # lowerCaseKeys: lowerCaseKeys
2093
2120
  kebabCase: kebabCase
2094
2121
  kebabCaseKeys: kebabCaseKeys
2095
2122
  error: fail
2096
2123
  pluckData: pluckData
2097
2124
  pluckKey: pluckKey
2098
2125
  renameKey: renameKey
2126
+ deprecateRenamedKey: deprecateRenamedKey
2099
2127
  extractOptions: extractOptions
2100
2128
  isDetached: isDetached
2101
2129
  noop: noop
@@ -2109,16 +2137,19 @@ up.util = (($) ->
2109
2137
  sequence: sequence
2110
2138
  promiseTimer: promiseTimer
2111
2139
  previewable: previewable
2140
+ # parsePath: parsePath
2112
2141
  evalOption: evalOption
2113
2142
  horizontalScreenHalf: horizontalScreenHalf
2114
2143
  detachWith: detachWith
2115
2144
  flatten: flatten
2116
2145
  isTruthy: isTruthy
2146
+ isSingletonElement: isSingletonElement
2117
2147
  newDeferred: newDeferred
2118
2148
  always: always
2119
2149
  muteRejection: muteRejection
2120
2150
  rejectOnError: rejectOnError
2121
2151
  isBodyDescendant: isBodyDescendant
2152
+ isBasicObjectProperty: isBasicObjectProperty
2122
2153
  isCrossDomain: isCrossDomain
2123
2154
  microtask: microtask
2124
2155
  isEqual: isEqual
@@ -2129,6 +2160,10 @@ up.util = (($) ->
2129
2160
  readInlineStyle: readInlineStyle
2130
2161
  writeInlineStyle: writeInlineStyle
2131
2162
  hasCssTransition: hasCssTransition
2163
+ splitValues : splitValues
2164
+ sum: sum
2165
+ # wrapArray: wrapArray
2166
+ values: objectValues
2132
2167
 
2133
2168
  )(jQuery)
2134
2169