text: /**
   * The list view is a paginated table of all items in the list. It can show a
   * variety of information about the individual items in columns.
   */
  var audios = {};
  import _ from 'lodash';
  import React from 'react';
  // import { findDOMNode } from 'react-dom'; // TODO re-implement focus when ready
  import numeral from 'numeral';
  import {connect} from 'react-redux';
  
  import {
  	BlankState,
  	Center,
  	Container,
  	Glyph,
  	GlyphButton,
  	Pagination,
  	Spinner,
  } from '../../elemental';
  
  import ListFilters from './components/Filtering/ListFilters';
  import ListHeaderTitle from './components/ListHeaderTitle';
  import ListHeaderToolbar from './components/ListHeaderToolbar';
  import ListManagement from './components/ListManagement';
  
  import ConfirmationDialog from '../../shared/ConfirmationDialog';
  import CreateForm from '../../shared/CreateForm';
  import FlashMessages from '../../shared/FlashMessages';
  import ItemsTable from './components/ItemsTable/ItemsTable';
  import UpdateForm from './components/UpdateForm';
  import {plural as pluralize} from '../../../utils/string';
  import {listsByPath} from '../../../utils/lists';
  import {checkForQueryChange} from '../../../utils/queryParams';
  
  import {
  	deleteItems,
  	setActiveSearch,
  	setActiveSort,
  	setCurrentPage,
  	selectList,
  	clearCachedQuery,
  } from './actions';
  
  import {
  	deleteItem,
  } from '../Item/actions';
  
  const ESC_KEY_CODE = 27;
  
  const ListView = React.createClass({
  	contextTypes: {
  		router: React.PropTypes.object.isRequired,
  	},
  	getInitialState() {
  		return {
  			confirmationDialog: {
  				isOpen: false,
  			},
  			checkedItems: {},
  			constrainTableWidth: true,
  			manageMode: false,
  			showCreateForm: false,
  			showUpdateForm: false,
  		};
  	},
  	componentWillMount() {
  		// When we directly navigate to a list without coming from another client
  		// side routed page before, we need to initialize the list and parse
  		// possibly specified query parameters
  
  		this.props.dispatch(selectList(this.props.params.listId));
  
  		const isNoCreate = this.props.lists.data[this.props.params.listId].nocreate;
  		const shouldOpenCreate = this.props.location.search === '?create';
  
  
  		this.setState({
  			showCreateForm: (shouldOpenCreate && !isNoCreate) || Keystone.createFormErrors,
  		});
  
  		const _self = this;
  
  		window.socket.on('list/insert', function (item) {
  			if (_self.props.currentList.id == item.list_id) {
  				_self.props.currentList.items.results.unshift(item);
  				_self.props.currentList.items.count++;
  				item['focus_inserted'] = true;
  				if (typeof item.play !== "undefined") {
  					const sound = new Audio();
  					sound.src = item.play;
  					sound.addEventListener('load', function () {
  						sound.play();
  					});
  				}
  				_self.setState({
  					currentList: _self.props.currentList,
  				});
  			}
  		});
  
  		window.socket.on('list/update', function (item) {
  			if (_self.props.currentList.id == item.list_id) {
  				item['focus_updated'] = true;
  				const item_index = _.findIndex(_self.props.currentList.items.results, {'id': item.id});
  				_self.props.currentList.items.results[item_index] = item;
  
  				if (typeof item.play !== "undefined") {
  					const sound = new Audio();
  					sound.src = item.play;
  					sound.addEventListener('load', function () {
  						sound.play();
  					});
  				}
  
  				_self.setState({
  					currentList: _self.props.currentList,
  				});
  			}
  		});
  
  		this.toggleTableWidth();
  
  	},
  	componentWillReceiveProps(nextProps) {
  		// We've opened a new list from the client side routing, so initialize
  		// again with the new list id
  		const isReady = this.props.lists.ready && nextProps.lists.ready;
  		if (isReady && checkForQueryChange(nextProps, this.props)) {
  			this.props.dispatch(selectList(nextProps.params.listId));
  		}
  	},
  	componentWillUnmount() {
  		this.props.dispatch(clearCachedQuery());
  	},
  
  	// ==============================
  	// HEADER
  	// ==============================
  	// Called when a new item is created
  	onCreate(item) {
  		// Hide the create form
  		this.toggleCreateModal(false);
  		// Redirect to newly created item path
  		const list = this.props.currentList;
  		this.context.router.push(`${Keystone.adminPath}/${list.path}/${item.id}`);
  	},
  	createAutocreate() {
  		const list = this.props.currentList;
  		list.createItem(null, (err, data) => {
  			if (err) {
  				// TODO Proper error handling
  				alert('Something went wrong, please try again!');
  				console.log(err);
  			} else {
  				this.context.router.push(`${Keystone.adminPath}/${list.path}/${data.id}`);
  			}
  		});
  	},
  	updateSearch(e) {
  		this.props.dispatch(setActiveSearch(e.target.value));
  	},
  	handleSearchClear() {
  		this.props.dispatch(setActiveSearch(''));
  
  		// TODO re-implement focus when ready
  		// findDOMNode(this.refs.listSearchInput).focus();
  	},
  	handleSearchKey(e) {
  		// clear on esc
  		if (e.which === ESC_KEY_CODE) {
  			this.handleSearchClear();
  		}
  	},
  	handlePageSelect(i) {
  		// If the current page index is the same as the index we are intending to pass to redux, bail out.
  		if (i === this.props.lists.page.index) return;
  		return this.props.dispatch(setCurrentPage(i));
  	},
  	toggleManageMode(filter = !this.state.manageMode) {
  		this.setState({
  			manageMode: filter,
  			checkedItems: {},
  		});
  	},
  	toggleUpdateModal(filter = !this.state.showUpdateForm) {
  		this.setState({
  			showUpdateForm: filter,
  		});
  	},
  	massUpdate() {
  		// TODO: Implement update multi-item
  		console.log('Update ALL the things!');
  	},
  	massDelete() {
  		const {checkedItems} = this.state;
  		const list = this.props.currentList;
  		const itemCount = pluralize(checkedItems, ('* ' + list.singular.toLowerCase()), ('* ' + list.plural.toLowerCase()));
  		const itemIds = Object.keys(checkedItems);
  
  		this.setState({
  			confirmationDialog: {
  				isOpen: true,
  				label: 'Delete',
  				body: (
  					<div>
  						Are you sure you want to delete {itemCount}?
  						<br/>
  						<br/>
  						This cannot be undone.
  					</div>
  				),
  				onConfirmation: () => {
  					this.props.dispatch(deleteItems(itemIds));
  					this.toggleManageMode();
  					this.removeConfirmationDialog();
  				},
  			},
  		});
  	},
  	handleManagementSelect(selection) {
  		if (selection === 'all') this.checkAllItems();
  		if (selection === 'none') this.uncheckAllTableItems();
  		if (selection === 'visible') this.checkAllTableItems();
  		return false;
  	},
  	renderConfirmationDialog() {
  		const props = this.state.confirmationDialog;
  		return (
  			<ConfirmationDialog
  				confirmationLabel={props.label}
  				isOpen={props.isOpen}
  				onCancel={this.removeConfirmationDialog}
  				onConfirmation={props.onConfirmation}
  			>
  				{props.body}
  			</ConfirmationDialog>
  		);
  	},
  	renderManagement() {
  		const {checkedItems, manageMode, selectAllItemsLoading} = this.state;
  		const {currentList} = this.props;
  
  		return (
  			<ListManagement
  				checkedItemCount={Object.keys(checkedItems).length}
  				handleDelete={this.massDelete}
  				handleSelect={this.handleManagementSelect}
  				handleToggle={() => this.toggleManageMode(!manageMode)}
  				isOpen={manageMode}
  				itemCount={this.props.items.count}
  				itemsPerPage={this.props.lists.page.size}
  				nodelete={currentList.nodelete}
  				rowColors={currentList.rowColors}
  				noedit={currentList.noedit}
  				rules={currentList.rules}
  				selectAllItemsLoading={selectAllItemsLoading}
  			/>
  		);
  	},
  	renderPagination() {
  		const items = this.props.items;
  		if (this.state.manageMode || !items.count) return;
  
  		const list = this.props.currentList;
  		const currentPage = this.props.lists.page.index;
  		const pageSize = this.props.lists.page.size;
  
  		return (
  			<Pagination
  				currentPage={currentPage}
  				onPageSelect={this.handlePageSelect}
  				pageSize={pageSize}
  				plural={list.plural}
  				singular={list.singular}
  				style={{marginBottom: 0}}
  				total={items.count}
  				limit={10}
  			/>
  		);
  	},
  	renderHeader() {
  		const items = this.props.items;
  		const {autocreate, nocreate, plural, singular} = this.props.currentList;
  
  		return (
  			<Container style={{paddingTop: '2em'}}>
  				<ListHeaderTitle
  					activeSort={this.props.active.sort}
  					availableColumns={this.props.currentList.columns}
  					handleSortSelect={this.handleSortSelect}
  					title={`
  						${numeral(items.count).format()}
  						${pluralize(items.count, ' ' + singular, ' ' + plural)}
  					`}
  				/>
  				<ListHeaderToolbar
  					// common
  					dispatch={this.props.dispatch}
  					list={listsByPath[this.props.params.listId]}
  
  					// expand
  					expandIsActive={!this.state.constrainTableWidth}
  					expandOnClick={this.toggleTableWidth}
  
  					// create
  					createIsAvailable={!nocreate}
  					createListName={singular}
  					createOnClick={autocreate
  						? this.createAutocreate
  						: this.openCreateModal}
  
  					// search
  					searchHandleChange={this.updateSearch}
  					searchHandleClear={this.handleSearchClear}
  					searchHandleKeyup={this.handleSearchKey}
  					searchValue={this.props.active.search}
  
  					// filters
  					filtersActive={this.props.active.filters}
  					filtersAvailable={this.props.currentList.columns.filter((col) => (
  						col.field && col.field.hasFilterMethod) || col.type === 'heading'
  					)}
  
  					// columns
  					columnsActive={this.props.active.columns}
  					columnsAvailable={this.props.currentList.columns}
  				/>
  				<ListFilters
  					dispatch={this.props.dispatch}
  					filters={this.props.active.filters}
  				/>
  			</Container>
  		);
  	},
  
  	// ==============================
  	// TABLE
  	// ==============================
  
  	checkTableItem(item, e) {
  		e.preventDefault();
  		const newCheckedItems = {...this.state.checkedItems};
  		const itemId = item.id;
  		if (this.state.checkedItems[itemId]) {
  			delete newCheckedItems[itemId];
  		} else {
  			newCheckedItems[itemId] = true;
  		}
  		this.setState({
  			checkedItems: newCheckedItems,
  		});
  	},
  	checkAllTableItems() {
  		const checkedItems = {};
  		this.props.items.results.forEach(item => {
  			checkedItems[item.id] = true;
  		});
  		this.setState({
  			checkedItems: checkedItems,
  		});
  	},
  	checkAllItems() {
  		const checkedItems = {...this.state.checkedItems};
  		// Just in case this API call takes a long time, we'll update the select all button with
  		// a spinner.
  		this.setState({selectAllItemsLoading: true});
  		var self = this;
  		this.props.currentList.loadItems({expandRelationshipFilters: false, filters: {}}, function (err, data) {
  			data.results.forEach(item => {
  				checkedItems[item.id] = true;
  			});
  			self.setState({
  				checkedItems: checkedItems,
  				selectAllItemsLoading: false,
  			});
  		});
  	},
  	uncheckAllTableItems() {
  		this.setState({
  			checkedItems: {},
  		});
  	},
  	deleteTableItem(item, e) {
  		if (e.altKey) {
  			this.props.dispatch(deleteItem(item.id));
  			return;
  		}
  
  		e.preventDefault();
  
  		this.setState({
  			confirmationDialog: {
  				isOpen: true,
  				label: 'Delete',
  				body: (
  					<div>
  						Are you sure you want to delete <strong>{item.name}</strong>?
  						<br/>
  						<br/>
  						This cannot be undone.
  					</div>
  				),
  				onConfirmation: () => {
  					this.props.dispatch(deleteItem(item.id));
  					this.removeConfirmationDialog();
  				},
  			},
  		});
  	},
  	removeConfirmationDialog() {
  		this.setState({
  			confirmationDialog: {
  				isOpen: false,
  			},
  		});
  	},
  	toggleTableWidth() {
  		this.setState({
  			constrainTableWidth: !this.state.constrainTableWidth,
  		});
  	},
  
  	// ==============================
  	// COMMON
  	// ==============================
  
  	handleSortSelect(path, inverted) {
  		if (inverted) path = '-' + path;
  		this.props.dispatch(setActiveSort(path));
  	},
  	toggleCreateModal(visible) {
  		this.setState({
  			showCreateForm: visible,
  		});
  	},
  	openCreateModal() {
  		this.toggleCreateModal(true);
  	},
  	closeCreateModal() {
  		this.toggleCreateModal(false);
  	},
  	showBlankState() {
  		return !this.props.loading
  			&& !this.props.items.results.length
  			&& !this.props.active.search
  			&& !this.props.active.filters.length;
  	},
  	renderBlankState() {
  		const {currentList} = this.props;
  
  		if (!this.showBlankState()) return null;
  
  		// create and nav directly to the item view, or open the create modal
  		const onClick = currentList.autocreate
  			? this.createAutocreate
  			: this.openCreateModal;
  
  		// display the button if create allowed
  		const button = !currentList.nocreate ? (
  			<GlyphButton color="success" glyph="plus" position="left" onClick={onClick}
  									 data-e2e-list-create-button="no-results">
  				Create {currentList.singular}
  			</GlyphButton>
  		) : null;
  
  		return (
  			<Container>
  				{(this.props.error) ? (
  					<FlashMessages
  						messages={{
  							error: [{
  								title: "There is a problem with the network, we're trying to reconnect...",
  							}]
  						}}
  					/>
  				) : null}
  				<BlankState heading={`No ${this.props.currentList.plural.toLowerCase()} found...`} style={{marginTop: 40}}>
  					{button}
  				</BlankState>
  			</Container>
  		);
  	},
  	renderActiveState() {
  		if (this.showBlankState()) return null;
  
  		const containerStyle = {
  			transition: 'max-width 160ms ease-out',
  			msTransition: 'max-width 160ms ease-out',
  			MozTransition: 'max-width 160ms ease-out',
  			WebkitTransition: 'max-width 160ms ease-out',
  		};
  		if (!this.state.constrainTableWidth) {
  			containerStyle.maxWidth = '100%';
  		}
  		return (
  			<div>
  				{this.renderHeader()}
  				<Container>
  					<div style={{height: 35, marginBottom: '1em', marginTop: '1em'}}>
  						{this.renderManagement()}
  						{this.renderPagination()}
  						<span style={{clear: 'both', display: 'table'}}/>
  					</div>
  				</Container>
  				<Container style={containerStyle}>
  					{(this.props.error) ? (
  						<FlashMessages
  							messages={{
  								error: [{
  									title: "There is a problem with the network, we're trying to reconnect..",
  								}]
  							}}
  						/>
  					) : null}
  					{(this.props.loading) ? (
  						<Center height="50vh">
  							<Spinner/>
  						</Center>
  					) : (
  						<div>
  							<ItemsTable
  								activeSort={this.props.active.sort}
  								checkedItems={this.state.checkedItems}
  								checkTableItem={this.checkTableItem}
  								columns={this.props.active.columns}
  								deleteTableItem={this.deleteTableItem}
  								handleSortSelect={this.handleSortSelect}
  								items={this.props.items}
  								list={this.props.currentList}
  								manageMode={this.state.manageMode}
  								rowAlert={this.props.rowAlert}
  								currentPage={this.props.lists.page.index}
  								pageSize={this.props.lists.page.size}
  								drag={this.props.lists.drag}
  								dispatch={this.props.dispatch}
  							/>
  							{this.renderNoSearchResults()}
  						</div>
  					)}
  				</Container>
  			</div>
  		);
  	},
  	renderNoSearchResults() {
  		if (this.props.items.results.length) return null;
  		let matching = this.props.active.search;
  		if (this.props.active.filters.length) {
  			matching += (matching ? ' and ' : '') + pluralize(this.props.active.filters.length, '* filter', '* filters');
  		}
  		matching = matching ? ' found matching ' + matching : '.';
  		return (
  			<BlankState style={{marginTop: 20, marginBottom: 20}}>
  				<Glyph
  					name="search"
  					size="medium"
  					style={{marginBottom: 20}}
  				/>
  				<h2 style={{color: 'inherit'}}>
  					No {this.props.currentList.plural.toLowerCase()}{matching}
  				</h2>
  			</BlankState>
  		);
  	},
  	render() {
  		if (!this.props.ready) {
  			return (
  				<Center height="50vh" data-screen-id="list">
  					<Spinner/>
  				</Center>
  			);
  		}
  		return (
  			<div data-screen-id="list">
  				{this.renderBlankState()}
  				{this.renderActiveState()}
  				<CreateForm
  					err={Keystone.createFormErrors}
  					isOpen={this.state.showCreateForm}
  					list={this.props.currentList}
  					onCancel={this.closeCreateModal}
  					onCreate={this.onCreate}
  				/>
  				<UpdateForm
  					isOpen={this.state.showUpdateForm}
  					itemIds={Object.keys(this.state.checkedItems)}
  					list={this.props.currentList}
  					onCancel={() => this.toggleUpdateModal(false)}
  				/>
  				{this.renderConfirmationDialog()}
  			</div>
  		);
  	},
  });
  
  module.exports = connect((state) => {
  	return {
  		lists: state.lists,
  		loading: state.lists.loading,
  		error: state.lists.error,
  		currentList: state.lists.currentList,
  		items: state.lists.items,
  		page: state.lists.page,
  		ready: state.lists.ready,
  		rowAlert: state.lists.rowAlert,
  		active: state.active,
  	};
  })(ListView);
  