Toolbar.js 6.9 KB

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