github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/server/camlistored/ui/nav_react.js (about)

     1  /*
     2  Copyright 2014 The Camlistore Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  goog.provide('cam.NavReact');
    18  goog.provide('cam.NavReact.Item');
    19  goog.provide('cam.NavReact.LinkItem');
    20  goog.provide('cam.NavReact.SearchItem');
    21  
    22  goog.require('goog.events.KeyCodes');
    23  
    24  goog.require('cam.object');
    25  goog.require('cam.reactUtil');
    26  goog.require('cam.style');
    27  
    28  cam.NavReact = React.createClass({
    29  	displayName: 'NavReact',
    30  
    31  	propTypes: {
    32  		onOpen: React.PropTypes.func.isRequired,
    33  		onClose: React.PropTypes.func.isRequired,
    34  		open: React.PropTypes.bool.isRequired,
    35  		timer: cam.reactUtil.quacksLike({setTimeout: React.PropTypes.func.isRequired, clearTimeout: React.PropTypes.func.isRequired,}).isRequired,
    36  	},
    37  
    38  	componentWillMount: function() {
    39  		this.expandTimer_ = 0;
    40  	},
    41  
    42  	render: function() {
    43  		return React.DOM.div({
    44  				className: React.addons.classSet({
    45  					'cam-nav': true,
    46  					'cam-nav-collapsed': !this.props.open,
    47  				}),
    48  				onMouseEnter: this.handleMouseEnter_,
    49  				onMouseLeave: this.handleMouseLeave_,
    50  				onKeyUp: this.handleKeyUp_,
    51  			},
    52  			React.DOM.img({className:'cam-nav-close', src:'close.svg', onClick: this.handleCloseClick_}),
    53  			this.props.children
    54  		);
    55  	},
    56  
    57  	open: function() {
    58  		this.clearExpandTimer_();
    59  		this.props.onOpen();
    60  	},
    61  
    62  	close: function() {
    63  		this.clearExpandTimer_();
    64  		this.props.onClose();
    65  	},
    66  
    67  	handleMouseEnter_: function(e) {
    68  		this.clearExpandTimer_();
    69  		this.expandTimer_ = this.props.timer.setTimeout(this.open, 250);
    70  	},
    71  
    72  	clearExpandTimer_: function() {
    73  		if (this.expandTimer_) {
    74  			this.props.timer.clearTimeout(this.expandTimer_);
    75  			this.expandTimer_ = 0;
    76  		}
    77  	},
    78  
    79  	handleMouseLeave_: this.clearExpandTimer_,
    80  
    81  	handleKeyUp_: function(e) {
    82  		if (e.keyCode == goog.events.KeyCodes.ESC) {
    83  			e.preventDefault();
    84  			this.close();
    85  		}
    86  	},
    87  
    88  	handleCloseClick_: function(e) {
    89  		e.stopPropagation();
    90  		this.close();
    91  	},
    92  });
    93  
    94  cam.NavReact.ItemBase = {
    95  	propTypes: {
    96  		iconSrc: React.PropTypes.string.isRequired,
    97  	},
    98  
    99  	getRootProps_: function(opt_extraClassName) {
   100  		var className = 'cam-nav-item';
   101  		if (opt_extraClassName) {
   102  			className += ' ' + opt_extraClassName;
   103  		}
   104  		return {
   105  			className: className,
   106  			style: {backgroundImage:cam.style.getURLValue(this.props.iconSrc)},
   107  		};
   108  	},
   109  };
   110  
   111  cam.NavReact.Item = React.createClass(cam.reactUtil.extend(cam.NavReact.ItemBase, {
   112  	propTypes: {
   113  		onClick: React.PropTypes.func,
   114  	},
   115  
   116  	render: function() {
   117  		return React.DOM.button(cam.object.extend(this.getRootProps_(), {
   118  				onClick: this.props.onClick
   119  			}), this.props.children);
   120  	},
   121  }));
   122  
   123  
   124  cam.NavReact.SearchItem = React.createClass(cam.reactUtil.extend(cam.NavReact.ItemBase, {
   125  	propTypes: {
   126  		value: React.PropTypes.string,
   127  		onSearch: React.PropTypes.func.isRequired,
   128  	},
   129  
   130  	getDefaultProps: function() {
   131  		return {
   132  			value: '',
   133  		}
   134  	},
   135  
   136  	render: function() {
   137  		if (!goog.isString(this.props.children)) {
   138  			throw new Error('Children of cam.NavReact.SearchItem must be a single string.');
   139  		}
   140  
   141  		return React.DOM.div(this.getRootProps_('cam-nav-searchitem'),
   142  			React.DOM.form({onClick:this.focus, onSubmit:this.handleSubmit_},
   143  				React.DOM.input({
   144  					ref:'input',
   145  					placeholder:this.props.children,
   146  					defaultValue: this.props.value,
   147  					onChange: this.handleChange_,
   148  					onMouseEnter: this.focus,
   149  				})
   150  			)
   151  		);
   152  	},
   153  
   154  	focus: function() {
   155  		this.getInputNode_().focus();
   156  	},
   157  
   158  	blur: function() {
   159  		this.getInputNode_().blur();
   160  	},
   161  
   162  	clear: function() {
   163  		this.getInputNode_().value = '';
   164  	},
   165  
   166  	handleSubmit_: function(e) {
   167  		this.props.onSearch(this.getInputNode_().value);
   168  		e.preventDefault();
   169  	},
   170  
   171  	getInputNode_: function() {
   172  		return this.refs.input.getDOMNode();
   173  	}
   174  }));
   175  
   176  
   177  cam.NavReact.LinkItem = React.createClass(cam.reactUtil.extend(cam.NavReact.ItemBase, {
   178  	propTypes: {
   179  		extraClassName: React.PropTypes.string,
   180  		href: React.PropTypes.string.isRequired,
   181  	},
   182  
   183  	getDefaultProps: function() {
   184  		return {
   185  			extraClassName: '',
   186  		};
   187  	},
   188  
   189  	render: function() {
   190  		var extraClassName = 'cam-nav-linkitem';
   191  		if (this.props.extraClassName != '') {
   192  			extraClassName += ' ' + this.props.extraClassName;
   193  		}
   194  		return React.DOM.a(
   195  			cam.object.extend(this.getRootProps_(extraClassName), {href:this.props.href}),
   196  			this.props.children
   197  		);
   198  	},
   199  }));