// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Native browser button renderer for {@link goog.ui.Button}s.
 *
 * @author attila@google.com (Attila Bodis)
 */

goog.provide('goog.ui.NativeButtonRenderer');

goog.require('goog.asserts');
goog.require('goog.dom.InputType');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.events.EventType');
goog.require('goog.ui.ButtonRenderer');
goog.require('goog.ui.Component');



/**
 * Renderer for {@link goog.ui.Button}s.  Renders and decorates native HTML
 * button elements.  Since native HTML buttons have built-in support for many
 * features, overrides many expensive (and redundant) superclass methods to
 * be no-ops.
 * @constructor
 * @extends {goog.ui.ButtonRenderer}
 */
goog.ui.NativeButtonRenderer = function() {
  goog.ui.ButtonRenderer.call(this);
};
goog.inherits(goog.ui.NativeButtonRenderer, goog.ui.ButtonRenderer);
goog.addSingletonGetter(goog.ui.NativeButtonRenderer);


/** @override */
goog.ui.NativeButtonRenderer.prototype.getAriaRole = function() {
  // Native buttons don't need ARIA roles to be recognized by screen readers.
  return undefined;
};


/**
 * Returns the button's contents wrapped in a native HTML button element.  Sets
 * the button's disabled attribute as needed.
 * @param {goog.ui.Control} button Button to render.
 * @return {Element} Root element for the button (a native HTML button element).
 * @override
 */
goog.ui.NativeButtonRenderer.prototype.createDom = function(button) {
  this.setUpNativeButton_(button);
  return button.getDomHelper().createDom(
      goog.dom.TagName.BUTTON, {
        'class': this.getClassNames(button).join(' '),
        'disabled': !button.isEnabled(),
        'title': button.getTooltip() || '',
        'value': button.getValue() || ''
      },
      button.getCaption() || '');
};


/**
 * Overrides {@link goog.ui.ButtonRenderer#canDecorate} by returning true only
 * if the element is an HTML button.
 * @param {Element} element Element to decorate.
 * @return {boolean} Whether the renderer can decorate the element.
 * @override
 */
goog.ui.NativeButtonRenderer.prototype.canDecorate = function(element) {
  return element.tagName == goog.dom.TagName.BUTTON ||
      (element.tagName == goog.dom.TagName.INPUT &&
       (element.type == goog.dom.InputType.BUTTON ||
        element.type == goog.dom.InputType.SUBMIT ||
        element.type == goog.dom.InputType.RESET));
};


/** @override */
goog.ui.NativeButtonRenderer.prototype.decorate = function(button, element) {
  this.setUpNativeButton_(button);
  if (element.disabled) {
    // Add the marker class for the DISABLED state before letting the superclass
    // implementation decorate the element, so its state will be correct.
    var disabledClassName = goog.asserts.assertString(
        this.getClassForState(goog.ui.Component.State.DISABLED));
    goog.dom.classlist.add(element, disabledClassName);
  }
  return goog.ui.NativeButtonRenderer.superClass_.decorate.call(
      this, button, element);
};


/**
 * Native buttons natively support BiDi and keyboard focus.
 * @suppress {visibility} getHandler and performActionInternal
 * @override
 */
goog.ui.NativeButtonRenderer.prototype.initializeDom = function(button) {
  // WARNING:  This is a hack, and it is only applicable to native buttons,
  // which are special because they do natively what most goog.ui.Controls
  // do programmatically.  Do not use your renderer's initializeDom method
  // to hook up event handlers!
  button.getHandler().listen(
      button.getElement(), goog.events.EventType.CLICK,
      button.performActionInternal);
};


/**
 * @override
 * Native buttons don't support text selection.
 */
goog.ui.NativeButtonRenderer.prototype.setAllowTextSelection =
    goog.nullFunction;


/**
 * @override
 * Native buttons natively support right-to-left rendering.
 */
goog.ui.NativeButtonRenderer.prototype.setRightToLeft = goog.nullFunction;


/**
 * @override
 * Native buttons are always focusable as long as they are enabled.
 */
goog.ui.NativeButtonRenderer.prototype.isFocusable = function(button) {
  return button.isEnabled();
};


/**
 * @override
 * Native buttons natively support keyboard focus.
 */
goog.ui.NativeButtonRenderer.prototype.setFocusable = goog.nullFunction;


/**
 * @override
 * Native buttons also expose the DISABLED state in the HTML button's
 * `disabled` attribute.
 */
goog.ui.NativeButtonRenderer.prototype.setState = function(
    button, state, enable) {
  goog.ui.NativeButtonRenderer.superClass_.setState.call(
      this, button, state, enable);
  var element = button.getElement();
  if (element && state == goog.ui.Component.State.DISABLED) {
    element.disabled = enable;
  }
};


/**
 * @override
 * Native buttons store their value in the HTML button's `value`
 * attribute.
 */
goog.ui.NativeButtonRenderer.prototype.getValue = function(element) {
  // TODO(attila): Make this work on IE!  This never worked...
  // See http://www.fourmilab.ch/fourmilog/archives/2007-03/000824.html
  // for a description of the problem.
  return element.value;
};


/**
 * @override
 * Native buttons also expose their value in the HTML button's `value`
 * attribute.
 */
goog.ui.NativeButtonRenderer.prototype.setValue = function(element, value) {
  if (element) {
    // TODO(attila): Make this work on IE!  This never worked...
    // See http://www.fourmilab.ch/fourmilog/archives/2007-03/000824.html
    // for a description of the problem.
    element.value = value;
  }
};


/**
 * @override
 * Native buttons don't need ARIA states to support accessibility, so this is
 * a no-op.
 */
goog.ui.NativeButtonRenderer.prototype.updateAriaState = goog.nullFunction;


/**
 * Sets up the button control such that it doesn't waste time adding
 * functionality that is already natively supported by native browser
 * buttons.
 * @param {goog.ui.Control} button Button control to configure.
 * @private
 */
goog.ui.NativeButtonRenderer.prototype.setUpNativeButton_ = function(button) {
  button.setHandleMouseEvents(false);
  button.setAutoStates(goog.ui.Component.State.ALL, false);
  button.setSupportedState(goog.ui.Component.State.FOCUSED, false);
};
