Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / framework / widgets / button / rw.button.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 import './button.scss';
20 import Loader from '../loading-indicator/loadingIndicator.jsx';
21 var React = require('react');
22 var ButtonEventListenerMixin = require('../mixins/ButtonEventListener.js');
23
24
25 /**
26 * A generic button component.
27 * It's props values and a brief description below
28 *
29 * Label: The label of the button. What it displays at any given time.
30 * Icon: A url for an icon that will be displayed on the button. Leave blank if no icon required.
31 * Class: Css Classes applied to the element.
32 * sizeOfButton: The preset sizes for the button (small, default, large, xlarge, expand).
33 * minWidth: Minimum Width of the button.
34 * maxWidth: Maximum Width of the button.
35 **/
36 module.exports = React.createClass({
37 displayName: "Button",
38 mixins:[ButtonEventListenerMixin],
39 propTypes: {
40 label: React.PropTypes.string,
41 icon: React.PropTypes.array,
42 className: React.PropTypes.string,
43 //sizeOfButton: React.PropTypes.string,
44 minWidth: React.PropTypes.string,
45 maxWidth: React.PropTypes.string,
46 //isActive: React.PropTypes.bool,
47 //isFocused: React.PropTypes.bool,
48 //isHovered: React.PropTypes.bool,
49 isDisabled: React.PropTypes.bool
50 },
51
52
53 /**
54 * Defines default state.
55 * sizeOfButton: See Prop type definitions.
56 * class: See Prop type definitions.
57 * label: See Prop type definitions.
58 * isActive: Boolean to indicate if button is active.
59 * isHovered: Boolean to indicate if the button is being hovered over.
60 * isFocused: Boolean to indicate if the button has been focused.
61 * isDisabled: Boolean to indicate if button has been disabled.
62 * @returns {{sizeOfButton: (*|string), class: *, isActive: boolean, isHovered: boolean,
63 * isFocused: boolean, isDisabled: (*|boolean), label: *}}
64 */
65 getInitialState: function() {
66 return {
67 //sizeOfButton: this.props.size || '', //There is no Medium value in CSS, default size is the absence of a value
68 className: this.props.className || 'rw-button-primary', //Default value is 'rw-button-primary' which is the primary one
69 label: this.props.label,
70 isActive: false,
71 isHovered: false,
72 isFocused: false,
73 isLoading: this.props.isLoading || false,
74 isDisabled: this.props.isDisabled || false
75 }
76 },
77
78
79 /**
80 * If any of the state variables have changed, the component should update.
81 * "nextProps" and "nextState" hold the state and property variables as they will be after the update.
82 * "this.props" and "this.state" hold the state and property variables as they were before the update.
83 * returns true if the state have changed. Otherwise returns false.
84 * @param nextProps
85 * @param nextState
86 * @returns {boolean}
87 */
88 shouldComponentUpdate: function(nextProps, nextState) {
89 var currentStateString = this.state.label + this.state.isDisabled + this.state.isActive + this.state.isFocused +
90 this.state.isHovered + this.props.isLoading;
91 var nextStateString = nextState.label + nextState.isDisabled + nextState.isActive + nextState.isFocused +
92 nextState.isHovered + nextProps.isLoading;
93
94 if (currentStateString == nextStateString) {
95 return false;
96 }
97 return true;
98 },
99
100
101 /**
102 * Returns a string reflecting the current state of the button.
103 * If the button state "isDisabled" is true, returns a string "disabled".
104 * Otherwise returns a string containing a word for each state that has been set to true.
105 * (ie "active focused" if the states active and focused are true, but hovered is false).
106 * @returns {string}
107 */
108 setButtonState: function() {
109 var ret = "";
110 if (this.state.isDisabled) {
111 return "disabled";
112 }
113 if (this.state.isActive) {
114 ret += "active ";
115 }
116 if (this.state.isHovered) {
117 ret += "hovered ";
118 }
119 if (this.state.isFocused) {
120 ret += "focused ";
121 }
122 return ret;
123 },
124
125
126
127 /**
128 * Track the width if set and write into markup using Style attribute
129 * Returns the minWidth and maxWidth prop in a string
130 * @returns {{}}
131 */
132 setButtonWidth:function(){

133 var width = {};


134
135 if (this.props.minWidth) {

136 width.minWidth = String(this.props.minWidth);

137 }

138 if (this.props.maxWidth) {

139 width.maxWidth = String(this.props.maxWidth);

140 }

141
142 return width;

143 },
144
145
146
147 /**
148 * Apply the size of the button to the icon directly
149 * Returns a string indicating the icon size.
150 * @returns {string}
151 */
152 /*
153 setIconSize:function(){
154
155 var iconClass = "rw-icon";
156
157 if(this.props.size){
158 iconClass += "-" + this.props.size;
159 }
160 return iconClass;
161 },
162 */
163
164
165
166 /**
167 * Builds the list of classes.
168 * Returns a string holding each class seperated by a space.
169 * @returns {string}
170 */
171 /*
172 setButtonClass:function() {
173 var buttonClass = "";
174 var buttonClassType = "rw-button-primary";
175 // If the size is declared, add it in
176 if (this.state.sizeOfButton) {
177 buttonClass += this.state.sizeOfButton;
178 }
179 //
180 if (typeof(this.props.className) != "undefined") {
181 this.props.className.push("rw-button-secondary");
182
183 // Run through the array and check all the values
184 for (var i = 0; i < this.props.className.length; i++) {
185
186 if (this.props.className[i].indexOf("secondary") > -1) {
187 buttonClassType = "rw-button-secondary"; // If the value of the array is equal to the string "secondary", add a predefined string
188 } else {
189 buttonClass += " " + this.props.className[i]; // Else just write the value of the array
190 }
191 }
192 }
193 buttonClass += " " + buttonClassType; //Add the button style type either primary or secondary
194 return buttonClass;
195 },
196 */
197
198 /**
199 * Builds an array of html elements for the icons and returns them.
200 * @returns {Array}
201 */
202 setIconElement: function() {
203 var button_icon = [];
204
205 if (typeof(this.props.icon) != "undefined") {
206 for (var i = 0; i < this.props.icon.length; i++) {
207 button_icon.push(React.createElement('svg', {
208 className: "rw-button__icon",
209 key: i,
210 dangerouslySetInnerHTML: {__html: '<use xlink:href="#' + this.props.icon[i] + '" />'} //Using a React method to drop in a hack since React does not support xlink:href yet
211 }));
212 }
213 }
214 return button_icon;
215 },
216
217 /**
218 * Renders the Button Component
219 * Returns a react component that constructs the html that houses the button component.
220 * @returns {*}
221 */
222 render: function() {
223 var button = null;
224 var button_style = this.setButtonWidth();
225 var button_state = this.setButtonState();
226 var button_class = this.state.className;
227 var button_icon = this.setIconElement();
228 var display = this.state.label;
229 if (this.props.isLoading) {
230 display = React.createElement(Loader, {show: true, size: '1rem', color: this.props.loadingColor});
231 }
232
233 button = React.createElement("button", {
234 className: button_class,
235 "data-state": button_state,
236 style: button_style,
237
238 // onClick: this.onClick,
239 onClick: this.props.onClick,
240 onMouseUp: this.onMouseUp,
241 onMouseDown: this.onMouseDown,
242 onMouseOver: this.onMouseOver,
243 onMouseEnter: this.onMouseEnter,
244 onMouseLeave: this.onMouseLeave,
245 onMouseOut: this.onMouseOut,
246 onTouchCancel: this.onTouchCancel,
247 onTouchEnd: this.onTouchEnd,
248 onTouchMove: this.onTouchMove,
249 onTouchStart: this.onTouchStart,
250 onKeyDown: this.onKeyDown,
251 onKeyPress: this.onKeyPress,
252 onKeyUp: this.onKeyUp,
253 onFocus: this.onFocus,
254 onBlur: this.onBlur
255 },
256 button_icon,
257 React.createElement("span", {className: "rw-button__label"}, display)
258 );
259 return button;
260 }
261 });