index.global.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. this.FullCalendar = this.FullCalendar || {};
  2. this.FullCalendar.Vue = (function (exports, vue, core, internal) {
  3. 'use strict';
  4. const OPTION_IS_COMPLEX = {
  5. headerToolbar: true,
  6. footerToolbar: true,
  7. events: true,
  8. eventSources: true,
  9. resources: true
  10. };
  11. const FullCalendar = vue.defineComponent({
  12. props: {
  13. options: Object
  14. },
  15. data() {
  16. return {
  17. renderId: 0,
  18. customRenderingMap: new Map()
  19. };
  20. },
  21. methods: {
  22. getApi() {
  23. return getSecret(this).calendar;
  24. },
  25. buildOptions(suppliedOptions) {
  26. return {
  27. ...suppliedOptions,
  28. customRenderingMetaMap: kebabToCamelKeys(this.$slots),
  29. handleCustomRendering: getSecret(this).handleCustomRendering,
  30. };
  31. },
  32. },
  33. render() {
  34. const customRenderingNodes = [];
  35. for (const customRendering of this.customRenderingMap.values()) {
  36. customRenderingNodes.push(vue.h(CustomRenderingComponent, {
  37. key: customRendering.id,
  38. customRendering,
  39. }));
  40. }
  41. return vue.h('div', {
  42. // when renderId is changed, Vue will trigger a real-DOM async rerender, calling beforeUpdate/updated
  43. attrs: { 'data-fc-render-id': this.renderId }
  44. }, vue.h(vue.Fragment, customRenderingNodes)); // for containing CustomRendering keys
  45. },
  46. mounted() {
  47. const customRenderingStore = new internal.CustomRenderingStore();
  48. getSecret(this).handleCustomRendering = customRenderingStore.handle.bind(customRenderingStore);
  49. const calendarOptions = this.buildOptions(this.options);
  50. const calendar = new core.Calendar(this.$el, calendarOptions);
  51. getSecret(this).calendar = calendar;
  52. calendar.render();
  53. customRenderingStore.subscribe((customRenderingMap) => {
  54. this.customRenderingMap = customRenderingMap; // likely same reference, so won't rerender
  55. this.renderId++; // force rerender
  56. getSecret(this).needCustomRenderingResize = true;
  57. });
  58. },
  59. beforeUpdate() {
  60. this.getApi().resumeRendering(); // the watcher handlers paused it
  61. },
  62. updated() {
  63. if (getSecret(this).needCustomRenderingResize) {
  64. getSecret(this).needCustomRenderingResize = false;
  65. this.getApi().updateSize();
  66. }
  67. },
  68. beforeUnmount() {
  69. this.getApi().destroy();
  70. },
  71. watch: buildWatchers()
  72. });
  73. // Custom Rendering
  74. // -------------------------------------------------------------------------------------------------
  75. const CustomRenderingComponent = vue.defineComponent({
  76. props: {
  77. customRendering: Object
  78. },
  79. render() {
  80. const customRendering = this.customRendering;
  81. const innerContent = typeof customRendering.generatorMeta === 'function' ?
  82. customRendering.generatorMeta(customRendering.renderProps) : // vue-normalized slot function
  83. customRendering.generatorMeta; // probably a vue JSX node returned from content-inject func
  84. return vue.h(vue.Teleport, { to: customRendering.containerEl }, innerContent);
  85. }
  86. });
  87. // storing internal state:
  88. // https://github.com/vuejs/vue/issues/1988#issuecomment-163013818
  89. function getSecret(inst) {
  90. return inst;
  91. }
  92. function buildWatchers() {
  93. let watchers = {
  94. // watches changes of ALL options and their nested objects,
  95. // but this is only a means to be notified of top-level non-complex options changes.
  96. options: {
  97. deep: true,
  98. handler(options) {
  99. let calendar = this.getApi();
  100. calendar.pauseRendering();
  101. let calendarOptions = this.buildOptions(options);
  102. calendar.resetOptions(calendarOptions);
  103. this.renderId++; // will queue a rerender
  104. }
  105. }
  106. };
  107. for (let complexOptionName in OPTION_IS_COMPLEX) {
  108. // handlers called when nested objects change
  109. watchers[`options.${complexOptionName}`] = {
  110. deep: true,
  111. handler(val) {
  112. // unfortunately the handler is called with undefined if new props were set, but the complex one wasn't ever set
  113. if (val !== undefined) {
  114. let calendar = this.getApi();
  115. calendar.pauseRendering();
  116. calendar.resetOptions({
  117. [complexOptionName]: val
  118. }, [complexOptionName]);
  119. this.renderId++; // will queue a rerender
  120. }
  121. }
  122. };
  123. }
  124. return watchers;
  125. }
  126. // General Utils
  127. // -------------------------------------------------------------------------------------------------
  128. function kebabToCamelKeys(map) {
  129. const newMap = {};
  130. for (const key in map) {
  131. newMap[kebabToCamel(key)] = map[key];
  132. }
  133. return newMap;
  134. }
  135. function kebabToCamel(s) {
  136. return s
  137. .split('-')
  138. .map((word, index) => index ? capitalize(word) : word)
  139. .join('');
  140. }
  141. function capitalize(s) {
  142. return s.charAt(0).toUpperCase() + s.slice(1);
  143. }
  144. exports["default"] = FullCalendar;
  145. Object.defineProperty(exports, '__esModule', { value: true });
  146. return exports;
  147. })({}, Vue, FullCalendar, FullCalendar.Internal);