timeline.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. /**
  6. * @api
  7. */
  8. define([
  9. 'underscore',
  10. 'moment',
  11. 'uiLayout',
  12. 'Magento_Ui/js/grid/listing'
  13. ], function (_, moment, layout, Listing) {
  14. 'use strict';
  15. var ONE_DAY = 86400000;
  16. return Listing.extend({
  17. defaults: {
  18. recordTmpl: 'ui/timeline/record',
  19. dateFormat: 'YYYY-MM-DD HH:mm:ss',
  20. headerFormat: 'ddd MM/DD',
  21. detailsFormat: 'DD/MM/YYYY HH:mm:ss',
  22. scale: 7,
  23. scaleStep: 1,
  24. minScale: 7,
  25. maxScale: 28,
  26. minDays: 28,
  27. displayMode: 'timeline',
  28. displayModes: {
  29. timeline: {
  30. label: 'Timeline',
  31. value: 'timeline',
  32. template: 'ui/timeline/timeline'
  33. }
  34. },
  35. viewConfig: {
  36. component: 'Magento_Ui/js/timeline/timeline-view',
  37. name: '${ $.name }_view',
  38. model: '${ $.name }'
  39. },
  40. tracks: {
  41. scale: true
  42. },
  43. statefull: {
  44. scale: true
  45. },
  46. range: {}
  47. },
  48. /**
  49. * Initializes Timeline component.
  50. *
  51. * @returns {Timeline} Chainable.
  52. */
  53. initialize: function () {
  54. this._super()
  55. .initView()
  56. .updateRange();
  57. return this;
  58. },
  59. /**
  60. * Initializes components configuration.
  61. *
  62. * @returns {Timeline} Chainable.
  63. */
  64. initConfig: function () {
  65. this._super();
  66. this.maxScale = Math.min(this.minDays, this.maxScale);
  67. this.minScale = Math.min(this.maxScale, this.minScale);
  68. return this;
  69. },
  70. /**
  71. * Initializes observable properties.
  72. *
  73. * @returns {Timeline} Chainable.
  74. */
  75. initObservable: function () {
  76. this._super()
  77. .observe.call(this.range, true, 'hasToday');
  78. return this;
  79. },
  80. /**
  81. * Initializes TimelineView component.
  82. *
  83. * @returns {Timeline} Chainable.
  84. */
  85. initView: function () {
  86. layout([this.viewConfig]);
  87. return this;
  88. },
  89. /**
  90. * Checks if provided event record is active,
  91. * i.e. it has already started.
  92. *
  93. * @param {Object} record
  94. * @returns {Boolean}
  95. */
  96. isActive: function (record) {
  97. return Number(record.status) === 1;
  98. },
  99. /**
  100. * Checks if provided event record is upcoming,
  101. * i.e. it will start later on.
  102. *
  103. * @param {Object} record
  104. * @returns {Boolean}
  105. */
  106. isUpcoming: function (record) {
  107. return Number(record.status) === 2;
  108. },
  109. /**
  110. * Checks if provided event record is permanent,
  111. * i.e. it has no ending time.
  112. *
  113. * @param {Object} record
  114. * @returns {Boolean}
  115. */
  116. isPermanent: function (record) {
  117. return !this.getEndDate(record);
  118. },
  119. /**
  120. * Checks if provided date indicates current day.
  121. *
  122. * @param {(Number|Moment)} date
  123. * @returns {Boolenan}
  124. */
  125. isToday: function (date) {
  126. return moment().isSame(date, 'day');
  127. },
  128. /**
  129. * Checks if range object contains todays date.
  130. *
  131. * @returns {Boolean}
  132. */
  133. hasToday: function () {
  134. return this.range.hasToday;
  135. },
  136. /**
  137. * Returns start date of provided record.
  138. *
  139. * @param {Object} record
  140. * @returns {String}
  141. */
  142. getStartDate: function (record) {
  143. return record['start_time'];
  144. },
  145. /**
  146. * Returns end date of provided record.
  147. *
  148. * @param {Object} record
  149. * @returns {String}
  150. */
  151. getEndDate: function (record) {
  152. return record['end_time'];
  153. },
  154. /**
  155. * Returns difference in days between records' start date
  156. * and a first day of a range.
  157. *
  158. * @param {Object} record
  159. * @returns {Number}
  160. */
  161. getStartDelta: function (record) {
  162. var start = this.createDate(this.getStartDate(record)),
  163. firstDay = this.range.firstDay;
  164. return start.diff(firstDay, 'days', true);
  165. },
  166. /**
  167. * Calculates the amount of days that provided event lasts.
  168. *
  169. * @param {Object} record
  170. * @returns {Number}
  171. */
  172. getDaysLength: function (record) {
  173. var start = this.createDate(this.getStartDate(record)),
  174. end = this.createDate(this.getEndDate(record));
  175. if (!end.isValid()) {
  176. end = this.range.lastDay.endOf('day');
  177. }
  178. return end.diff(start, 'days', true);
  179. },
  180. /**
  181. * Creates new date object based on provided date string value.
  182. *
  183. * @param {String} dateStr
  184. * @returns {Moment}
  185. */
  186. createDate: function (dateStr) {
  187. return moment(dateStr, this.dateFormat);
  188. },
  189. /**
  190. * Converts days to weeks.
  191. *
  192. * @param {Number} days
  193. * @returns {Number}
  194. */
  195. daysToWeeks: function (days) {
  196. var weeks = days / 7;
  197. if (weeks % 1) {
  198. weeks = weeks.toFixed(1);
  199. }
  200. return weeks;
  201. },
  202. /**
  203. * Updates data of a range object,
  204. * e.g. total days, first day and last day, etc.
  205. *
  206. * @returns {Object} Range instance.
  207. */
  208. updateRange: function () {
  209. var firstDay = this._getFirstDay(),
  210. lastDay = this._getLastDay(),
  211. totalDays = lastDay.diff(firstDay, 'days'),
  212. days = [],
  213. i = -1;
  214. if (totalDays < this.minDays) {
  215. totalDays += this.minDays - totalDays - 1;
  216. }
  217. while (++i <= totalDays) {
  218. days.push(+firstDay + ONE_DAY * i);
  219. }
  220. return _.extend(this.range, {
  221. days: days,
  222. totalDays: totalDays,
  223. firstDay: firstDay,
  224. lastDay: moment(_.last(days)),
  225. hasToday: this.isToday(firstDay)
  226. });
  227. },
  228. /**
  229. *
  230. * @private
  231. * @param {String} key
  232. * @returns {Array<Moment>}
  233. */
  234. _getDates: function (key) {
  235. var dates = [];
  236. this.rows.forEach(function (record) {
  237. if (record[key]) {
  238. dates.push(this.createDate(record[key]));
  239. }
  240. }, this);
  241. return dates;
  242. },
  243. /**
  244. * Returns date which is closest to the current day.
  245. *
  246. * @private
  247. * @returns {Moment}
  248. */
  249. _getFirstDay: function () {
  250. var dates = this._getDates('start_time'),
  251. first = moment.min(dates).subtract(1, 'day'),
  252. today = moment();
  253. if (!first.isValid() || first < today) {
  254. first = today;
  255. }
  256. return first.startOf('day');
  257. },
  258. /**
  259. * Returns the most distant date
  260. * specified in available records.
  261. *
  262. * @private
  263. * @returns {Moment}
  264. */
  265. _getLastDay: function () {
  266. var startDates = this._getDates('start_time'),
  267. endDates = this._getDates('end_time'),
  268. last = moment.max(startDates.concat(endDates));
  269. return last.add(1, 'day').startOf('day');
  270. },
  271. /**
  272. * TODO: remove after integration with date binding.
  273. *
  274. * @param {Number} timestamp
  275. * @returns {String}
  276. */
  277. formatHeader: function (timestamp) {
  278. return moment(timestamp).format(this.headerFormat);
  279. },
  280. /**
  281. * TODO: remove after integration with date binding.
  282. *
  283. * @param {String} date
  284. * @returns {String}
  285. */
  286. formatDetails: function (date) {
  287. return moment(date).format(this.detailsFormat);
  288. }
  289. });
  290. });