imagelessmenubuttonrenderer.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview An alternative custom button renderer that uses even more CSS
  16. * voodoo than the default implementation to render custom buttons with fake
  17. * rounded corners and dimensionality (via a subtle flat shadow on the bottom
  18. * half of the button) without the use of images.
  19. *
  20. * Based on the Custom Buttons 3.1 visual specification, see
  21. * http://go/custombuttons
  22. *
  23. * @author eae@google.com (Emil A Eklund)
  24. * @see ../demos/imagelessmenubutton.html
  25. */
  26. goog.provide('goog.ui.ImagelessMenuButtonRenderer');
  27. goog.require('goog.dom');
  28. goog.require('goog.dom.TagName');
  29. goog.require('goog.dom.classlist');
  30. goog.require('goog.ui.INLINE_BLOCK_CLASSNAME');
  31. goog.require('goog.ui.MenuButton');
  32. goog.require('goog.ui.MenuButtonRenderer');
  33. goog.require('goog.ui.registry');
  34. /**
  35. * Custom renderer for {@link goog.ui.MenuButton}s. Imageless buttons can
  36. * contain almost arbitrary HTML content, will flow like inline elements, but
  37. * can be styled like block-level elements.
  38. *
  39. * @deprecated These contain a lot of unnecessary DOM for modern user agents.
  40. * Please use a simpler button renderer like css3buttonrenderer.
  41. * @constructor
  42. * @extends {goog.ui.MenuButtonRenderer}
  43. * @final
  44. */
  45. goog.ui.ImagelessMenuButtonRenderer = function() {
  46. goog.ui.MenuButtonRenderer.call(this);
  47. };
  48. goog.inherits(goog.ui.ImagelessMenuButtonRenderer, goog.ui.MenuButtonRenderer);
  49. goog.addSingletonGetter(goog.ui.ImagelessMenuButtonRenderer);
  50. /**
  51. * Default CSS class to be applied to the root element of components rendered
  52. * by this renderer.
  53. * @type {string}
  54. */
  55. goog.ui.ImagelessMenuButtonRenderer.CSS_CLASS =
  56. goog.getCssName('goog-imageless-button');
  57. /** @override */
  58. goog.ui.ImagelessMenuButtonRenderer.prototype.getContentElement = function(
  59. element) {
  60. if (element) {
  61. var captionElem = goog.dom.getElementsByTagNameAndClass(
  62. '*', goog.getCssName(this.getCssClass(), 'caption'), element)[0];
  63. return captionElem;
  64. }
  65. return null;
  66. };
  67. /**
  68. * Returns true if this renderer can decorate the element. Overrides
  69. * {@link goog.ui.MenuButtonRenderer#canDecorate} by returning true if the
  70. * element is a DIV, false otherwise.
  71. * @param {Element} element Element to decorate.
  72. * @return {boolean} Whether the renderer can decorate the element.
  73. * @override
  74. */
  75. goog.ui.ImagelessMenuButtonRenderer.prototype.canDecorate = function(element) {
  76. return element.tagName == goog.dom.TagName.DIV;
  77. };
  78. /**
  79. * Takes a text caption or existing DOM structure, and returns the content
  80. * wrapped in a pseudo-rounded-corner box. Creates the following DOM structure:
  81. *
  82. * <div class="goog-inline-block goog-imageless-button">
  83. * <div class="goog-inline-block goog-imageless-button-outer-box">
  84. * <div class="goog-imageless-button-inner-box">
  85. * <div class="goog-imageless-button-pos-box">
  86. * <div class="goog-imageless-button-top-shadow">&nbsp;</div>
  87. * <div class="goog-imageless-button-content
  88. * goog-imageless-menubutton-caption">Contents...
  89. * </div>
  90. * <div class="goog-imageless-menubutton-dropdown"></div>
  91. * </div>
  92. * </div>
  93. * </div>
  94. * </div>
  95. *
  96. * Used by both {@link #createDom} and {@link #decorate}. To be overridden
  97. * by subclasses.
  98. * @param {goog.ui.ControlContent} content Text caption or DOM structure to wrap
  99. * in a box.
  100. * @param {goog.dom.DomHelper} dom DOM helper, used for document interaction.
  101. * @return {!Element} Pseudo-rounded-corner box containing the content.
  102. * @override
  103. */
  104. goog.ui.ImagelessMenuButtonRenderer.prototype.createButton = function(
  105. content, dom) {
  106. var baseClass = this.getCssClass();
  107. var inlineBlock = goog.ui.INLINE_BLOCK_CLASSNAME + ' ';
  108. return dom.createDom(
  109. goog.dom.TagName.DIV,
  110. inlineBlock + goog.getCssName(baseClass, 'outer-box'),
  111. dom.createDom(
  112. goog.dom.TagName.DIV,
  113. inlineBlock + goog.getCssName(baseClass, 'inner-box'),
  114. dom.createDom(
  115. goog.dom.TagName.DIV, goog.getCssName(baseClass, 'pos'),
  116. dom.createDom(
  117. goog.dom.TagName.DIV,
  118. goog.getCssName(baseClass, 'top-shadow'), '\u00A0'),
  119. dom.createDom(
  120. goog.dom.TagName.DIV,
  121. [
  122. goog.getCssName(baseClass, 'content'),
  123. goog.getCssName(baseClass, 'caption'),
  124. goog.getCssName('goog-inline-block')
  125. ],
  126. content),
  127. dom.createDom(goog.dom.TagName.DIV, [
  128. goog.getCssName(baseClass, 'dropdown'),
  129. goog.getCssName('goog-inline-block')
  130. ]))));
  131. };
  132. /**
  133. * Check if the button's element has a box structure.
  134. * @param {goog.ui.Button} button Button instance whose structure is being
  135. * checked.
  136. * @param {Element} element Element of the button.
  137. * @return {boolean} Whether the element has a box structure.
  138. * @protected
  139. * @override
  140. */
  141. goog.ui.ImagelessMenuButtonRenderer.prototype.hasBoxStructure = function(
  142. button, element) {
  143. var outer = button.getDomHelper().getFirstElementChild(element);
  144. var outerClassName = goog.getCssName(this.getCssClass(), 'outer-box');
  145. if (outer && goog.dom.classlist.contains(outer, outerClassName)) {
  146. var inner = button.getDomHelper().getFirstElementChild(outer);
  147. var innerClassName = goog.getCssName(this.getCssClass(), 'inner-box');
  148. if (inner && goog.dom.classlist.contains(inner, innerClassName)) {
  149. var pos = button.getDomHelper().getFirstElementChild(inner);
  150. var posClassName = goog.getCssName(this.getCssClass(), 'pos');
  151. if (pos && goog.dom.classlist.contains(pos, posClassName)) {
  152. var shadow = button.getDomHelper().getFirstElementChild(pos);
  153. var shadowClassName = goog.getCssName(this.getCssClass(), 'top-shadow');
  154. if (shadow && goog.dom.classlist.contains(shadow, shadowClassName)) {
  155. var content = button.getDomHelper().getNextElementSibling(shadow);
  156. var contentClassName = goog.getCssName(this.getCssClass(), 'content');
  157. if (content &&
  158. goog.dom.classlist.contains(content, contentClassName)) {
  159. // We have a proper box structure.
  160. return true;
  161. }
  162. }
  163. }
  164. }
  165. }
  166. return false;
  167. };
  168. /**
  169. * Returns the CSS class to be applied to the root element of components
  170. * rendered using this renderer.
  171. * @return {string} Renderer-specific CSS class.
  172. * @override
  173. */
  174. goog.ui.ImagelessMenuButtonRenderer.prototype.getCssClass = function() {
  175. return goog.ui.ImagelessMenuButtonRenderer.CSS_CLASS;
  176. };
  177. // Register a decorator factory function for
  178. // goog.ui.ImagelessMenuButtonRenderer. Since we're using goog-imageless-button
  179. // as the base class in order to get the same styling as
  180. // goog.ui.ImagelessButtonRenderer, we need to be explicit about giving
  181. // goog-imageless-menu-button here.
  182. goog.ui.registry.setDecoratorByClassName(
  183. goog.getCssName('goog-imageless-menu-button'), function() {
  184. return new goog.ui.MenuButton(
  185. null, null, goog.ui.ImagelessMenuButtonRenderer.getInstance());
  186. });