Cite/sort.js

  1. import {getLabel} from '../get/modules/label'
  2. import getName from '../get/name'
  3. /**
  4. * @callback Cite~sort
  5. * @param {CSL} a - element a
  6. * @param {CSL} b - element b
  7. * @return {Number} positive for a > b, negative for b > a, zero for a = b
  8. */
  9. /**
  10. * Get value for comparing
  11. *
  12. * @access private
  13. * @method getComparisonValue
  14. *
  15. * @param {CSL} obj - obj
  16. * @param {String} prop - The prop in question
  17. * @param {Boolean} label - Prop is label
  18. *
  19. * @return {String|Number} something to compare
  20. */
  21. const getComparisonValue = function (obj, prop, label = prop === 'label') {
  22. let value = label ? getLabel(obj) : obj[prop]
  23. switch (prop) {
  24. case 'author':
  25. case 'editor':
  26. return value.map(name => name.literal || name.family || getName(name))
  27. case 'accessed':
  28. case 'issued':
  29. return value['date-parts'][0]
  30. case 'page':
  31. return value.split('-').map(num => parseInt(num))
  32. case 'edition':
  33. case 'issue':
  34. case 'volume':
  35. value = parseInt(value)
  36. return !isNaN(value) ? value : -Infinity
  37. default:
  38. return value || -Infinity
  39. }
  40. }
  41. /**
  42. * Compares props
  43. *
  44. * @access private
  45. * @method compareProp
  46. *
  47. * @param {CSL} a - Object a
  48. * @param {CSL} b - Object b
  49. * @param {String} prop - The prop in question. Prepend ! to sort the other way around.
  50. * @param {Boolean} flip - Override flip
  51. *
  52. * @return {Number} positive for a > b, negative for b > a, zero for a = b (flips if prop has !)
  53. */
  54. const compareProp = function (a, b, prop, flip = /^!/.test(prop)) {
  55. prop = prop.replace(/^!/, '')
  56. const valueA = getComparisonValue(a, prop)
  57. const valueB = getComparisonValue(b, prop)
  58. return valueA === valueB ? 0 : flip !== (valueA > valueB) ? 1 : -1
  59. }
  60. /**
  61. * Generates a sorting callback based on props.
  62. *
  63. * @access private
  64. * @method getSortCallback
  65. *
  66. * @param {...String} props - How to sort
  67. *
  68. * @return {Cite~sort} sorting callback
  69. */
  70. const getSortCallback = function (...props) {
  71. return (a, b) => {
  72. const keys = props.slice()
  73. let output = 0
  74. while (!output && keys.length) {
  75. output = compareProp(a, b, keys.shift())
  76. }
  77. return output
  78. }
  79. }
  80. /**
  81. * Sort the dataset
  82. *
  83. * @memberof Cite#
  84. *
  85. * @param {Cite~sort|Array<String>} [method=[]] - How to sort
  86. * @param {Boolean} [log=false] - Show this call in the log
  87. *
  88. * @return {Cite} The updated parent object
  89. */
  90. const sort = function (method = [], log) {
  91. if (log) {
  92. this.save()
  93. }
  94. this.data.sort(typeof method === 'function' ? method : getSortCallback(...method, 'label'))
  95. return this
  96. }
  97. export { sort }