buttonrenderer.js 7.3 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 Renderer for {@link goog.ui.Button}s in App style.
  16. *
  17. * Based on ImagelessButtonRender. Uses even more CSS voodoo than the default
  18. * implementation to render custom buttons with fake rounded corners and
  19. * dimensionality (via a subtle flat shadow on the bottom half of the button)
  20. * without the use of images.
  21. *
  22. * Based on the Custom Buttons 3.1 visual specification, see
  23. * http://go/custombuttons
  24. *
  25. * @author eae@google.com (Emil A Eklund)
  26. */
  27. goog.provide('goog.ui.style.app.ButtonRenderer');
  28. goog.require('goog.dom.TagName');
  29. goog.require('goog.dom.classlist');
  30. goog.require('goog.ui.Button');
  31. goog.require('goog.ui.CustomButtonRenderer');
  32. goog.require('goog.ui.INLINE_BLOCK_CLASSNAME');
  33. goog.require('goog.ui.registry');
  34. /**
  35. * Custom renderer for {@link goog.ui.Button}s. Imageless buttons can contain
  36. * almost arbitrary HTML content, will flow like inline elements, but can be
  37. * styled like block-level elements.
  38. *
  39. * @constructor
  40. * @extends {goog.ui.CustomButtonRenderer}
  41. */
  42. goog.ui.style.app.ButtonRenderer = function() {
  43. goog.ui.CustomButtonRenderer.call(this);
  44. };
  45. goog.inherits(goog.ui.style.app.ButtonRenderer, goog.ui.CustomButtonRenderer);
  46. goog.addSingletonGetter(goog.ui.style.app.ButtonRenderer);
  47. /**
  48. * Default CSS class to be applied to the root element of components rendered
  49. * by this renderer.
  50. * @type {string}
  51. */
  52. goog.ui.style.app.ButtonRenderer.CSS_CLASS = goog.getCssName('goog-button');
  53. /**
  54. * Array of arrays of CSS classes that we want composite classes added and
  55. * removed for in IE6 and lower as a workaround for lack of multi-class CSS
  56. * selector support.
  57. * @type {Array<Array<string>>}
  58. */
  59. goog.ui.style.app.ButtonRenderer.IE6_CLASS_COMBINATIONS = [];
  60. /**
  61. * Returns the button's contents wrapped in the following DOM structure:
  62. *
  63. * <div class="goog-inline-block goog-button-base goog-button">
  64. * <div class="goog-inline-block goog-button-base-outer-box">
  65. * <div class="goog-button-base-inner-box">
  66. * <div class="goog-button-base-pos">
  67. * <div class="goog-button-base-top-shadow">&nbsp;</div>
  68. * <div class="goog-button-base-content">Contents...</div>
  69. * </div>
  70. * </div>
  71. * </div>
  72. * </div>
  73. * @override
  74. */
  75. goog.ui.style.app.ButtonRenderer.prototype.createDom;
  76. /** @override */
  77. goog.ui.style.app.ButtonRenderer.prototype.getContentElement = function(
  78. element) {
  79. return element && /** @type {Element} */ (
  80. element.firstChild.firstChild.firstChild.lastChild);
  81. };
  82. /**
  83. * Takes a text caption or existing DOM structure, and returns the content
  84. * wrapped in a pseudo-rounded-corner box. Creates the following DOM structure:
  85. *
  86. * <div class="goog-inline-block goog-button-base-outer-box">
  87. * <div class="goog-inline-block goog-button-base-inner-box">
  88. * <div class="goog-button-base-pos">
  89. * <div class="goog-button-base-top-shadow">&nbsp;</div>
  90. * <div class="goog-button-base-content">Contents...</div>
  91. * </div>
  92. * </div>
  93. * </div>
  94. *
  95. * Used by both {@link #createDom} and {@link #decorate}. To be overridden
  96. * by subclasses.
  97. * @param {goog.ui.ControlContent} content Text caption or DOM structure to wrap
  98. * in a box.
  99. * @param {goog.dom.DomHelper} dom DOM helper, used for document interaction.
  100. * @return {Element} Pseudo-rounded-corner box containing the content.
  101. * @override
  102. */
  103. goog.ui.style.app.ButtonRenderer.prototype.createButton = function(
  104. content, dom) {
  105. var baseClass = this.getStructuralCssClass();
  106. var inlineBlock = goog.ui.INLINE_BLOCK_CLASSNAME + ' ';
  107. return dom.createDom(
  108. goog.dom.TagName.DIV,
  109. inlineBlock + goog.getCssName(baseClass, 'outer-box'),
  110. dom.createDom(
  111. goog.dom.TagName.DIV,
  112. inlineBlock + goog.getCssName(baseClass, 'inner-box'),
  113. dom.createDom(
  114. goog.dom.TagName.DIV, goog.getCssName(baseClass, 'pos'),
  115. dom.createDom(
  116. goog.dom.TagName.DIV,
  117. goog.getCssName(baseClass, 'top-shadow'), '\u00A0'),
  118. dom.createDom(
  119. goog.dom.TagName.DIV, goog.getCssName(baseClass, 'content'),
  120. content))));
  121. };
  122. /**
  123. * Check if the button's element has a box structure.
  124. * @param {goog.ui.Button} button Button instance whose structure is being
  125. * checked.
  126. * @param {Element} element Element of the button.
  127. * @return {boolean} Whether the element has a box structure.
  128. * @protected
  129. * @override
  130. */
  131. goog.ui.style.app.ButtonRenderer.prototype.hasBoxStructure = function(
  132. button, element) {
  133. var baseClass = this.getStructuralCssClass();
  134. var outer = button.getDomHelper().getFirstElementChild(element);
  135. var outerClassName = goog.getCssName(baseClass, 'outer-box');
  136. if (outer && goog.dom.classlist.contains(outer, outerClassName)) {
  137. var inner = button.getDomHelper().getFirstElementChild(outer);
  138. var innerClassName = goog.getCssName(baseClass, 'inner-box');
  139. if (inner && goog.dom.classlist.contains(inner, innerClassName)) {
  140. var pos = button.getDomHelper().getFirstElementChild(inner);
  141. var posClassName = goog.getCssName(baseClass, 'pos');
  142. if (pos && goog.dom.classlist.contains(pos, posClassName)) {
  143. var shadow = button.getDomHelper().getFirstElementChild(pos);
  144. var shadowClassName = goog.getCssName(baseClass, 'top-shadow');
  145. if (shadow && goog.dom.classlist.contains(shadow, shadowClassName)) {
  146. var content = button.getDomHelper().getNextElementSibling(shadow);
  147. var contentClassName = goog.getCssName(baseClass, 'content');
  148. if (content &&
  149. goog.dom.classlist.contains(content, contentClassName)) {
  150. // We have a proper box structure.
  151. return true;
  152. }
  153. }
  154. }
  155. }
  156. }
  157. return false;
  158. };
  159. /** @override */
  160. goog.ui.style.app.ButtonRenderer.prototype.getCssClass = function() {
  161. return goog.ui.style.app.ButtonRenderer.CSS_CLASS;
  162. };
  163. /** @override */
  164. goog.ui.style.app.ButtonRenderer.prototype.getStructuralCssClass = function() {
  165. // TODO(user): extract to a constant.
  166. return goog.getCssName('goog-button-base');
  167. };
  168. /** @override */
  169. goog.ui.style.app.ButtonRenderer.prototype.getIe6ClassCombinations =
  170. function() {
  171. return goog.ui.style.app.ButtonRenderer.IE6_CLASS_COMBINATIONS;
  172. };
  173. // Register a decorator factory function for goog.ui.style.app.ButtonRenderer.
  174. goog.ui.registry.setDecoratorByClassName(
  175. goog.ui.style.app.ButtonRenderer.CSS_CLASS, function() {
  176. return new goog.ui.Button(
  177. null, goog.ui.style.app.ButtonRenderer.getInstance());
  178. });