// Copyright (C) Plan-A Software Ltd. All Rights Reserved.
//
// Written by Kiran Lakhotia <kiran@plan-a-software.co.uk>, 2014
//
// 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.
//
'use strict';
goog.provide('plana.ui.BootstrapDialog');
goog.require('goog.a11y.aria.Role');
goog.require('goog.a11y.aria.State');
goog.require('goog.dom.ViewportSizeMonitor');
goog.require('goog.dom.classes');
goog.require('goog.dom.dataset');
goog.require('goog.dom.safe');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.html.SafeHtml');
goog.require('goog.ui.Component.EventType');
goog.require('goog.ui.ModalPopup');
/**
* This class is a re-implementation of {@link goog.ui.Dialog} to
* create a bootstrap (css style) compatible modal dialog
* @constructor
* @extends {goog.ui.ModalPopup}
* @param {goog.dom.DomHelper=} opt_domHelper Optional dom helper
*/
plana.ui.BootstrapDialog = function(opt_domHelper) {
goog.ui.ModalPopup.call(this, false, opt_domHelper);
/**
* The header element
* @type {?Element}
* @private
*/
this.headerEl_ = null;
/**
* The dialog close button
* @type {?HTMLButtonElement}
* @private
*/
this.closeBtn_ = null;
/**
* The dialog title element
* @type {?Element}
* @private
*/
this.titleEl_ = null;
/**
* The dialog content element
* (contains header, body, footere)
* @type {?Element}
* @private
*/
this.contentEl_ = null;
/**
* The dialog body element
* @type {?Element}
* @private
*/
this.bodyEl_ = null;
/**
* The dialog footer element
* @type {?Element}
* @private
*/
this.footerEl_ = null;
/**
* The title text or HTML
* @type {?(string|Element)}
* @private
*/
this.title_ = null;
/**
* The body text or HTML
* @type {?(string|Element|goog.html.SafeHtml)}
* @private
*/
this.bodyContent_ = null;
/**
* The footer text or HTML
* @type {?(string|Element)}
* @private
*/
this.footer_ = null;
/**
* The container element for buttons
* @type {?Element}
* @private
*/
this.buttonEl_ = null;
/**
* Flag whether we should dispose the dialog
* on hiding
* @type {boolean}
* @private
*/
this.disposeOnHide_ = false;
/**
* The dialog's preferred ARIA role
* @type {goog.a11y.aria.Role}
* @private
*/
this.preferredAriaRole_ = goog.a11y.aria.Role.DIALOG;
/**
* Flag whether the escape key dismisses
* the dialog
* @type {boolean}
* @private
*/
this.escapeToCancel_ = true;
/**
* The array of action buttons. They will be
* rendered in the order they are added
* @type {Array.<HTMLButtonElement>}
* @private
*/
this.actionButtons_ = [];
/**
* Viewportsize monitor
* @type {goog.dom.ViewportSizeMonitor}
* @private
*/
this.vm_ = new goog.dom.ViewportSizeMonitor();
};
goog.inherits(plana.ui.BootstrapDialog, goog.ui.ModalPopup);
/**
* @override
* @suppress {checkTypes}
*/
plana.ui.BootstrapDialog.prototype.disposeInternal = function() {
plana.ui.BootstrapDialog.superClass_.disposeInternal.call(this);
this.headerEl_ = null;
this.closeBtn_ = null;
this.titleEl_ = null;
this.contentEl_ = null;
this.bodyEl_ = null;
this.footerEl_ = null;
this.title_ = null;
this.bodyContent_ = null;
this.footer_ = null;
this.disposeOnHide_ = null;
this.preferredAriaRole_ = null;
this.escapeToCancel_ = null;
this.actionButtons_.length = 0;
this.actionButtons_ = null;
this.buttonEl_ = null;
this.vm_.dispose();
this.vm_ = null;
};
/**
* @override
*/
plana.ui.BootstrapDialog.prototype.getCssClass = function() {
return 'modal';
};
/**
* Yes we can!
* @param {Element} element Element to decorate
* @return {boolean} True if the element can be decorated, false otherwise
* @override
*/
plana.ui.BootstrapDialog.prototype.canDecorate = function(element) {
return true;
};
/**
* @override
*/
plana.ui.BootstrapDialog.prototype.createDom = function() {
plana.ui.BootstrapDialog.superClass_.createDom.call(this);
var dom = this.dom_;
var root = this.getElement();
var dlg = dom.createDom('div', {
'class': 'modal-dialog'
});
dom.appendChild(root, dlg);
this.contentEl_ = dom.createDom('div', {
'class': 'modal-content'
});
dom.appendChild(dlg, this.contentEl_);
this.headerEl_ = dom.createDom('div', {
'class': 'modal-header'
});
dom.appendChild(this.contentEl_, this.headerEl_);
this.closeBtn_ = /**@type {HTMLButtonElement}*/ (dom.createDom('button', {
'type': 'button',
'class': 'close',
'aria-hidden': true
}, dom.htmlToDocumentFragment('×')));
dom.appendChild(this.headerEl_, this.closeBtn_);
this.titleEl_ = dom.createDom('h4', {
'class': 'modal-title'
});
dom.appendChild(this.headerEl_, this.titleEl_);
this.bodyEl_ = dom.createDom('div', {
'class': 'modal-body'
});
dom.appendChild(this.contentEl_, this.bodyEl_);
this.footerEl_ = dom.createDom('div', {
'class': 'modal-footer'
});
dom.appendChild(this.contentEl_, this.footerEl_);
this.buttonEl_ = dom.createDom('div');
dom.appendChild(this.footerEl_, this.buttonEl_);
//add buttons
dom.append(this.buttonEl_, this.actionButtons_);
goog.a11y.aria.setRole( /**@type {!Element}*/ (root),
this.getPreferredAriaRole());
goog.a11y.aria.setState( /**@type {!Element}*/ (root),
goog.a11y.aria.State.LABELLEDBY, '');
if (this.title_ != null)
this.setTitle(this.title_);
if (this.bodyContent_ != null)
this.setBodyContent(this.bodyContent_);
if (this.footer_ != null)
this.setFooter(this.footer_);
};
/**
* Decorates the element for the UI component. If the element is in the
* document, the enterDocument method will be called.
*
* Any buttons *must* be inside a 'modal-footer' element, otherwise they
* are not added to the set of handled buttons
*
* A cancel button must have 'data-dismiss' attribute and the default button
* a 'data-role' attribute set to the value 'default'
*
* @param {Element} element Element to decorate
* @override
*/
plana.ui.BootstrapDialog.prototype.decorateInternal = function(element) {
//call superclass to create background masks
plana.ui.BootstrapDialog.superClass_.decorateInternal.call(this, element);
goog.dom.setFocusableTabIndex(element, true);
goog.asserts.assert(this.getElement(), 'must have root');
goog.asserts.assert(goog.dom.classes.has(element, 'modal'),
'element must have modal class');
var dom = this.dom_;
var modalChildren = dom.getChildren(element);
goog.asserts.assert(modalChildren.length == 1,
'modal dialog must have only one child: modal-dialog');
/**
* @type {!Element}
*/
var dlg = modalChildren[0];
goog.asserts.assert(goog.dom.classes.has(dlg, 'modal-dialog'),
'the dialog element must have modal-dialog class');
var contentChildren = dom.getChildren(dlg);
goog.asserts.assert(contentChildren.length == 1,
'modal-dialog class element can only have one child: modal-content');
this.contentEl_ = /**@type {!Element}*/ (contentChildren[0]);
goog.asserts.assert(goog.dom.classes.has(this.contentEl_, 'modal-content'),
'the content element must have modal-content class');
var header = dom.getElementsByTagNameAndClass(null,
'modal-header', this.contentEl_);
if (header.length > 0)
this.headerEl_ = header[0];
var close = dom.getElementsByTagNameAndClass(null,
'close', this.contentEl_);
if (close.length > 0)
this.closeBtn_ = close[0];
var title = dom.getElementsByTagNameAndClass(null,
'modal-title', this.contentEl_);
if (title.length > 0) {
var titleEl = /**@type {!Element}*/ (title[0]);
goog.a11y.aria.setState( /**@type {!Element}*/ (element),
goog.a11y.aria.State.LABELLEDBY,
/**@type {string|undefined}*/
(titleEl['id']) || '');
}
var body = dom.getElementsByTagNameAndClass(null,
'modal-body', this.contentEl_);
if (body.length > 0)
this.bodyEl_ = body[0];
var footer = dom.getElementsByTagNameAndClass(null,
'modal-footer');
if (footer.length > 0) {
this.footerEl_ = /**@type {!Element}*/ (footer[0]);
var btns = dom.getElementsByTagNameAndClass('button',
null, this.footerEl_);
for (var i = 0, btn; btn = /**@type {!HTMLButtonElement}*/ (btns[i]);
++i) {
this.actionButtons_.push(btn);
}
}
};
/**
* @override
*/
plana.ui.BootstrapDialog.prototype.enterDocument = function() {
plana.ui.BootstrapDialog.superClass_.enterDocument.call(this);
var handler = this.getHandler();
var modal = this.getElement();
if (this.closeBtn_)
handler.listen(this.closeBtn_, goog.events.EventType.CLICK,
this.onClose_, false);
// Listen for keyboard events while the dialog is visible
handler.listen(modal, goog.events.EventType.KEYDOWN,
this.onKey_, false);
handler.listen(modal, goog.events.EventType.KEYPRESS,
this.onKey_, false);
handler.listen(this.vm_, goog.events.EventType.RESIZE,
this.onResize, false);
for (var i = 0, btn; btn = this.actionButtons_[i]; ++i) {
handler.listen(btn, goog.events.EventType.CLICK,
this.onButtonClick_, false);
}
};
/**
* @override
*/
plana.ui.BootstrapDialog.prototype.exitDocument = function() {
plana.ui.BootstrapDialog.superClass_.exitDocument.call(this);
var handler = this.getHandler();
var modal = this.getElement();
if (this.closeBtn_)
handler.unlisten(this.closeBtn_, goog.events.EventType.CLICK,
this.onClose_, false);
handler.unlisten(modal, goog.events.EventType.KEYDOWN,
this.onKey_, false);
handler.unlisten(modal, goog.events.EventType.KEYPRESS,
this.onKey_, false);
handler.unlisten(this.vm_, goog.events.EventType.RESIZE,
this.onResize, false);
for (var i = 0, btn; btn = this.actionButtons_[i]; ++i) {
handler.unlisten(btn, goog.events.EventType.CLICK,
this.onButtonClick_, false);
}
};
/**
* Callback for when viewport size changed. This simply re-centers the
* dialog
* @param {goog.events.Event} e
* @protected
*/
plana.ui.BootstrapDialog.prototype.onResize = function(e) {
this.reposition();
};
/**
* Handles buttons clicks. If the cancel button is clicked, this closes
* the dialog. Otherwise it fires a button event and lets the user
* decide what to do
* @param {goog.events.BrowserEvent} e Browser's event object
* @private
*/
plana.ui.BootstrapDialog.prototype.onButtonClick_ = function(e) {
var btn = /**@type {!HTMLButtonElement}*/ (e.target);
var caption = this.dom_.getTextContent(btn);
var key = this.getButtonKey_(btn);
var close = this.dispatchEvent({
type: goog.ui.Component.EventType.SELECT,
key: key,
caption: caption,
target: btn
});
if (close) {
this.setVisible(false);
}
};
/**
* This function returns the key associated with a button. We first
* check the name of a button, if that's not set, we check the id
* @param {!Node} btn The button whose key to return
* @return {!string} The button key
* @private
*/
plana.ui.BootstrapDialog.prototype.getButtonKey_ = function(btn) {
/**
* @type {string|undefined}
*/
var key = btn['name'];
if (!key || key == '')
key = /**@type {string|undefined}*/ (btn['id']);
return key ? key : '';
};
/**
* This function returns the cancel button if it exists
* @return {?HTMLButtonElement} The cancel button or null if non exists
* @private
*/
plana.ui.BootstrapDialog.prototype.getCancelButton_ = function() {
var css = this.getCssClass();
for (var i = 0, btn; btn = this.actionButtons_[i]; ++i) {
var dismiss = goog.dom.dataset.get(btn, 'dismiss');
if (dismiss && dismiss == css)
return btn;
}
return null;
};
/**
* This function returns the default button if it exists. It looks
* for 'data-role==default'
* @return {?HTMLButtonElement} The default button or null if non exists
* @private
*/
plana.ui.BootstrapDialog.prototype.getDefaultButton_ = function() {
for (var i = 0, btn; btn = this.actionButtons_[i]; ++i) {
var role = goog.dom.dataset.get(btn, 'role');
if (role && role == 'default')
return btn;
}
return null;
};
/**
* Handles keydown and keypress events, and dismisses the popup if cancel is
* pressed. If there is a cancel action in the ButtonSet, than that will be
* fired. Also prevents tabbing out of the dialog
* @param {goog.events.BrowserEvent} e Browser's event object
* @private
*/
plana.ui.BootstrapDialog.prototype.onKey_ = function(e) {
var close = false;
var hasHandler = false;
var hasButtons = this.actionButtons_.length > 0;
/**
* @type {!HTMLElement}
*/
var target = /**@type {!HTMLElement}*/ (e.target);
if (e.type == goog.events.EventType.KEYDOWN) {
// Escape and tab can only properly be handled in keydown handlers
if (this.escapeToCancel_ && e.keyCode == goog.events.KeyCodes.ESC) {
// Only if there is a valid cancel button is an event dispatched
var cancel = this.getCancelButton_();
// Users may expect to hit escape on a SELECT element
var isSpecialFormElement =
target.tagName == 'SELECT' &&
( /**@type {HTMLSelectElement}*/ (target)).disabled == false;
if (cancel && !isSpecialFormElement) {
hasHandler = true;
close = this.dispatchEvent({
type: goog.ui.Component.EventType.SELECT,
key: this.getButtonKey_(cancel),
caption: this.dom_.getTextContent(cancel),
target: cancel
});
} else if (!isSpecialFormElement) {
close = true;
}
} else if (e.keyCode == goog.events.KeyCodes.TAB && e.shiftKey &&
target == this.getElement()) {
// Prevent the user from shift-tabbing backwards out of the dialog box
// Instead, set up a wrap in focus backward to the end of the dialog
this.setupBackwardTabWrap();
}
} else if (e.keyCode == goog.events.KeyCodes.ENTER) {
// Only handle ENTER in keypress events, in case the action opens a
// popup window
/**
* @type {string | undefined}
*/
var key = undefined;
/**
* @type {string | undefined}
*/
var caption = undefined;
/**
* @type {HTMLButtonElement|undefined}
*/
var btnTarget;
if (target.tagName == 'BUTTON' &&
( /**@type {HTMLButtonElement}*/ (target)).disabled == false) {
// If the target is a button and it's enabled, we can fire that button's
// handler
key =
/**@type {string}*/
( /**@type {HTMLButtonElement}*/ (target).name);
caption = this.dom_.getTextContent(target);
btnTarget = /**@type {HTMLButtonElement}*/ (target);
} else if (hasButtons) {
// Try to fire the default button's handler (if one exists), but only if
// the button is enabled
/**
* @type {?HTMLButtonElement}
*/
var defaultButton = this.getDefaultButton_();
// Users may expect to hit enter on a TEXTAREA, SELECT or an A element
var isSpecialFormElement =
(target.tagName == 'TEXTAREA' || target.tagName == 'SELECT' ||
target.tagName == 'A') &&
( /**@type {HTMLSelectElement|HTMLTextAreaElement|HTMLAnchorElement}*/
(target)).disabled == false;
if (defaultButton &&
( /**@type {HTMLButtonElement}*/ (defaultButton)).disabled == false &&
isSpecialFormElement == false) {
key = this.getButtonKey_(defaultButton);
caption = this.dom_.getTextContent(defaultButton);
btnTarget = defaultButton;
}
}
if (key && hasButtons) {
hasHandler = true;
close = this.dispatchEvent({
type: goog.ui.Component.EventType.SELECT,
key: key,
caption: caption,
target: btnTarget
});
}
}
if (close || hasHandler) {
e.stopPropagation();
e.preventDefault();
}
if (close) {
this.setVisible(false);
}
};
/**
* Callback for closing the dialog
* @param {goog.events.BrowserEvent} e The click event
* @private
*/
plana.ui.BootstrapDialog.prototype.onClose_ = function(e) {
this.setVisible(false);
};
/**
* Setter for the title element
* @param {string|Element} title The title text or HTML content
*/
plana.ui.BootstrapDialog.prototype.setTitle = function(title) {
this.title_ = title;
if (this.titleEl_ != null) {
var dom = this.dom_;
if (goog.isString(title)) {
dom.setTextContent(this.titleEl_, title);
} else {
dom.appendChild(this.titleEl_, title);
}
}
};
/**
* Setter for the body element
* @param {string|Element|goog.html.SafeHtml} body The body text or HTML
*/
plana.ui.BootstrapDialog.prototype.setBodyContent = function(body) {
this.bodyContent_ = body;
if (this.bodyEl_) {
var dom = this.dom_;
dom.removeChildren(this.bodyEl_);
if (goog.isString(body)) {
dom.setTextContent(this.bodyEl_, body);
} else if (body instanceof goog.html.SafeHtml) {
goog.dom.safe.setInnerHtml(this.bodyEl_, body);
} else {
dom.appendChild(this.bodyEl_, body);
}
}
};
/**
* Allows arbitrary HTML to be set in the content element
* @param {!goog.html.SafeHtml} html Content HTML
*/
plana.ui.BootstrapDialog.prototype.setSafeHtmlContent = function(html) {
this.bodyContent_ = html;
if (this.bodyEl_) {
goog.dom.safe.setInnerHtml(this.bodyEl_, html);
}
};
/**
* Setter for the footer element
* @param {string|Element} footer The footer text or HTML content
*/
plana.ui.BootstrapDialog.prototype.setFooter = function(footer) {
this.footer_ = footer;
if (this.footerEl_ != null) {
var dom = this.dom_;
if (goog.isString(footer)) {
dom.setTextContent(this.footerEl_, footer);
} else {
dom.appendChild(this.footerEl_, footer);
}
}
};
/**
* @override
* @param {boolean} visible Whether to show or hide the dialog
*/
plana.ui.BootstrapDialog.prototype.setVisible = function(visible) {
if (visible == this.isVisible()) {
return;
}
var el = this.getElement();
if (!el) {
this.render();
el = this.getElement();
} else if (visible) {
this.enterDocument();
}
plana.ui.BootstrapDialog.superClass_.setVisible.call(this, visible);
if (visible) {
goog.style.setStyle(el, 'display', 'block');
if (goog.dom.classes.has(el, 'fade'))
goog.dom.classes.add(el, 'in');
//unfortuantely have to set focus again here, due to display issue
this.focus();
} else {
if (this.disposeOnHide_) {
/**
* @type {?plana.ui.BootstrapDialog}
*/
var self = this;
window.setTimeout(function() {
self.dispose();
self = null;
}, 0);
} else {
this.exitDocument();
if (goog.dom.classes.has(el, 'fade'))
goog.dom.classes.remove(el, 'in');
}
}
};
/**
* Focuses the dialog contents and the default dialog button if there is one
* @override
*/
plana.ui.BootstrapDialog.prototype.focus = function() {
plana.ui.BootstrapDialog.superClass_.focus.call(this);
// Move focus to the default button (if any)
if (this.actionButtons_.length > 0) {
var defaultButton = this.getDefaultButton_();
if (defaultButton && !defaultButton.disabled) {
var doc = this.dom_.getDocument();
try {
// Reopening a dialog can cause focusing the button to fail in
// WebKit and Opera. Shift the focus to a temporary <input>
// element to make refocusing the button possible
if (goog.userAgent.WEBKIT || goog.userAgent.OPERA) {
var temp = doc.createElement('input');
temp.style.cssText =
'position:fixed;width:0;height:0;left:0;top:0;';
this.getElement().appendChild(temp);
temp.focus();
this.getElement().removeChild(temp);
}
defaultButton.focus();
} catch (e) {
// Swallow this. Could be the button is disabled
// and IE6 wishes to throw an error
}
}
}
};
/**
* Gets the content HTML of the body element as a plain string.
*
* If the body element exists, then this returns the 'innerHTML'
* property. Otherwise it returns the content as set by the users,
* converted to a string
* @return {string} Content HTML
*/
plana.ui.BootstrapDialog.prototype.getBodyContentAsString = function() {
if (this.bodyEl_) {
return this.bodyEl_.innerHTML;
} else {
if (this.bodyContent_) {
if (goog.isString(this.bodyContent_))
return this.bodyContent_;
else if (this.bodyContent_ instanceof goog.html.SafeHtml)
return goog.html.SafeHtml.unwrap(this.bodyContent_);
else {
return this.dom_.getOuterHtml(this.bodyContent_);
}
}
}
return '';
};
/**
* Returns the dialog's preferred ARIA role. This can be used to override the
* default dialog role, e.g. with an ARIA role of ALERTDIALOG for a simple
* warning or confirmation dialog
* @return {goog.a11y.aria.Role} This dialog's preferred ARIA role
*/
plana.ui.BootstrapDialog.prototype.getPreferredAriaRole = function() {
return this.preferredAriaRole_;
};
/**
* Sets the dialog's preferred ARIA role. This can be used to override the
* default dialog role, e.g. with an ARIA role of ALERTDIALOG for a simple
* warning or confirmation dialog
* @param {goog.a11y.aria.Role} role This dialog's preferred ARIA role
*/
plana.ui.BootstrapDialog.prototype.setPreferredAriaRole = function(role) {
this.preferredAriaRole_ = role;
};
/**
* Returns the header element so that more complicated things can be done.
* Renders if the DOM is not yet created
* @return {?Element} The header element
*/
plana.ui.BootstrapDialog.prototype.getHeaderElement = function() {
if (this.getElement() == null)
this.render();
return this.headerEl_;
};
/**
* Returns the title element so that more complicated things can be done with
* the title. Renders if the DOM is not yet created
* @return {?Element} The title element
*/
plana.ui.BootstrapDialog.prototype.getTitleElement = function() {
if (this.getElement() == null)
this.render();
return this.titleEl_;
};
/**
* Returns the title close element so that more complicated things can be done
* with the close area of the title. Renders if the DOM is not yet created
* @return {?HTMLButtonElement} The close box
*/
plana.ui.BootstrapDialog.prototype.getTitleCloseElement = function() {
if (this.getElement() == null)
this.render();
return this.closeBtn_;
};
/**
* Returns the body element so that more complicated things can be done with
* the content area. Renders if the DOM is not yet created. Overrides
* {@link goog.ui.Component#getContentElement}
* @return {Element} The content element
* @override
*/
plana.ui.BootstrapDialog.prototype.getContentElement = function() {
if (this.getElement() == null)
this.render();
return this.bodyEl_;
};
/**
* Returns the footer element so that more complicated things can be done with
* it. Renders if the DOM is not yet created
* @return {?Element} The button container element
*/
plana.ui.BootstrapDialog.prototype.getFooter = function() {
if (this.getElement() == null)
this.render();
return this.footerEl_;
};
/**
* Returns the button element so that more complicated things can be done with
* the button area. Renders if the DOM is not yet created
* @return {?Element} The button container element
*/
plana.ui.BootstrapDialog.prototype.getButtonElement = function() {
if (this.getElement() == null)
this.render();
return this.buttonEl_;
};
/**
* Whether the dialog should be disposed off on close
* @param {boolean} b The value to set
*/
plana.ui.BootstrapDialog.prototype.setDisposeOnHide = function(b) {
this.disposeOnHide_ = b;
};
/**
* This function adds a button to the dialog. Buttons must be added before
* the dialog is rendered. A user can either add an existing button element,
* or a {key: string, caption: string} object that will be rendered as button
* @param {HTMLButtonElement|{key: string, caption: string}} button The button
* to add
* @param {boolean=} opt_isDefault Whether the button is the default button.
* Results in css class 'btn-primary' if the button parameter is not an
* existing HTML element
* @param {boolean=} opt_isCancel Whether this is a cancel button
* @param {string=} opt_css Optional css class to use for the button in case
* the button parameter is not an existing HTML element
*/
plana.ui.BootstrapDialog.prototype.addButton = function(
button, opt_isDefault, opt_isCancel, opt_css) {
goog.asserts.assert(button != null, 'button cannot be null');
var isDefault = opt_isDefault || false;
var isCancel = opt_isCancel || false;
/**
* @type {HTMLButtonElement}
*/
var buttonEl;
var dom = this.dom_;
if (!button['tagName']) {
var css;
if (isDefault) {
css = 'btn-primary';
} else {
css = opt_css ? opt_css : 'btn-default';
}
buttonEl = /**@type {HTMLButtonElement}*/ (dom.createDom('button', {
'type': 'button',
'class': 'btn ' + css,
'name': button.key
}, dom.createTextNode(button.caption)));
} else {
buttonEl = /**@type {HTMLButtonElement}*/ (button);
}
if (isCancel)
goog.dom.dataset.set(buttonEl, 'dismiss', this.getCssClass());
if (isDefault)
goog.dom.dataset.set(buttonEl, 'role', 'default');
this.actionButtons_.push(buttonEl);
if (this.buttonEl_)
dom.appendChild(this.buttonEl_, buttonEl);
};
/**
* This function returns the HTML of a button or null
* if the button is not found
* @param {!string} key The key of the button to get
* @return {?HTMLButtonElement} The button or null
*/
plana.ui.BootstrapDialog.prototype.getButton = function(key) {
for (var i = 0, btn; btn = this.actionButtons_[i]; ++i) {
var _key = this.getButtonKey_(btn);
if (_key == key)
return btn;
}
return null;
};