ui.scheduler.appointments.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /**
  2. * DevExtreme (ui/scheduler/ui.scheduler.appointments.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _renderer = require("../../core/renderer");
  11. var _renderer2 = _interopRequireDefault(_renderer);
  12. var _dom_adapter = require("../../core/dom_adapter");
  13. var _dom_adapter2 = _interopRequireDefault(_dom_adapter);
  14. var _events_engine = require("../../events/core/events_engine");
  15. var _events_engine2 = _interopRequireDefault(_events_engine);
  16. var _element_data = require("../../core/element_data");
  17. var _element_data2 = _interopRequireDefault(_element_data);
  18. var _translator = require("../../animation/translator");
  19. var _translator2 = _interopRequireDefault(_translator);
  20. var _date = require("../../core/utils/date");
  21. var _date2 = _interopRequireDefault(_date);
  22. var _common = require("../../core/utils/common");
  23. var _common2 = _interopRequireDefault(_common);
  24. var _type = require("../../core/utils/type");
  25. var _type2 = _interopRequireDefault(_type);
  26. var _iterator = require("../../core/utils/iterator");
  27. var _object = require("../../core/utils/object");
  28. var _object2 = _interopRequireDefault(_object);
  29. var _array = require("../../core/utils/array");
  30. var _array2 = _interopRequireDefault(_array);
  31. var _extend = require("../../core/utils/extend");
  32. var _dom = require("../../core/utils/dom");
  33. var _utils = require("./utils.recurrence");
  34. var _utils2 = _interopRequireDefault(_utils);
  35. var _component_registrator = require("../../core/component_registrator");
  36. var _component_registrator2 = _interopRequireDefault(_component_registrator);
  37. var _uiScheduler = require("./ui.scheduler.publisher_mixin");
  38. var _uiScheduler2 = _interopRequireDefault(_uiScheduler);
  39. var _uiScheduler3 = require("./ui.scheduler.appointment");
  40. var _uiScheduler4 = _interopRequireDefault(_uiScheduler3);
  41. var _utils3 = require("../../events/utils");
  42. var _utils4 = _interopRequireDefault(_utils3);
  43. var _double_click = require("../../events/double_click");
  44. var _double_click2 = _interopRequireDefault(_double_click);
  45. var _date3 = require("../../localization/date");
  46. var _date4 = _interopRequireDefault(_date3);
  47. var _message = require("../../localization/message");
  48. var _message2 = _interopRequireDefault(_message);
  49. var _uiCollection_widget = require("../collection/ui.collection_widget.edit");
  50. var _uiCollection_widget2 = _interopRequireDefault(_uiCollection_widget);
  51. var _draggable = require("../draggable");
  52. var _draggable2 = _interopRequireDefault(_draggable);
  53. var _deferred = require("../../core/utils/deferred");
  54. function _interopRequireDefault(obj) {
  55. return obj && obj.__esModule ? obj : {
  56. "default": obj
  57. }
  58. }
  59. var APPOINTMENT_SETTINGS_NAME = "dxAppointmentSettings";
  60. var COMPONENT_CLASS = "dx-scheduler-scrollable-appointments";
  61. var APPOINTMENT_ITEM_CLASS = "dx-scheduler-appointment";
  62. var APPOINTMENT_TITLE_CLASS = "dx-scheduler-appointment-title";
  63. var APPOINTMENT_CONTENT_DETAILS_CLASS = "dx-scheduler-appointment-content-details";
  64. var APPOINTMENT_DATE_CLASS = "dx-scheduler-appointment-content-date";
  65. var RECURRING_ICON_CLASS = "dx-scheduler-appointment-recurrence-icon";
  66. var ALL_DAY_CONTENT_CLASS = "dx-scheduler-appointment-content-allday";
  67. var DBLCLICK_EVENT_NAME = _utils4.default.addNamespace(_double_click2.default.name, "dxSchedulerAppointment");
  68. var toMs = _date2.default.dateToMilliseconds;
  69. var SchedulerAppointments = _uiCollection_widget2.default.inherit({
  70. _supportedKeys: function() {
  71. var parent = this.callBase();
  72. var tabHandler = function(e) {
  73. var appointments = this._getAccessAppointments();
  74. var focusedAppointment = appointments.filter(".dx-state-focused");
  75. var index = focusedAppointment.data("dxAppointmentSettings").sortedIndex;
  76. var lastIndex = appointments.length - 1;
  77. if (index > 0 && e.shiftKey || index < lastIndex && !e.shiftKey) {
  78. e.preventDefault();
  79. e.shiftKey ? index-- : index++;
  80. var $nextAppointment = this._getAppointmentByIndex(index);
  81. this._resetTabIndex($nextAppointment);
  82. _events_engine2.default.trigger($nextAppointment, "focus")
  83. }
  84. };
  85. return (0, _extend.extend)(parent, {
  86. escape: function() {
  87. this.moveAppointmentBack();
  88. this._escPressed = true
  89. }.bind(this),
  90. del: function(e) {
  91. if (this.option("allowDelete")) {
  92. e.preventDefault();
  93. var data = this._getItemData(e.target);
  94. this.notifyObserver("deleteAppointment", {
  95. data: data,
  96. target: e.target
  97. });
  98. this.notifyObserver("hideAppointmentTooltip")
  99. }
  100. }.bind(this),
  101. tab: tabHandler
  102. })
  103. },
  104. _getAppointmentByIndex: function(sortedIndex) {
  105. var appointments = this._getAccessAppointments();
  106. return appointments.filter(function(_, $item) {
  107. return _element_data2.default.data($item, "dxAppointmentSettings").sortedIndex === sortedIndex
  108. }).eq(0)
  109. },
  110. _getAccessAppointments: function() {
  111. return this._itemElements().filter(":visible").not(".dx-state-disabled")
  112. },
  113. _resetTabIndex: function($appointment) {
  114. this._focusTarget().attr("tabIndex", -1);
  115. $appointment.attr("tabIndex", this.option("tabIndex"))
  116. },
  117. _moveFocus: _common2.default.noop,
  118. _focusTarget: function() {
  119. return this._itemElements()
  120. },
  121. _renderFocusTarget: function() {
  122. var $appointment = this._getAppointmentByIndex(0);
  123. this._resetTabIndex($appointment)
  124. },
  125. _focusInHandler: function(e) {
  126. if (this._targetIsDisabled(e)) {
  127. e.stopPropagation();
  128. return
  129. }
  130. clearTimeout(this._appointmentFocusedTimeout);
  131. this.callBase.apply(this, arguments);
  132. this._$currentAppointment = (0, _renderer2.default)(e.target);
  133. this.option("focusedElement", (0, _dom.getPublicElement)((0, _renderer2.default)(e.target)));
  134. var that = this;
  135. this._appointmentFocusedTimeout = setTimeout(function() {
  136. that.notifyObserver("appointmentFocused")
  137. })
  138. },
  139. _targetIsDisabled: function(e) {
  140. return (0, _renderer2.default)(e.currentTarget).is(".dx-state-disabled, .dx-state-disabled *")
  141. },
  142. _focusOutHandler: function() {
  143. var $appointment = this._getAppointmentByIndex(0);
  144. this.option("focusedElement", (0, _dom.getPublicElement)($appointment));
  145. this.callBase.apply(this, arguments)
  146. },
  147. _eventBindingTarget: function() {
  148. return this._itemContainer()
  149. },
  150. _getDefaultOptions: function() {
  151. return (0, _extend.extend)(this.callBase(), {
  152. noDataText: null,
  153. activeStateEnabled: true,
  154. hoverStateEnabled: true,
  155. tabIndex: 0,
  156. fixedContainer: null,
  157. allDayContainer: null,
  158. allowDrag: true,
  159. allowResize: true,
  160. allowAllDayResize: true,
  161. onAppointmentDblClick: null,
  162. _collectorOffset: 0
  163. })
  164. },
  165. _optionChanged: function(args) {
  166. switch (args.name) {
  167. case "items":
  168. this._cleanFocusState();
  169. this._clearDropDownItems();
  170. this._clearDropDownItemsElements();
  171. this._repaintAppointments(args.value);
  172. this._renderDropDownAppointments();
  173. this._attachAppointmentsEvents();
  174. break;
  175. case "fixedContainer":
  176. case "allDayContainer":
  177. case "onAppointmentDblClick":
  178. break;
  179. case "allowDrag":
  180. case "allowResize":
  181. case "allowAllDayResize":
  182. this._invalidate();
  183. break;
  184. case "focusedElement":
  185. this._resetTabIndex((0, _renderer2.default)(args.value));
  186. this.callBase(args);
  187. break;
  188. case "allowDelete":
  189. break;
  190. case "focusStateEnabled":
  191. this._clearDropDownItemsElements();
  192. this._renderDropDownAppointments();
  193. this.callBase(args);
  194. break;
  195. default:
  196. this.callBase(args)
  197. }
  198. },
  199. _isAllDayAppointment: function(appointment) {
  200. return appointment.settings.length && appointment.settings[0].allDay || false
  201. },
  202. _isRepaintAppointment: function(appointment) {
  203. return !_type2.default.isDefined(appointment.needRepaint) || true === appointment.needRepaint
  204. },
  205. _isRepaintAll: function(appointments) {
  206. if (this.invoke("isCurrentViewAgenda")) {
  207. return true
  208. }
  209. for (var i = 0; i < appointments.length; i++) {
  210. var appointment = appointments[i];
  211. if (!this._isRepaintAppointment(appointment)) {
  212. return false
  213. }
  214. }
  215. return true
  216. },
  217. _applyFragment: function(fragment, allDay) {
  218. if (fragment.children().length > 0) {
  219. this._getAppointmentContainer(allDay).append(fragment)
  220. }
  221. },
  222. _onEachAppointment: function(appointment, index, container, isRepaintAll) {
  223. if (appointment && true === appointment.needRemove) {
  224. this._clearItem(appointment);
  225. return
  226. }
  227. if (this._isRepaintAppointment(appointment)) {
  228. appointment.needRepaint = false;
  229. !isRepaintAll && this._clearItem(appointment);
  230. this._renderItem(index, appointment, container)
  231. }
  232. },
  233. _repaintAppointments: function(appointments) {
  234. var _this = this;
  235. var isRepaintAll = this._isRepaintAll(appointments);
  236. var allDayFragment = (0, _renderer2.default)(this._getAppointmentContainer(true));
  237. var commonFragment = (0, _renderer2.default)(this._getAppointmentContainer(false));
  238. if (isRepaintAll) {
  239. this._getAppointmentContainer(true).html("");
  240. this._getAppointmentContainer(false).html("")
  241. }!appointments.length && this._cleanItemContainer();
  242. appointments.forEach(function(appointment, index) {
  243. var container = _this._isAllDayAppointment(appointment) ? allDayFragment : commonFragment;
  244. _this._onEachAppointment(appointment, index, container, isRepaintAll)
  245. });
  246. this._applyFragment(allDayFragment, true);
  247. this._applyFragment(commonFragment, false)
  248. },
  249. _attachAppointmentsEvents: function() {
  250. this._attachClickEvent();
  251. this._attachHoldEvent();
  252. this._attachContextMenuEvent();
  253. this._attachAppointmentDblClick();
  254. this._renderFocusState();
  255. this._attachFeedbackEvents();
  256. this._attachHoverEvents()
  257. },
  258. _clearItem: function(item) {
  259. var $items = this._findItemElementByItem(item.itemData);
  260. if (!$items.length) {
  261. return
  262. }(0, _iterator.each)($items, function(_, $item) {
  263. $item.detach();
  264. $item.remove()
  265. })
  266. },
  267. _clearDropDownItems: function() {
  268. this._virtualAppointments = {}
  269. },
  270. _clearDropDownItemsElements: function() {
  271. this.invoke("clearCompactAppointments")
  272. },
  273. _findItemElementByItem: function(item) {
  274. var result = [];
  275. var that = this;
  276. this.itemElements().each(function() {
  277. var $item = (0, _renderer2.default)(this);
  278. if ($item.data(that._itemDataKey()) === item) {
  279. result.push($item)
  280. }
  281. });
  282. return result
  283. },
  284. _itemClass: function() {
  285. return APPOINTMENT_ITEM_CLASS
  286. },
  287. _itemContainer: function() {
  288. var $container = this.callBase();
  289. var $result = $container;
  290. var $allDayContainer = this.option("allDayContainer");
  291. if ($allDayContainer) {
  292. $result = $container.add($allDayContainer)
  293. }
  294. return $result
  295. },
  296. _cleanItemContainer: function() {
  297. this.callBase();
  298. var $allDayContainer = this.option("allDayContainer");
  299. if ($allDayContainer) {
  300. $allDayContainer.empty()
  301. }
  302. this._virtualAppointments = {}
  303. },
  304. _clean: function() {
  305. this.callBase();
  306. delete this._$currentAppointment;
  307. delete this._initialSize;
  308. delete this._initialCoordinates
  309. },
  310. _init: function() {
  311. this.callBase();
  312. this.$element().addClass(COMPONENT_CLASS);
  313. this._preventSingleAppointmentClick = false
  314. },
  315. _renderAppointmentTemplate: function($container, data, model) {
  316. var startDate = model.settings ? new Date(this.invoke("getField", "startDate", model.settings)) : data.startDate;
  317. var endDate = model.settings ? new Date(this.invoke("getField", "endDate", model.settings)) : data.endDate;
  318. if (isNaN(startDate) || isNaN(endDate)) {
  319. startDate = data.startDate;
  320. endDate = data.endDate
  321. }(0, _renderer2.default)("<div>").text(this._createAppointmentTitle(data)).addClass(APPOINTMENT_TITLE_CLASS).appendTo($container);
  322. if (_type2.default.isPlainObject(data)) {
  323. if (data.html) {
  324. $container.html(data.html)
  325. }
  326. }
  327. var recurrenceRule = data.recurrenceRule;
  328. var allDay = data.allDay;
  329. var $contentDetails = (0, _renderer2.default)("<div>").addClass(APPOINTMENT_CONTENT_DETAILS_CLASS);
  330. var apptStartTz = data.startDateTimeZone;
  331. var apptEndTz = data.endDateTimeZone;
  332. startDate = this.invoke("convertDateByTimezone", startDate, apptStartTz);
  333. endDate = this.invoke("convertDateByTimezone", endDate, apptEndTz);
  334. (0, _renderer2.default)("<div>").addClass(APPOINTMENT_DATE_CLASS).text(_date4.default.format(startDate, "shorttime")).appendTo($contentDetails);
  335. (0, _renderer2.default)("<div>").addClass(APPOINTMENT_DATE_CLASS).text(" - ").appendTo($contentDetails);
  336. (0, _renderer2.default)("<div>").addClass(APPOINTMENT_DATE_CLASS).text(_date4.default.format(endDate, "shorttime")).appendTo($contentDetails);
  337. $contentDetails.appendTo($container);
  338. if (recurrenceRule) {
  339. (0, _renderer2.default)("<span>").addClass(RECURRING_ICON_CLASS + " dx-icon-repeat").appendTo($container)
  340. }
  341. if (allDay) {
  342. (0, _renderer2.default)("<div>").text(" " + _message2.default.format("dxScheduler-allDay") + ": ").addClass(ALL_DAY_CONTENT_CLASS).prependTo($contentDetails)
  343. }
  344. },
  345. _createAppointmentTitle: function(data) {
  346. if (_type2.default.isPlainObject(data)) {
  347. return data.text
  348. }
  349. return String(data)
  350. },
  351. _executeItemRenderAction: function(index, itemData, itemElement) {
  352. var action = this._getItemRenderAction();
  353. if (action) {
  354. action({
  355. appointmentElement: itemElement,
  356. appointmentData: itemData,
  357. targetedAppointmentData: this.invoke("getTargetedAppointmentData", itemData, itemElement, index)
  358. })
  359. }
  360. delete this._currentAppointmentSettings
  361. },
  362. _itemClickHandler: function(e) {
  363. this.callBase(e, {}, {
  364. afterExecute: function(e) {
  365. this._processItemClick(e.args[0].event)
  366. }.bind(this)
  367. })
  368. },
  369. _processItemClick: function(e) {
  370. var $target = (0, _renderer2.default)(e.currentTarget);
  371. var data = this._getItemData($target);
  372. if (this._targetIsDisabled(e)) {
  373. e.stopPropagation();
  374. return
  375. }
  376. if ("keydown" === e.type || _utils4.default.isFakeClickEvent(e)) {
  377. this.notifyObserver("showEditAppointmentPopup", {
  378. data: data,
  379. target: $target
  380. });
  381. return
  382. }
  383. this._appointmentClickTimeout = setTimeout(function() {
  384. if (!this._preventSingleAppointmentClick && _dom_adapter2.default.getBody().contains($target[0])) {
  385. this.notifyObserver("showAppointmentTooltip", {
  386. data: data,
  387. target: $target
  388. })
  389. }
  390. this._preventSingleAppointmentClick = false
  391. }.bind(this), 300)
  392. },
  393. _extendActionArgs: function() {
  394. var args = this.callBase.apply(this, arguments);
  395. return this.invoke("mapAppointmentFields", args)
  396. },
  397. _render: function() {
  398. this.callBase.apply(this, arguments);
  399. this._attachAppointmentDblClick()
  400. },
  401. _attachAppointmentDblClick: function() {
  402. var that = this;
  403. var itemSelector = that._itemSelector();
  404. var itemContainer = this._itemContainer();
  405. _events_engine2.default.off(itemContainer, DBLCLICK_EVENT_NAME, itemSelector);
  406. _events_engine2.default.on(itemContainer, DBLCLICK_EVENT_NAME, itemSelector, function(e) {
  407. that._itemDXEventHandler(e, "onAppointmentDblClick", {}, {
  408. afterExecute: function(e) {
  409. that._dblClickHandler(e.args[0].event)
  410. }
  411. })
  412. })
  413. },
  414. _dblClickHandler: function(e) {
  415. var $targetAppointment = (0, _renderer2.default)(e.currentTarget);
  416. var appointmentData = this._getItemData($targetAppointment);
  417. clearTimeout(this._appointmentClickTimeout);
  418. this._preventSingleAppointmentClick = true;
  419. this.notifyObserver("showEditAppointmentPopup", {
  420. data: appointmentData,
  421. target: $targetAppointment
  422. })
  423. },
  424. _renderItem: function(index, item, container) {
  425. var itemData = item.itemData;
  426. for (var i = 0; i < item.settings.length; i++) {
  427. var setting = item.settings[i];
  428. this._currentAppointmentSettings = setting;
  429. var $item = this.callBase(index, itemData, container);
  430. $item.data(APPOINTMENT_SETTINGS_NAME, setting)
  431. }
  432. },
  433. _getItemContent: function($itemFrame) {
  434. $itemFrame.data(APPOINTMENT_SETTINGS_NAME, this._currentAppointmentSettings);
  435. var $itemContent = this.callBase($itemFrame);
  436. return $itemContent
  437. },
  438. _createItemByTemplate: function(itemTemplate, renderArgs) {
  439. return itemTemplate.render({
  440. model: renderArgs.itemData,
  441. container: renderArgs.container,
  442. index: renderArgs.index
  443. })
  444. },
  445. _getAppointmentContainer: function(allDay) {
  446. var $allDayContainer = this.option("allDayContainer");
  447. var $container = this.itemsContainer().not($allDayContainer);
  448. if (allDay && $allDayContainer) {
  449. $container = $allDayContainer
  450. }
  451. return $container
  452. },
  453. _postprocessRenderItem: function(args) {
  454. this._renderAppointment(args.itemElement, this._currentAppointmentSettings)
  455. },
  456. _renderAppointment: function($appointment, settings) {
  457. $appointment.data(APPOINTMENT_SETTINGS_NAME, settings);
  458. this._applyResourceDataAttr($appointment);
  459. var data = this._getItemData($appointment);
  460. var geometry = this.invoke("getAppointmentGeometry", settings);
  461. var allowResize = !settings.isCompact && this.option("allowResize") && (!_type2.default.isDefined(settings.skipResizing) || _type2.default.isString(settings.skipResizing));
  462. var allowDrag = this.option("allowDrag");
  463. var allDay = settings.allDay;
  464. this.invoke("setCellDataCacheAlias", this._currentAppointmentSettings, geometry);
  465. var deferredColor = this._getAppointmentColor($appointment, settings.groupIndex);
  466. if (settings.virtual) {
  467. this._processVirtualAppointment(settings, $appointment, data, deferredColor)
  468. } else {
  469. this._createComponent($appointment, _uiScheduler4.default, {
  470. observer: this.option("observer"),
  471. data: data,
  472. geometry: geometry,
  473. direction: settings.direction || "vertical",
  474. allowResize: allowResize,
  475. allowDrag: allowDrag,
  476. allDay: allDay,
  477. reduced: settings.appointmentReduced,
  478. isCompact: settings.isCompact,
  479. startDate: new Date(settings.startDate),
  480. cellWidth: this.invoke("getCellWidth"),
  481. cellHeight: this.invoke("getCellHeight"),
  482. resizableConfig: this._resizableConfig(data, settings)
  483. });
  484. deferredColor.done(function(color) {
  485. if (color) {
  486. $appointment.css("backgroundColor", color)
  487. }
  488. });
  489. this._renderDraggable($appointment, allDay)
  490. }
  491. },
  492. _applyResourceDataAttr: function($appointment) {
  493. this.notifyObserver("getResourcesFromItem", {
  494. itemData: this._getItemData($appointment),
  495. callback: function(resources) {
  496. if (resources) {
  497. (0, _iterator.each)(resources, function(name, values) {
  498. var attr = "data-" + _common2.default.normalizeKey(name.toLowerCase()) + "-";
  499. for (var i = 0; i < values.length; i++) {
  500. $appointment.attr(attr + _common2.default.normalizeKey(values[i]), true)
  501. }
  502. })
  503. }
  504. }
  505. })
  506. },
  507. _resizableConfig: function(appointmentData, itemSetting) {
  508. return {
  509. area: this._calculateResizableArea(itemSetting, appointmentData),
  510. onResizeStart: function(e) {
  511. this._$currentAppointment = (0, _renderer2.default)(e.element);
  512. if (this.invoke("needRecalculateResizableArea")) {
  513. var updatedArea = this._calculateResizableArea(this._$currentAppointment.data("dxAppointmentSettings"), this._$currentAppointment.data("dxItemData"));
  514. e.component.option("area", updatedArea);
  515. e.component._renderDragOffsets(e.event)
  516. }
  517. this._initialSize = {
  518. width: e.width,
  519. height: e.height
  520. };
  521. this._initialCoordinates = _translator2.default.locate(this._$currentAppointment)
  522. }.bind(this),
  523. onResizeEnd: function(e) {
  524. if (this._escPressed) {
  525. e.event.cancel = true;
  526. return
  527. }
  528. this._resizeEndHandler(e)
  529. }.bind(this)
  530. }
  531. },
  532. _calculateResizableArea: function(itemSetting, appointmentData) {
  533. var area = this.$element().closest(".dx-scrollable-content");
  534. this.notifyObserver("getResizableAppointmentArea", {
  535. coordinates: {
  536. left: itemSetting.left,
  537. top: 0,
  538. groupIndex: itemSetting.groupIndex
  539. },
  540. allDay: itemSetting.allDay,
  541. callback: function(result) {
  542. if (result) {
  543. area = result
  544. }
  545. }
  546. });
  547. return area
  548. },
  549. _resizeEndHandler: function(e) {
  550. var $element = (0, _renderer2.default)(e.element);
  551. var itemData = this._getItemData($element);
  552. var startDate = this.invoke("getStartDate", itemData, true);
  553. var endDate = this.invoke("getEndDate", itemData, true);
  554. var dateRange = this._getDateRange(e, startDate, endDate);
  555. var updatedDates = {};
  556. this.invoke("setField", "startDate", updatedDates, new Date(dateRange[0]));
  557. this.invoke("setField", "endDate", updatedDates, new Date(dateRange[1]));
  558. var data = (0, _extend.extend)({}, itemData, updatedDates);
  559. this.notifyObserver("updateAppointmentAfterResize", {
  560. target: itemData,
  561. data: data,
  562. $appointment: $element
  563. })
  564. },
  565. _getDateRange: function(e, startDate, endDate) {
  566. var itemData = this._getItemData(e.element);
  567. var deltaTime = this.invoke("getDeltaTime", e, this._initialSize, itemData);
  568. var renderingStrategyDirection = this.invoke("getRenderingStrategyDirection");
  569. var cond = false;
  570. var isAllDay = this.invoke("isAllDay", itemData);
  571. var needCorrectDates = this.invoke("needCorrectAppointmentDates") && !isAllDay;
  572. var startTime;
  573. var endTime;
  574. if ("vertical" !== renderingStrategyDirection || isAllDay) {
  575. cond = this.option("rtlEnabled") ? e.handles.right : e.handles.left
  576. } else {
  577. cond = e.handles.top
  578. }
  579. if (cond) {
  580. startTime = needCorrectDates ? this._correctStartDateByDelta(startDate, deltaTime) : startDate.getTime() - deltaTime;
  581. endTime = endDate.getTime()
  582. } else {
  583. startTime = startDate.getTime();
  584. endTime = needCorrectDates ? this._correctEndDateByDelta(endDate, deltaTime) : endDate.getTime() + deltaTime
  585. }
  586. return [startTime, endTime]
  587. },
  588. _correctEndDateByDelta: function(endDate, deltaTime) {
  589. var endDayHour = this.invoke("getEndDayHour");
  590. var startDayHour = this.invoke("getStartDayHour");
  591. var result = endDate.getTime() + deltaTime;
  592. var visibleDayDuration = (endDayHour - startDayHour) * toMs("hour");
  593. var daysCount = deltaTime > 0 ? Math.ceil(deltaTime / visibleDayDuration) : Math.floor(deltaTime / visibleDayDuration);
  594. var maxDate = new Date(endDate);
  595. var minDate = new Date(endDate);
  596. minDate.setHours(startDayHour, 0, 0, 0);
  597. maxDate.setHours(endDayHour, 0, 0, 0);
  598. if (result > maxDate.getTime() || result <= minDate.getTime()) {
  599. var tailOfCurrentDay = maxDate.getTime() - endDate.getTime();
  600. var tailOfPrevDays = deltaTime - tailOfCurrentDay;
  601. var lastDay = new Date(endDate.setDate(endDate.getDate() + daysCount));
  602. lastDay.setHours(startDayHour, 0, 0, 0);
  603. result = lastDay.getTime() + tailOfPrevDays - visibleDayDuration * (daysCount - 1)
  604. }
  605. return result
  606. },
  607. _correctStartDateByDelta: function(startDate, deltaTime) {
  608. var endDayHour = this.invoke("getEndDayHour");
  609. var startDayHour = this.invoke("getStartDayHour");
  610. var result = startDate.getTime() - deltaTime;
  611. var visibleDayDuration = (endDayHour - startDayHour) * toMs("hour");
  612. var daysCount = deltaTime > 0 ? Math.ceil(deltaTime / visibleDayDuration) : Math.floor(deltaTime / visibleDayDuration);
  613. var maxDate = new Date(startDate);
  614. var minDate = new Date(startDate);
  615. minDate.setHours(startDayHour, 0, 0, 0);
  616. maxDate.setHours(endDayHour, 0, 0, 0);
  617. if (result < minDate.getTime() || result >= maxDate.getTime()) {
  618. var tailOfCurrentDay = startDate.getTime() - minDate.getTime();
  619. var tailOfPrevDays = deltaTime - tailOfCurrentDay;
  620. var firstDay = new Date(startDate.setDate(startDate.getDate() - daysCount));
  621. firstDay.setHours(endDayHour, 0, 0, 0);
  622. result = firstDay.getTime() - tailOfPrevDays + visibleDayDuration * (daysCount - 1)
  623. }
  624. return result
  625. },
  626. _tryGetAppointmentColor: function(appointment) {
  627. var settings = (0, _renderer2.default)(appointment).data(APPOINTMENT_SETTINGS_NAME);
  628. if (!settings) {
  629. return
  630. }
  631. return this._getAppointmentColor(appointment, settings.groupIndex)
  632. },
  633. _getAppointmentColor: function($appointment, groupIndex) {
  634. var res = new _deferred.Deferred;
  635. this.notifyObserver("getAppointmentColor", {
  636. itemData: this._getItemData($appointment),
  637. groupIndex: groupIndex,
  638. callback: function(d) {
  639. return d.done(function(color) {
  640. return res.resolve(color)
  641. })
  642. }
  643. });
  644. return res.promise()
  645. },
  646. _renderDraggable: function($appointment, allDay) {
  647. if (!this.option("allowDrag")) {
  648. return
  649. }
  650. var that = this;
  651. var $fixedContainer = this.option("fixedContainer");
  652. var draggableArea;
  653. var correctCoordinates = function(element, isFixedContainer) {
  654. var coordinates = _translator2.default.locate((0, _renderer2.default)(element));
  655. that.notifyObserver("correctAppointmentCoordinates", {
  656. coordinates: coordinates,
  657. allDay: allDay,
  658. isFixedContainer: isFixedContainer,
  659. callback: function(result) {
  660. if (result) {
  661. coordinates = result
  662. }
  663. }
  664. });
  665. _translator2.default.move($appointment, coordinates)
  666. };
  667. this.notifyObserver("getDraggableAppointmentArea", {
  668. callback: function(result) {
  669. if (result) {
  670. draggableArea = result
  671. }
  672. }
  673. });
  674. this._createComponent($appointment, _draggable2.default, {
  675. area: draggableArea,
  676. boundOffset: that._calculateBoundOffset(),
  677. immediate: false,
  678. onDragStart: function(args) {
  679. var e = args.event;
  680. that._skipDraggableRestriction(e);
  681. that.notifyObserver("hideAppointmentTooltip");
  682. $fixedContainer.append($appointment);
  683. that._$currentAppointment = (0, _renderer2.default)(args.element);
  684. that._initialSize = {
  685. width: args.width,
  686. height: args.height
  687. };
  688. that._initialCoordinates = _translator2.default.locate(that._$currentAppointment)
  689. },
  690. onDrag: function(args) {
  691. correctCoordinates(args.element)
  692. },
  693. onDragEnd: function(args) {
  694. correctCoordinates(args.element, true);
  695. var $container = that._getAppointmentContainer(allDay);
  696. $container.append($appointment);
  697. if (this._escPressed) {
  698. args.event.cancel = true;
  699. return
  700. }
  701. that._dragEndHandler(args)
  702. }
  703. })
  704. },
  705. _calculateBoundOffset: function() {
  706. var result = {
  707. top: 0
  708. };
  709. this.notifyObserver("getBoundOffset", {
  710. callback: function(offset) {
  711. result = offset
  712. }
  713. });
  714. return result
  715. },
  716. _skipDraggableRestriction: function(e) {
  717. if (this.option("rtlEnabled")) {
  718. e.maxLeftOffset = null
  719. } else {
  720. e.maxRightOffset = null
  721. }
  722. e.maxBottomOffset = null
  723. },
  724. _dragEndHandler: function(e) {
  725. var $element = (0, _renderer2.default)(e.element);
  726. var itemData = this._getItemData($element);
  727. var coordinates = this._initialCoordinates;
  728. this.notifyObserver("updateAppointmentAfterDrag", {
  729. data: itemData,
  730. $appointment: $element,
  731. coordinates: coordinates
  732. })
  733. },
  734. _virtualAppointments: {},
  735. _processVirtualAppointment: function(appointmentSetting, $appointment, appointmentData, color) {
  736. var virtualAppointment = appointmentSetting.virtual;
  737. var virtualGroupIndex = virtualAppointment.index;
  738. if (!_type2.default.isDefined(this._virtualAppointments[virtualGroupIndex])) {
  739. this._virtualAppointments[virtualGroupIndex] = {
  740. coordinates: {
  741. top: virtualAppointment.top,
  742. left: virtualAppointment.left
  743. },
  744. items: {
  745. data: [],
  746. colors: []
  747. },
  748. isAllDay: virtualAppointment.isAllDay ? true : false,
  749. buttonColor: color
  750. }
  751. }
  752. appointmentData.settings = [appointmentSetting];
  753. this._virtualAppointments[virtualGroupIndex].items.data.push(appointmentData);
  754. this._virtualAppointments[virtualGroupIndex].items.colors.push(color);
  755. $appointment.remove()
  756. },
  757. _renderContentImpl: function() {
  758. this.callBase();
  759. this._renderDropDownAppointments()
  760. },
  761. _renderDropDownAppointments: function() {
  762. (0, _iterator.each)(this._virtualAppointments, function(groupIndex) {
  763. var virtualGroup = this._virtualAppointments[groupIndex];
  764. var virtualItems = virtualGroup.items;
  765. var virtualCoordinates = virtualGroup.coordinates;
  766. var $container = virtualGroup.isAllDay ? this.option("allDayContainer") : this.$element();
  767. var left = virtualCoordinates.left;
  768. var buttonWidth = this.invoke("getDropDownAppointmentWidth", virtualGroup.isAllDay);
  769. var buttonHeight = this.invoke("getDropDownAppointmentHeight");
  770. var rtlOffset = 0;
  771. if (this.option("rtlEnabled")) {
  772. rtlOffset = buttonWidth
  773. }
  774. this.notifyObserver("renderCompactAppointments", {
  775. $container: $container,
  776. coordinates: {
  777. top: virtualCoordinates.top,
  778. left: left + rtlOffset
  779. },
  780. items: virtualItems,
  781. buttonColor: virtualGroup.buttonColor,
  782. itemTemplate: this.option("itemTemplate"),
  783. width: buttonWidth - this.option("_collectorOffset"),
  784. height: buttonHeight,
  785. onAppointmentClick: this.option("onItemClick"),
  786. isCompact: this.invoke("isAdaptive") || this._isGroupCompact(virtualGroup),
  787. applyOffset: this._isGroupCompact(virtualGroup)
  788. })
  789. }.bind(this))
  790. },
  791. _isGroupCompact: function(virtualGroup) {
  792. return !virtualGroup.isAllDay && this.invoke("supportCompactDropDownAppointments")
  793. },
  794. _sortAppointmentsByStartDate: function(appointments) {
  795. appointments.sort(function(a, b) {
  796. var result = 0;
  797. var firstDate = new Date(this.invoke("getField", "startDate", a.settings || a)).getTime();
  798. var secondDate = new Date(this.invoke("getField", "startDate", b.settings || b)).getTime();
  799. if (firstDate < secondDate) {
  800. result = -1
  801. }
  802. if (firstDate > secondDate) {
  803. result = 1
  804. }
  805. return result
  806. }.bind(this))
  807. },
  808. _processRecurrenceAppointment: function(appointment, index, skipLongAppointments) {
  809. var recurrenceRule = this.invoke("getField", "recurrenceRule", appointment);
  810. var result = {
  811. parts: [],
  812. indexes: []
  813. };
  814. if (recurrenceRule) {
  815. var dates = appointment.settings || appointment;
  816. var startDate = new Date(this.invoke("getField", "startDate", dates));
  817. var endDate = new Date(this.invoke("getField", "endDate", dates));
  818. var appointmentDuration = endDate.getTime() - startDate.getTime();
  819. var recurrenceException = this.invoke("getField", "recurrenceException", appointment);
  820. var startViewDate = this.invoke("getStartViewDate");
  821. var endViewDate = this.invoke("getEndViewDate");
  822. var recurrentDates = _utils2.default.getDatesByRecurrence({
  823. rule: recurrenceRule,
  824. exception: recurrenceException,
  825. start: startDate,
  826. end: endDate,
  827. min: startViewDate,
  828. max: endViewDate
  829. });
  830. var recurrentDateCount = appointment.settings ? 1 : recurrentDates.length;
  831. for (var i = 0; i < recurrentDateCount; i++) {
  832. var appointmentPart = (0, _extend.extend)({}, appointment, true);
  833. if (recurrentDates[i]) {
  834. var appointmentSettings = this._applyStartDateToObj(recurrentDates[i], {});
  835. this._applyEndDateToObj(new Date(recurrentDates[i].getTime() + appointmentDuration), appointmentSettings);
  836. appointmentPart.settings = appointmentSettings
  837. } else {
  838. appointmentPart.settings = dates
  839. }
  840. result.parts.push(appointmentPart);
  841. if (!skipLongAppointments) {
  842. this._processLongAppointment(appointmentPart, result)
  843. }
  844. }
  845. result.indexes.push(index)
  846. }
  847. return result
  848. },
  849. _processLongAppointment: function(appointment, result) {
  850. var parts = this.splitAppointmentByDay(appointment);
  851. var partCount = parts.length;
  852. var endViewDate = this.invoke("getEndViewDate").getTime();
  853. var startViewDate = this.invoke("getStartViewDate").getTime();
  854. var startDateTimeZone = this.invoke("getField", "startDateTimeZone", appointment);
  855. result = result || {
  856. parts: []
  857. };
  858. if (partCount > 1) {
  859. (0, _extend.extend)(appointment, parts[0]);
  860. for (var i = 1; i < partCount; i++) {
  861. var startDate = this.invoke("getField", "startDate", parts[i].settings).getTime();
  862. startDate = this.invoke("convertDateByTimezone", startDate, startDateTimeZone);
  863. if (startDate < endViewDate && startDate > startViewDate) {
  864. result.parts.push(parts[i])
  865. }
  866. }
  867. }
  868. return result
  869. },
  870. _reduceRecurrenceAppointments: function(recurrenceIndexes, appointments) {
  871. (0, _iterator.each)(recurrenceIndexes, function(i, index) {
  872. appointments.splice(index - i, 1)
  873. })
  874. },
  875. _combineAppointments: function(appointments, additionalAppointments) {
  876. if (additionalAppointments.length) {
  877. _array2.default.merge(appointments, additionalAppointments)
  878. }
  879. this._sortAppointmentsByStartDate(appointments)
  880. },
  881. _applyStartDateToObj: function(startDate, obj) {
  882. this.invoke("setField", "startDate", obj, startDate);
  883. return obj
  884. },
  885. _applyEndDateToObj: function(endDate, obj) {
  886. this.invoke("setField", "endDate", obj, endDate);
  887. return obj
  888. },
  889. updateDraggablesBoundOffsets: function() {
  890. if (this.option("allowDrag")) {
  891. this.$element().find("." + APPOINTMENT_ITEM_CLASS).each(function(_, appointmentElement) {
  892. var $appointment = (0, _renderer2.default)(appointmentElement);
  893. var appointmentData = this._getItemData($appointment);
  894. if (!this.invoke("isAllDay", appointmentData)) {
  895. _draggable2.default.getInstance($appointment).option("boundOffset", this._calculateBoundOffset())
  896. }
  897. }.bind(this))
  898. }
  899. },
  900. moveAppointmentBack: function() {
  901. var $appointment = this._$currentAppointment;
  902. var size = this._initialSize;
  903. var coords = this._initialCoordinates;
  904. if ($appointment) {
  905. if (coords) {
  906. _translator2.default.move($appointment, coords);
  907. delete this._initialSize
  908. }
  909. if (size) {
  910. $appointment.outerWidth(size.width);
  911. $appointment.outerHeight(size.height);
  912. delete this._initialCoordinates
  913. }
  914. }
  915. },
  916. focus: function() {
  917. var $appointment = this._$currentAppointment;
  918. if ($appointment) {
  919. this.option("focusedElement", (0, _dom.getPublicElement)($appointment));
  920. _events_engine2.default.trigger(this.option("focusedElement"), "focus")
  921. }
  922. },
  923. splitAppointmentByDay: function(appointment) {
  924. var dates = appointment.settings || appointment;
  925. var originalStartDate = new Date(this.invoke("getField", "startDate", dates));
  926. var startDate = _date2.default.makeDate(originalStartDate);
  927. var endDate = _date2.default.makeDate(this.invoke("getField", "endDate", dates));
  928. var startDateTimeZone = this.invoke("getField", "startDateTimeZone", appointment);
  929. var endDateTimeZone = this.invoke("getField", "endDateTimeZone", appointment);
  930. var maxAllowedDate = this.invoke("getEndViewDate");
  931. var startDayHour = this.invoke("getStartDayHour");
  932. var endDayHour = this.invoke("getEndDayHour");
  933. var appointmentIsLong = this.invoke("appointmentTakesSeveralDays", appointment);
  934. var result = [];
  935. startDate = this.invoke("convertDateByTimezone", startDate, startDateTimeZone);
  936. endDate = this.invoke("convertDateByTimezone", endDate, endDateTimeZone);
  937. if (startDate.getHours() <= endDayHour && startDate.getHours() >= startDayHour && !appointmentIsLong) {
  938. result.push(this._applyStartDateToObj(new Date(startDate), {
  939. appointmentData: appointment
  940. }));
  941. startDate.setDate(startDate.getDate() + 1)
  942. }
  943. while (appointmentIsLong && startDate.getTime() < endDate.getTime() - 1 && startDate < maxAllowedDate) {
  944. var currentStartDate = new Date(startDate);
  945. var currentEndDate = new Date(startDate);
  946. this._checkStartDate(currentStartDate, originalStartDate, startDayHour);
  947. this._checkEndDate(currentEndDate, endDate, endDayHour);
  948. var appointmentData = _object2.default.deepExtendArraySafe({}, appointment, true);
  949. var appointmentSettings = {};
  950. this._applyStartDateToObj(currentStartDate, appointmentSettings);
  951. this._applyEndDateToObj(currentEndDate, appointmentSettings);
  952. appointmentData.settings = appointmentSettings;
  953. result.push(appointmentData);
  954. startDate.setDate(startDate.getDate() + 1);
  955. startDate.setHours(startDayHour)
  956. }
  957. return result
  958. },
  959. _checkStartDate: function(currentDate, originalDate, startDayHour) {
  960. if (!_date2.default.sameDate(currentDate, originalDate) || currentDate.getHours() <= startDayHour) {
  961. currentDate.setHours(startDayHour, 0, 0, 0)
  962. } else {
  963. currentDate.setHours(originalDate.getHours(), originalDate.getMinutes(), originalDate.getSeconds(), originalDate.getMilliseconds())
  964. }
  965. },
  966. _checkEndDate: function(currentDate, originalDate, endDayHour) {
  967. if (!_date2.default.sameDate(currentDate, originalDate) || currentDate.getHours() > endDayHour) {
  968. currentDate.setHours(endDayHour, 0, 0, 0)
  969. } else {
  970. currentDate.setHours(originalDate.getHours(), originalDate.getMinutes(), originalDate.getSeconds(), originalDate.getMilliseconds())
  971. }
  972. }
  973. }).include(_uiScheduler2.default);
  974. (0, _component_registrator2.default)("dxSchedulerAppointments", SchedulerAppointments);
  975. module.exports = SchedulerAppointments;