Header.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /* Top toolbar area with buttons and title
  2. ----------------------------------------------------------------------------------------------------------------------*/
  3. // TODO: rename all header-related things to "toolbar"
  4. function Header(calendar) {
  5. var t = this;
  6. // exports
  7. t.render = render;
  8. t.removeElement = removeElement;
  9. t.updateTitle = updateTitle;
  10. t.activateButton = activateButton;
  11. t.deactivateButton = deactivateButton;
  12. t.disableButton = disableButton;
  13. t.enableButton = enableButton;
  14. t.getViewsWithButtons = getViewsWithButtons;
  15. t.el = null; // mirrors local `el`
  16. // locals
  17. var el;
  18. var viewsWithButtons = [];
  19. var tm;
  20. // can be called repeatedly and will rerender
  21. function render() {
  22. var options = calendar.options;
  23. var sections = options.header;
  24. tm = options.theme ? 'ui' : 'fc';
  25. if (sections) {
  26. if (!el) {
  27. el = this.el = $("<div class='fc-toolbar'/>");
  28. }
  29. else {
  30. el.empty();
  31. }
  32. el.append(renderSection('left'))
  33. .append(renderSection('right'))
  34. .append(renderSection('center'))
  35. .append('<div class="fc-clear"/>');
  36. }
  37. else {
  38. removeElement();
  39. }
  40. }
  41. function removeElement() {
  42. if (el) {
  43. el.remove();
  44. el = t.el = null;
  45. }
  46. }
  47. function renderSection(position) {
  48. var sectionEl = $('<div class="fc-' + position + '"/>');
  49. var options = calendar.options;
  50. var buttonStr = options.header[position];
  51. if (buttonStr) {
  52. $.each(buttonStr.split(' '), function(i) {
  53. var groupChildren = $();
  54. var isOnlyButtons = true;
  55. var groupEl;
  56. $.each(this.split(','), function(j, buttonName) {
  57. var customButtonProps;
  58. var viewSpec;
  59. var buttonClick;
  60. var overrideText; // text explicitly set by calendar's constructor options. overcomes icons
  61. var defaultText;
  62. var themeIcon;
  63. var normalIcon;
  64. var innerHtml;
  65. var classes;
  66. var button; // the element
  67. if (buttonName == 'title') {
  68. groupChildren = groupChildren.add($('<h2>&nbsp;</h2>')); // we always want it to take up height
  69. isOnlyButtons = false;
  70. }
  71. else {
  72. if ((customButtonProps = (options.customButtons || {})[buttonName])) {
  73. buttonClick = function(ev) {
  74. if (customButtonProps.click) {
  75. customButtonProps.click.call(button[0], ev);
  76. }
  77. };
  78. overrideText = ''; // icons will override text
  79. defaultText = customButtonProps.text;
  80. }
  81. else if ((viewSpec = calendar.getViewSpec(buttonName))) {
  82. buttonClick = function() {
  83. calendar.changeView(buttonName);
  84. };
  85. viewsWithButtons.push(buttonName);
  86. overrideText = viewSpec.buttonTextOverride;
  87. defaultText = viewSpec.buttonTextDefault;
  88. }
  89. else if (calendar[buttonName]) { // a calendar method
  90. buttonClick = function() {
  91. calendar[buttonName]();
  92. };
  93. overrideText = (calendar.overrides.buttonText || {})[buttonName];
  94. defaultText = options.buttonText[buttonName]; // everything else is considered default
  95. }
  96. if (buttonClick) {
  97. themeIcon =
  98. customButtonProps ?
  99. customButtonProps.themeIcon :
  100. options.themeButtonIcons[buttonName];
  101. normalIcon =
  102. customButtonProps ?
  103. customButtonProps.icon :
  104. options.buttonIcons[buttonName];
  105. if (overrideText) {
  106. innerHtml = htmlEscape(overrideText);
  107. }
  108. else if (themeIcon && options.theme) {
  109. innerHtml = "<span class='ui-icon ui-icon-" + themeIcon + "'></span>";
  110. }
  111. else if (normalIcon && !options.theme) {
  112. innerHtml = "<span class='fc-icon fc-icon-" + normalIcon + "'></span>";
  113. }
  114. else {
  115. innerHtml = htmlEscape(defaultText);
  116. }
  117. classes = [
  118. 'fc-' + buttonName + '-button',
  119. tm + '-button',
  120. tm + '-state-default'
  121. ];
  122. button = $( // type="button" so that it doesn't submit a form
  123. '<button type="button" class="' + classes.join(' ') + '">' +
  124. innerHtml +
  125. '</button>'
  126. )
  127. .click(function(ev) {
  128. // don't process clicks for disabled buttons
  129. if (!button.hasClass(tm + '-state-disabled')) {
  130. buttonClick(ev);
  131. // after the click action, if the button becomes the "active" tab, or disabled,
  132. // it should never have a hover class, so remove it now.
  133. if (
  134. button.hasClass(tm + '-state-active') ||
  135. button.hasClass(tm + '-state-disabled')
  136. ) {
  137. button.removeClass(tm + '-state-hover');
  138. }
  139. }
  140. })
  141. .mousedown(function() {
  142. // the *down* effect (mouse pressed in).
  143. // only on buttons that are not the "active" tab, or disabled
  144. button
  145. .not('.' + tm + '-state-active')
  146. .not('.' + tm + '-state-disabled')
  147. .addClass(tm + '-state-down');
  148. })
  149. .mouseup(function() {
  150. // undo the *down* effect
  151. button.removeClass(tm + '-state-down');
  152. })
  153. .hover(
  154. function() {
  155. // the *hover* effect.
  156. // only on buttons that are not the "active" tab, or disabled
  157. button
  158. .not('.' + tm + '-state-active')
  159. .not('.' + tm + '-state-disabled')
  160. .addClass(tm + '-state-hover');
  161. },
  162. function() {
  163. // undo the *hover* effect
  164. button
  165. .removeClass(tm + '-state-hover')
  166. .removeClass(tm + '-state-down'); // if mouseleave happens before mouseup
  167. }
  168. );
  169. groupChildren = groupChildren.add(button);
  170. }
  171. }
  172. });
  173. if (isOnlyButtons) {
  174. groupChildren
  175. .first().addClass(tm + '-corner-left').end()
  176. .last().addClass(tm + '-corner-right').end();
  177. }
  178. if (groupChildren.length > 1) {
  179. groupEl = $('<div/>');
  180. if (isOnlyButtons) {
  181. groupEl.addClass('fc-button-group');
  182. }
  183. groupEl.append(groupChildren);
  184. sectionEl.append(groupEl);
  185. }
  186. else {
  187. sectionEl.append(groupChildren); // 1 or 0 children
  188. }
  189. });
  190. }
  191. return sectionEl;
  192. }
  193. function updateTitle(text) {
  194. if (el) {
  195. el.find('h2').text(text);
  196. }
  197. }
  198. function activateButton(buttonName) {
  199. if (el) {
  200. el.find('.fc-' + buttonName + '-button')
  201. .addClass(tm + '-state-active');
  202. }
  203. }
  204. function deactivateButton(buttonName) {
  205. if (el) {
  206. el.find('.fc-' + buttonName + '-button')
  207. .removeClass(tm + '-state-active');
  208. }
  209. }
  210. function disableButton(buttonName) {
  211. if (el) {
  212. el.find('.fc-' + buttonName + '-button')
  213. .prop('disabled', true)
  214. .addClass(tm + '-state-disabled');
  215. }
  216. }
  217. function enableButton(buttonName) {
  218. if (el) {
  219. el.find('.fc-' + buttonName + '-button')
  220. .prop('disabled', false)
  221. .removeClass(tm + '-state-disabled');
  222. }
  223. }
  224. function getViewsWithButtons() {
  225. return viewsWithButtons;
  226. }
  227. }