unpoly-rails 0.56.7 → 0.57.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.

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