Calendar.view-spec.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. Calendar.mixin({
  2. viewSpecCache: null, // cache of view definitions (initialized in Calendar.js)
  3. // Gets information about how to create a view. Will use a cache.
  4. getViewSpec: function(viewType) {
  5. var cache = this.viewSpecCache;
  6. return cache[viewType] || (cache[viewType] = this.buildViewSpec(viewType));
  7. },
  8. // Given a duration singular unit, like "week" or "day", finds a matching view spec.
  9. // Preference is given to views that have corresponding buttons.
  10. getUnitViewSpec: function(unit) {
  11. var viewTypes;
  12. var i;
  13. var spec;
  14. if ($.inArray(unit, unitsDesc) != -1) {
  15. // put views that have buttons first. there will be duplicates, but oh well
  16. viewTypes = this.header.getViewsWithButtons(); // TODO: include footer as well?
  17. $.each(FC.views, function(viewType) { // all views
  18. viewTypes.push(viewType);
  19. });
  20. for (i = 0; i < viewTypes.length; i++) {
  21. spec = this.getViewSpec(viewTypes[i]);
  22. if (spec) {
  23. if (spec.singleUnit == unit) {
  24. return spec;
  25. }
  26. }
  27. }
  28. }
  29. },
  30. // Builds an object with information on how to create a given view
  31. buildViewSpec: function(requestedViewType) {
  32. var viewOverrides = this.overrides.views || {};
  33. var specChain = []; // for the view. lowest to highest priority
  34. var defaultsChain = []; // for the view. lowest to highest priority
  35. var overridesChain = []; // for the view. lowest to highest priority
  36. var viewType = requestedViewType;
  37. var spec; // for the view
  38. var overrides; // for the view
  39. var durationInput;
  40. var duration;
  41. var unit;
  42. // iterate from the specific view definition to a more general one until we hit an actual View class
  43. while (viewType) {
  44. spec = fcViews[viewType];
  45. overrides = viewOverrides[viewType];
  46. viewType = null; // clear. might repopulate for another iteration
  47. if (typeof spec === 'function') { // TODO: deprecate
  48. spec = { 'class': spec };
  49. }
  50. if (spec) {
  51. specChain.unshift(spec);
  52. defaultsChain.unshift(spec.defaults || {});
  53. durationInput = durationInput || spec.duration;
  54. viewType = viewType || spec.type;
  55. }
  56. if (overrides) {
  57. overridesChain.unshift(overrides); // view-specific option hashes have options at zero-level
  58. durationInput = durationInput || overrides.duration;
  59. viewType = viewType || overrides.type;
  60. }
  61. }
  62. spec = mergeProps(specChain);
  63. spec.type = requestedViewType;
  64. if (!spec['class']) {
  65. return false;
  66. }
  67. // fall back to top-level `duration` option
  68. durationInput = durationInput ||
  69. this.dynamicOverrides.duration ||
  70. this.overrides.duration;
  71. if (durationInput) {
  72. duration = moment.duration(durationInput);
  73. if (duration.valueOf()) { // valid?
  74. unit = computeDurationGreatestUnit(duration, durationInput);
  75. spec.duration = duration;
  76. spec.durationUnit = unit;
  77. // view is a single-unit duration, like "week" or "day"
  78. // incorporate options for this. lowest priority
  79. if (duration.as(unit) === 1) {
  80. spec.singleUnit = unit;
  81. overridesChain.unshift(viewOverrides[unit] || {});
  82. }
  83. }
  84. }
  85. spec.defaults = mergeOptions(defaultsChain);
  86. spec.overrides = mergeOptions(overridesChain);
  87. this.buildViewSpecOptions(spec);
  88. this.buildViewSpecButtonText(spec, requestedViewType);
  89. return spec;
  90. },
  91. // Builds and assigns a view spec's options object from its already-assigned defaults and overrides
  92. buildViewSpecOptions: function(spec) {
  93. spec.options = mergeOptions([ // lowest to highest priority
  94. Calendar.defaults, // global defaults
  95. spec.defaults, // view's defaults (from ViewSubclass.defaults)
  96. this.dirDefaults,
  97. this.localeDefaults, // locale and dir take precedence over view's defaults!
  98. this.overrides, // calendar's overrides (options given to constructor)
  99. spec.overrides, // view's overrides (view-specific options)
  100. this.dynamicOverrides // dynamically set via setter. highest precedence
  101. ]);
  102. populateInstanceComputableOptions(spec.options);
  103. },
  104. // Computes and assigns a view spec's buttonText-related options
  105. buildViewSpecButtonText: function(spec, requestedViewType) {
  106. // given an options object with a possible `buttonText` hash, lookup the buttonText for the
  107. // requested view, falling back to a generic unit entry like "week" or "day"
  108. function queryButtonText(options) {
  109. var buttonText = options.buttonText || {};
  110. return buttonText[requestedViewType] ||
  111. // view can decide to look up a certain key
  112. (spec.buttonTextKey ? buttonText[spec.buttonTextKey] : null) ||
  113. // a key like "month"
  114. (spec.singleUnit ? buttonText[spec.singleUnit] : null);
  115. }
  116. // highest to lowest priority
  117. spec.buttonTextOverride =
  118. queryButtonText(this.dynamicOverrides) ||
  119. queryButtonText(this.overrides) || // constructor-specified buttonText lookup hash takes precedence
  120. spec.overrides.buttonText; // `buttonText` for view-specific options is a string
  121. // highest to lowest priority. mirrors buildViewSpecOptions
  122. spec.buttonTextDefault =
  123. queryButtonText(this.localeDefaults) ||
  124. queryButtonText(this.dirDefaults) ||
  125. spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
  126. queryButtonText(Calendar.defaults) ||
  127. (spec.duration ? this.humanizeDuration(spec.duration) : null) || // like "3 days"
  128. requestedViewType; // fall back to given view name
  129. }
  130. });