<commit_before>/**
 * Interface for evaluating revisions
 *
 * @author: Helder (https://github.com/he7d3r)
 * @license: CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0/>
 * Based on mockups by Aaron Halfaker
 * https://meta.wikimedia.org/wiki/Research_talk:Revision_scoring_as_a_service?oldid=10266386#Revision_handcoding_.28mockups.29
 */
( function ( mw, $ ) {
	'use strict';
	var i18n, config, fields, workSet, curIdx;

	function toggleSelection( e ) {
		var $target = $( e.target ),
			wasSelected = $target.hasClass( 'rvc-selected' );
		$target
			.parent()
				.find( '.rvc-selected' )
					.removeClass( 'rvc-selected' )
					.end()
				.end();
		if ( !wasSelected ) {
			$target.addClass( 'rvc-selected' );
		}
		// The user must select one value for each field
		$( '#rvc-submit' ).prop(
			'disabled',
			 $( '.mw-ui-button.rvc-selected' ).length !== fields.length ||
			 curIdx >= workSet.length
		);
	}
/*
	function getRandomSet( size, done ) {
		var i, j, rev,
			apiDeferred = $.Deferred(),
			list = [];
		size = size || 100;
		done = done || 70;
		curIdx = done + 1;
		for ( i = 0; i < size; i++ ) {
			rev = {
				revid: Math.floor( Math.random() * 1000000 ),
				pageid: Math.floor( Math.random() * 1000000 ),
				// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
				fields: {}
			};
			if ( i <= done ) {
				// TODO:
				// * Should an 'undefined' value mean 'unknown'?
				//   In that case, this could be a boolean
				// * Or one should explicitly set a value (e.g. 0) to mean 'unknown'?
				//   In case there are just three possibilities, we could use -1, 0 and 1 instead of 0, 1 and 2?
				// FIXME: these names should not be hardcoded
				// TODO: Should we hardcode common sense such as "not damaging implies good faith"?
				for ( j = 0; j < fields.length; j++ ) {
					// Classes from 0 to (N-1), where N is the number of options for this field
					rev.fields[ fields[j].id ] = Math.floor( Math.random() * fields[j].options.length );
				}
			}
			list.push( rev );
		}
		apiDeferred.resolve( list );
		return apiDeferred.promise();
	}
*/
	function getRecentChanges( options ) {
		var apiDeferred = $.Deferred(),
			defaultOptions = {
				action: 'query',
				list: 'recentchanges',
				rctype: 'edit|new',
				rclimit: 50
			},
			params = $.extend( {}, defaultOptions, options );
		new mw.Api().get( params ).done( function( data ){
			var i,
				list = [],
				changes = data.query.recentchanges;
			for( i = 0; i < changes.length; i++ ){
				list.push( {
					revid: changes[i].revid,
					pageid: changes[i].pageid,
					// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
					fields: {}
				} );
			}
			apiDeferred.resolve( list );
		} )
		.fail( function(){
			// TODO: Reject and pass some error info?
			apiDeferred.resolve( [] );
		} );
		return apiDeferred.promise();
	}

	function showWorkSet( ws ){
		var i, j, field, idx, $icon, className, tooltip, value,
			$bar = $( '.rvc-progress' ).empty();
		workSet = ws || workSet;
		for ( i = 0; i < workSet.length; i++ ) {
			$icon = $( '
' );
			tooltip = mw.msg( 'rvc-revision-title', workSet[i].revid );
			for ( j = 0; j < fields.length; j++ ) {
				field = fields[j].id;
				idx = workSet[i].fields[ field ];
				value = fields[j].options[ idx ] && fields[j].options[ idx ].value;
				tooltip += '\n' + fields[j].label + ' ' + value;
				className = 'rvc-' + field + '-' + value;
				$icon.append( $( '
' ).addClass( className ) );
			}
			$icon.attr(
				'title',
				tooltip
			);
			$bar.append( $icon );
		}
		$( '.rvc-progress > div' ).css( 'width', ( 100 / workSet.length ) + '%' );
		$( '.mw-ui-button.rvc-selected' ).removeClass( 'rvc-selected' );
		$( '#rvc-submit' ).prop( 'disabled', true );
		if( curIdx < workSet.length ){
			$bar.find( '> div' ).eq( curIdx ).addClass( 'rvc-selected' );
			showDiff( workSet[ curIdx ].revid );
		}
	}

	function showDiff( revid ){
		new mw.Api().get( {
			action: 'query',
			prop: 'revisions',
			rvdiffto: 'prev',
			revids: revid,
			indexpageids: true
		} ).done( function( data ){
			var page = data.query.pages[ data.query.pageids[0] ];
			// $( '#firstHeading' ).text( page.title );
			$( '#rvc-diff' ).empty().append(
				page.revisions[0].diff['*']
			);
		} );
	}

	function submit(){
		var revData;
		$( '.mw-ui-button.rvc-selected' ).each( function(){
			var $this = $( this ),
				idxValue = $this.data( 'rvc-value' ),
				field = $this.parent().data( 'rvc-field' );
			if( field !== undefined && idxValue !== undefined ){
				workSet[ curIdx ].fields[ field ] = idxValue;
			}
		} );
		// FIXME: Generalize the API provided by the tool on Labs,
		// to deal with arbitrary number of fields (columns?)
		revData = {
			action: 'save',
			rev: workSet[ curIdx ].revid,
			page: workSet[ curIdx ].pageid,
			// FIXME: This number changes between wikis
			// FIXME: Authenticate using OAuth
			user: mw.config.get( 'wgUserId' ),
			// FIXME: This is just a hack to map our values to
			// the ones currently accepted by the tool
			score: {
					0: 'no',
					1: 'yes'
				}[ workSet[ curIdx ].fields.damaging ],
			gfaith: {
					0: 'no',
					1: 'yes'
				}[ workSet[ curIdx ].fields['good-faith'] ],
			wiki: mw.config.get( 'wgDBname' ),
			comment: location.origin +
				mw.util.getUrl( 'User:' + mw.config.get( 'wgUserName' ) )
		};
		$( '#rvc-submit' ).injectSpinner( 'rvc-submit-spinner' );
		$.ajax( {
			// See the saved data on http://ores-test.wmflabs.org/table
			url: '//ores-test.wmflabs.org/save',
			data: revData,
			dataType: 'jsonp'
		} ).always( function(){
			$.removeSpinner( 'rvc-submit-spinner' );
		} ).fail( function(){
			console.log( arguments );
			alert( 'An errror occurred! Check the console...' );
		} );
		curIdx++;
		showWorkSet();
		if( curIdx >= workSet.length ){
			alert( mw.msg( 'rvc-dataset-completed' ) );
			$( '#rvc-submit' ).prop( 'disabled', true );
		}
	}

	function load( data ) {
		var $ui = $( '#rvc-ui' ).empty(),
			$submit = $( '<input id="rvc-submit" class="mw-ui-button mw-ui-constructive" type="submit">' )
				.prop( 'disabled', true )
				.click( submit ),
			field, i, j, id, val, $feature, $group;
		config = $.parseJSON( data.query.pages[data.query.pageids[0]].revisions[0]['*'] )
		fields = config.fields;
		i18n = config.i18n;
		mw.messages.set( i18n[ mw.config.get( 'wgUserLanguage' ) ] || i18n.en );

		$submit.val( mw.msg( 'rvc-submit' ) );
		$ui.append(
			$( '
' )
				.text( mw.msg( 'rvc-work-set' ) ),
			$( '
' )
				.addClass( 'rvc-progress' )
		);
		for ( i = 0; i < fields.length; i++ ) {
			field = fields[i];
			id = field.id;
			$group = $( '
' )
				.data( 'rvc-field', id )
				// .addClass( 'mw-ui-radio');
				.addClass( 'mw-ui-button-group');
			for ( j = 0; j < field.options.length; j++ ) {
				val = field.options[j].value;
				$group.append(
					$( '
' )
						.addClass( 'mw-ui-button')
						.attr( 'id', 'rvc-' + field.id + '-' + val )
						.attr( 'title', mw.msg( field.options[j].tooltip ) )
						.text( mw.msg( field.options[j].label ) )
						.data( 'rvc-value', j )
						.click( toggleSelection )
// 					$( '<input type="radio">' )
// 						.attr( 'name', 'rvc-' + field.id )
// 						.attr( 'id', 'rvc-' + field.id + '-' + val )
// 						.attr( 'title', mw.msg( field.options[j].tooltip ) ),
// 					$( '' )
// 						.text( mw.msg( field.options[j].label ) )
// 						.attr( 'for', 'rvc-' + field.id + '-' + val )
// 						.data( 'rvc-value', j )
// 						.click( toggleSelection )
				);
			}
			$feature = $( '
' )
				.attr( 'title', mw.msg( field.help ) )
				.append(
					$( '
' )
						.text( mw.msg( field.label ) ),
					$group
				);
			$ui.append( $feature, '

' );
		}
		$ui.append( $submit )
			.append(
				'
' +
				'<colgroup><col class="diff-marker">' +
				'<col class="diff-content">' +
				'<col class="diff-marker">' +
				'<col class="diff-content">' +
				'</colgroup>

'
			);
		curIdx = 0;
		// getRandomSet()
		getRecentChanges()
			.done( showWorkSet );
	}

	if ( $.inArray( mw.config.get( 'wgAction' ), [ 'view', 'purge' ] ) !== -1 ) {
		$( function () {
			if ( $( '#rvc-ui' ).length !== 0 ) {
				mw.loader.using( [
					'mediawiki.api',
					'jquery.spinner',
					// TODO: Load this only when necessary
					// (e.g. if the user will be required to click on some button before the first diff appears)
					'mediawiki.action.history.diff'
				] ).done( function () {
					$.ajax(
					{
						// TODO: Move this to Labs (and use CORS if needed)
						'url': 'https://meta.wikimedia.org/w/api.php',
						'data': {
							action: 'query',
							format: 'json',
							prop: 'revisions',
							rvprop: 'content',
							titles: 'User:He7d3r/Tools/RevisionCodingConfig.js',
							indexpageids: ''
						},
						'dataType': 'jsonp'
					} )
					.done( load );
				} );
			}
		} );
	}

}( mediaWiki, jQuery ) );
<commit_msg>Load JSON for form configuration from Wikimedia Labs<commit_after>/**
 * Interface for evaluating revisions
 *
 * @author: Helder (https://github.com/he7d3r)
 * @license: CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0/>
 * Based on mockups by Aaron Halfaker
 * https://meta.wikimedia.org/wiki/Research_talk:Revision_scoring_as_a_service?oldid=10266386#Revision_handcoding_.28mockups.29
 */
( function ( mw, $ ) {
	'use strict';
	var i18n, config, fields, workSet, curIdx;

	function toggleSelection( e ) {
		var $target = $( e.target ),
			wasSelected = $target.hasClass( 'rvc-selected' );
		$target
			.parent()
				.find( '.rvc-selected' )
					.removeClass( 'rvc-selected' )
					.end()
				.end();
		if ( !wasSelected ) {
			$target.addClass( 'rvc-selected' );
		}
		// The user must select one value for each field
		$( '#rvc-submit' ).prop(
			'disabled',
			 $( '.mw-ui-button.rvc-selected' ).length !== fields.length ||
			 curIdx >= workSet.length
		);
	}
/*
	function getRandomSet( size, done ) {
		var i, j, rev,
			apiDeferred = $.Deferred(),
			list = [];
		size = size || 100;
		done = done || 70;
		curIdx = done + 1;
		for ( i = 0; i < size; i++ ) {
			rev = {
				revid: Math.floor( Math.random() * 1000000 ),
				pageid: Math.floor( Math.random() * 1000000 ),
				// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
				fields: {}
			};
			if ( i <= done ) {
				// TODO:
				// * Should an 'undefined' value mean 'unknown'?
				//   In that case, this could be a boolean
				// * Or one should explicitly set a value (e.g. 0) to mean 'unknown'?
				//   In case there are just three possibilities, we could use -1, 0 and 1 instead of 0, 1 and 2?
				// FIXME: these names should not be hardcoded
				// TODO: Should we hardcode common sense such as "not damaging implies good faith"?
				for ( j = 0; j < fields.length; j++ ) {
					// Classes from 0 to (N-1), where N is the number of options for this field
					rev.fields[ fields[j].id ] = Math.floor( Math.random() * fields[j].options.length );
				}
			}
			list.push( rev );
		}
		apiDeferred.resolve( list );
		return apiDeferred.promise();
	}
*/
	function getRecentChanges( options ) {
		var apiDeferred = $.Deferred(),
			defaultOptions = {
				action: 'query',
				list: 'recentchanges',
				rctype: 'edit|new',
				rclimit: 50
			},
			params = $.extend( {}, defaultOptions, options );
		new mw.Api().get( params ).done( function( data ){
			var i,
				list = [],
				changes = data.query.recentchanges;
			for( i = 0; i < changes.length; i++ ){
				list.push( {
					revid: changes[i].revid,
					pageid: changes[i].pageid,
					// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
					fields: {}
				} );
			}
			apiDeferred.resolve( list );
		} )
		.fail( function(){
			// TODO: Reject and pass some error info?
			apiDeferred.resolve( [] );
		} );
		return apiDeferred.promise();
	}

	function showWorkSet( ws ){
		var i, j, field, idx, $icon, className, tooltip, value,
			$bar = $( '.rvc-progress' ).empty();
		workSet = ws || workSet;
		for ( i = 0; i < workSet.length; i++ ) {
			$icon = $( '
' );
			tooltip = mw.msg( 'rvc-revision-title', workSet[i].revid );
			for ( j = 0; j < fields.length; j++ ) {
				field = fields[j].id;
				idx = workSet[i].fields[ field ];
				value = fields[j].options[ idx ] && fields[j].options[ idx ].value;
				tooltip += '\n' + fields[j].label + ' ' + value;
				className = 'rvc-' + field + '-' + value;
				$icon.append( $( '
' ).addClass( className ) );
			}
			$icon.attr(
				'title',
				tooltip
			);
			$bar.append( $icon );
		}
		$( '.rvc-progress > div' ).css( 'width', ( 100 / workSet.length ) + '%' );
		$( '.mw-ui-button.rvc-selected' ).removeClass( 'rvc-selected' );
		$( '#rvc-submit' ).prop( 'disabled', true );
		if( curIdx < workSet.length ){
			$bar.find( '> div' ).eq( curIdx ).addClass( 'rvc-selected' );
			showDiff( workSet[ curIdx ].revid );
		}
	}

	function showDiff( revid ){
		new mw.Api().get( {
			action: 'query',
			prop: 'revisions',
			rvdiffto: 'prev',
			revids: revid,
			indexpageids: true
		} ).done( function( data ){
			var page = data.query.pages[ data.query.pageids[0] ];
			// $( '#firstHeading' ).text( page.title );
			$( '#rvc-diff' ).empty().append(
				page.revisions[0].diff['*']
			);
		} );
	}

	function submit(){
		var revData;
		$( '.mw-ui-button.rvc-selected' ).each( function(){
			var $this = $( this ),
				idxValue = $this.data( 'rvc-value' ),
				field = $this.parent().data( 'rvc-field' );
			if( field !== undefined && idxValue !== undefined ){
				workSet[ curIdx ].fields[ field ] = idxValue;
			}
		} );
		// FIXME: Generalize the API provided by the tool on Labs,
		// to deal with arbitrary number of fields (columns?)
		revData = {
			action: 'save',
			rev: workSet[ curIdx ].revid,
			page: workSet[ curIdx ].pageid,
			// FIXME: This number changes between wikis
			// FIXME: Authenticate using OAuth
			user: mw.config.get( 'wgUserId' ),
			// FIXME: This is just a hack to map our values to
			// the ones currently accepted by the tool
			score: {
					0: 'no',
					1: 'yes'
				}[ workSet[ curIdx ].fields.damaging ],
			gfaith: {
					0: 'no',
					1: 'yes'
				}[ workSet[ curIdx ].fields['good-faith'] ],
			wiki: mw.config.get( 'wgDBname' ),
			comment: location.origin +
				mw.util.getUrl( 'User:' + mw.config.get( 'wgUserName' ) )
		};
		$( '#rvc-submit' ).injectSpinner( 'rvc-submit-spinner' );
		$.ajax( {
			// See the saved data on http://ores-test.wmflabs.org/table
			url: '//ores-test.wmflabs.org/save',
			data: revData,
			dataType: 'jsonp'
		} ).always( function(){
			$.removeSpinner( 'rvc-submit-spinner' );
		} ).fail( function(){
			console.log( arguments );
			alert( 'An errror occurred! Check the console...' );
		} );
		curIdx++;
		showWorkSet();
		if( curIdx >= workSet.length ){
			alert( mw.msg( 'rvc-dataset-completed' ) );
			$( '#rvc-submit' ).prop( 'disabled', true );
		}
	}

	function load( data ) {
		var $ui = $( '#rvc-ui' ).empty(),
			// FIXME: Migrate to OOjs UI (http://livingstyleguide.wmflabs.org/wiki/OOjs_UI)
			$submit = $( '<input id="rvc-submit" class="mw-ui-button mw-ui-constructive" type="submit">' )
				.prop( 'disabled', true )
				.click( submit ),
			field, i, j, id, val, $feature, $group;
		fields = data.form.fields;
		i18n = data.form.i18n;
		mw.messages.set( i18n[ mw.config.get( 'wgUserLanguage' ) ] || i18n.en );

		$submit.val( mw.msg( 'rvc-submit' ) );
		$ui.append(
			$( '
' )
				.text( mw.msg( 'rvc-work-set' ) ),
			$( '
' )
				.addClass( 'rvc-progress' )
		);
		for ( i = 0; i < fields.length; i++ ) {
			field = fields[i];
			id = field.id;
			$group = $( '
' )
				.data( 'rvc-field', id )
				// .addClass( 'mw-ui-radio');
				.addClass( 'mw-ui-button-group');
			for ( j = 0; j < field.options.length; j++ ) {
				val = field.options[j].value;
				$group.append(
					$( '
' )
						.addClass( 'mw-ui-button')
						.attr( 'id', 'rvc-' + field.id + '-' + val )
						.attr( 'title', mw.msg( field.options[j].tooltip ) )
						.text( mw.msg( field.options[j].label ) )
						.data( 'rvc-value', j )
						.click( toggleSelection )
// 					$( '<input type="radio">' )
// 						.attr( 'name', 'rvc-' + field.id )
// 						.attr( 'id', 'rvc-' + field.id + '-' + val )
// 						.attr( 'title', mw.msg( field.options[j].tooltip ) ),
// 					$( '' )
// 						.text( mw.msg( field.options[j].label ) )
// 						.attr( 'for', 'rvc-' + field.id + '-' + val )
// 						.data( 'rvc-value', j )
// 						.click( toggleSelection )
				);
			}
			$feature = $( '
' )
				.attr( 'title', mw.msg( field.help ) )
				.append(
					$( '
' )
						.text( mw.msg( field.label ) ),
					$group
				);
			$ui.append( $feature, '

' );
		}
		$ui.append( $submit )
			.append(
				'
' +
				'<colgroup><col class="diff-marker">' +
				'<col class="diff-content">' +
				'<col class="diff-marker">' +
				'<col class="diff-content">' +
				'</colgroup>

'
			);
		curIdx = 0;
		// getRandomSet()
		getRecentChanges()
			.done( showWorkSet );
	}

	if ( $.inArray( mw.config.get( 'wgAction' ), [ 'view', 'purge' ] ) !== -1 ) {
		$( function () {
			if ( $( '#rvc-ui' ).length !== 0 ) {
				mw.loader.using( [
					'mediawiki.api',
					'jquery.spinner',
					// TODO: Load this only when necessary
					// (e.g. if the user will be required to click on some button before the first diff appears)
					'mediawiki.action.history.diff'
				] ).done( function () {
					$.ajax(
					{
						'url': '//ores-test.wmflabs.org/coder/forms/damaging_and_goodfaith',
						'dataType': 'jsonp'
					} )
					.done( load );
				} );
			}
		} );
	}

}( mediaWiki, jQuery ) );
<|endoftext|>


<commit_before>import React, { Component } from "react";
import { connect } from "react-redux";

import {
	addComponent,
	removeComponent,
	watchComponent,
	setQueryOptions,
	updateQuery,
	loadMore
} from "@appbaseio/reactivecore/lib/actions";
import {
	isEqual,
	getQueryOptions,
	pushToAndClause
} from "@appbaseio/reactivecore/lib/utils/helper";
import types from "@appbaseio/reactivecore/lib/utils/types";

import Button, { pagination } from "../../styles/Button";
import Card, { container, Title, Image } from "../../styles/Card";

class ResultCard extends Component {
	constructor(props) {
		super(props);

		this.state = {
			from: 0,
			isLoading: false,
			totalPages: 0,
			currentPage: 0
		};
		this.internalComponent = props.componentId + "__internal";
	}

	componentDidMount() {
		this.props.addComponent(this.internalComponent);
		this.props.addComponent(this.props.componentId);

		const options = getQueryOptions(this.props);
		if (this.props.sortBy) {
			options.sort = [{
				[this.props.dataField]: {
					order: this.props.sortBy
				}
			}];
		}

		// Override sort query with defaultQuery's sort if defined
		let defaultQuery = null;
		if (this.props.defaultQuery) {
			defaultQuery = this.props.defaultQuery();
			if (defaultQuery.sort) {
				options.sort = defaultQuery.sort;
			}
		}

		this.props.setQueryOptions(this.props.componentId, options);
		this.setReact(this.props);

		if (defaultQuery) {
			let { sort, ...query } = defaultQuery;
			this.props.updateQuery({
				componentId: this.internalComponent,
				query
			});
		} else {
			this.props.updateQuery({
				componentId: this.internalComponent,
				query: null
			});
		}

		if (!this.props.pagination) {
			window.addEventListener("scroll", this.scrollHandler);
		}
	}

	componentWillReceiveProps(nextProps) {
		if (this.props.sortBy !== nextProps.sortBy || this.props.size !== nextProps.size) {
			const options = getQueryOptions(nextProps);
			if (this.props.sortBy) {
				options.sort = [{
					[this.props.dataField]: {
						order: this.props.sortBy
					}
				}];
			}
			this.props.setQueryOptions(this.props.componentId, options);
		}

		if (!isEqual(nextProps.react, this.props.react)) {
			this.setReact(nextProps);
		}

		// called when page is changed
		if (this.props.pagination && this.state.isLoading) {
			window.scrollTo(0,0);
			this.setState({
				isLoading: false
			});
		}

		if (!nextProps.pagination && this.props.hits && nextProps.hits && (this.props.hits.length < nextProps.hits.length || nextProps.hits.length === nextProps.total)) {
			this.setState({
				isLoading: false
			});
		}

		if (!nextProps.pagination && nextProps.hits && this.props.hits && nextProps.hits.length < this.props.hits.length) {
			window.scrollTo(0,0);
			this.setState({
				from: 0,
				isLoading: false
			});
		}

		if (nextProps.pagination && nextProps.total !== this.props.total) {
			this.setState({
				totalPages: nextProps.total / nextProps.size,
				currentPage: 0
			});
		}

		if (nextProps.pagination !== this.props.pagination) {
			if (nextProps.pagination) {
				window.addEventListener("scroll", this.scrollHandler);
			} else {
				window.removeEventListener("scroll", this.scrollHandler);
			}
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);
	}

	setReact = (props) => {
		const { react } = props;
		if (react) {
			const newReact = pushToAndClause(react, this.internalComponent)
			props.watchComponent(props.componentId, newReact);
		} else {
			props.watchComponent(props.componentId, { and: this.internalComponent });
		}
	};

	scrollHandler = () => {
		if (!this.state.isLoading && (window.innerHeight + window.scrollY + 300) >= document.body.offsetHeight) {
			this.loadMore();
		}
	};

	loadMore = () => {
		if (this.props.hits && !this.props.pagination && this.props.total !== this.props.hits.length) {
			const value = this.state.from + this.props.size;
			const options = getQueryOptions(this.props);
			this.setState({
				from: value,
				isLoading: true
			});
			this.props.loadMore(this.props.componentId, {
				...options,
				from: value
			}, true);
		} else if (this.state.isLoading) {
			this.setState({
				isLoading: false
			});
		}
	};

	setPage = (page) => {
		const value = this.props.size * page;
		const options = getQueryOptions(this.props);
		this.setState({
			from: value,
			isLoading: true,
			currentPage: page
		});
		this.props.loadMore(this.props.componentId, {
			...options,
			from: value
		}, false);
	};

	prevPage = () => {
		if (this.state.currentPage) {
			this.setPage(this.state.currentPage-1);
		}
	};

	nextPage = () => {
		if (this.state.currentPage < this.state.totalPages-1) {
			this.setPage(this.state.currentPage+1);
		}
	};

	getStart = () => {
		const midValue = parseInt(this.props.pages/2, 10);
		const start =  this.state.currentPage - midValue;
		return start > 1 ? start : 2;
	};

	renderPagination = () => {
		let start = this.getStart(),
			pages = [];

		for (let i = start; i < start + this.props.pages - 1; i++) {
			const pageBtn = (
				<Button primary={this.state.currentPage === i-1} key={i-1} onClick={() => this.setPage(i-1)}>
					{i}
				</Button>
			);
			if (i <= this.state.totalPages+1) {
				pages.push(pageBtn);
			}
		}

		if (!this.state.totalPages) {
			return null;
		}

		return (

				<Button disabled={this.state.currentPage === 0} onClick={this.prevPage}>
					Prev
				</Button>
				{
					<Button primary={this.state.currentPage === 0} onClick={() => this.setPage(0)}>
						1
					</Button>
				}
				{
					pages
				}
				<Button disabled={this.state.currentPage >= this.state.totalPages-1} onClick={this.nextPage}>
					Next
				</Button>

		)
	};

	highlightResults = (result) => {
		const data = { ...result };
		if (data.highlight) {
			Object.keys(data.highlight).forEach((highlightItem) => {
				const highlightValue = data.highlight[highlightItem][0];
				data._source = Object.assign({}, data._source, { [highlightItem]: highlightValue });
			});
		}
		return data;
	};

	parseHits = (hits) => {
		let results = null;
		if (hits) {
			results = [...hits].map(this.highlightResults);
		}
		return results;
	};

	renderAsCard = (item) => {
		const result = this.props.onData(item);
		return (<Card key={item._id} href={result.url}>
			<Image src={result.image}></Image>
			<Title>{result.title}</Title>

{result.desc}

		</Card>);
	};

	renderResultStats = () => {
		if (this.props.onResultStats) {
			return this.props.onResultStats(this.props.total, this.props.time);
		} else if (this.props.total) {
			return
{this.props.total} results found in {this.props.time}ms
;
		}
		return null;
	};

	render() {
		const results = this.parseHits(this.props.hits) || [];
		return (

				{this.props.isLoading && this.props.pagination && this.props.loader && this.props.loader}
				{
					this.props.showResultStats
						? this.renderResultStats()
						: null
				}
				{
					this.props.pagination && this.props.paginationAt !== "bottom"
						? this.renderPagination()
						: null
				}
				{
					this.props.pagination && this.props.paginationAt !== "bottom"
						? this.renderPagination()
						: null
				}

					{
						results.map(item => this.renderAsCard(item))
					}

				{
					this.state.isLoading && !this.props.pagination
						? (

							Loading...

)
						: null
				}
				{
					this.props.pagination && this.props.paginationAt !== "top"
						? this.renderPagination()
						: null
				}

		);
	}
}

ResultCard.propTypes = {
	addComponent: types.funcRequired,
	componentId: types.stringRequired,
	sortBy: types.sortBy,
	dataField: types.stringRequired,
	setQueryOptions: types.funcRequired,
	defaultQuery: types.func,
	updateQuery: types.funcRequired,
	size: types.number,
	react: types.react,
	pagination: types.bool,
	paginationAt: types.paginationAt,
	hits: types.hits,
	total: types.number,
	removeComponent: types.funcRequired,
	loadMore: types.funcRequired,
	pages: types.number,
	onAllData: types.func,
	onData: types.func,
	time: types.number,
	showResultStats: types.bool,
	onResultStats: types.func,
	loader: types.title,
	isLoading: types.bool
}

ResultCard.defaultProps = {
	pagination: false,
	paginationAt: "bottom",
	pages: 5,
	size: 10,
	from: 0,
	showResultStats: true
}

const mapStateToProps = (state, props) => ({
	hits: state.hits[props.componentId] && state.hits[props.componentId].hits,
	total: state.hits[props.componentId] && state.hits[props.componentId].total,
	time: state.hits[props.componentId] && state.hits[props.componentId].time || 0,
	isLoading: state.isLoading[props.componentId] || false
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	watchComponent: (component, react) => dispatch(watchComponent(component, react)),
	setQueryOptions: (component, props) => dispatch(setQueryOptions(component, props)),
	updateQuery: (updateQueryObject) => dispatch(updateQuery(updateQueryObject)),
	loadMore: (component, options, append) => dispatch(loadMore(component, options, append))
});

export default connect(mapStateToProps, mapDispatchtoProps)(ResultCard);
<commit_msg>:art: Add ResultCard style and className support<commit_after>import React, { Component } from "react";
import { connect } from "react-redux";

import {
	addComponent,
	removeComponent,
	watchComponent,
	setQueryOptions,
	updateQuery,
	loadMore
} from "@appbaseio/reactivecore/lib/actions";
import {
	isEqual,
	getQueryOptions,
	pushToAndClause
} from "@appbaseio/reactivecore/lib/utils/helper";
import types from "@appbaseio/reactivecore/lib/utils/types";

import Button, { pagination } from "../../styles/Button";
import Card, { container, Title, Image } from "../../styles/Card";

class ResultCard extends Component {
	constructor(props) {
		super(props);

		this.state = {
			from: 0,
			isLoading: false,
			totalPages: 0,
			currentPage: 0
		};
		this.internalComponent = props.componentId + "__internal";
	}

	componentDidMount() {
		this.props.addComponent(this.internalComponent);
		this.props.addComponent(this.props.componentId);

		const options = getQueryOptions(this.props);
		if (this.props.sortBy) {
			options.sort = [{
				[this.props.dataField]: {
					order: this.props.sortBy
				}
			}];
		}

		// Override sort query with defaultQuery's sort if defined
		let defaultQuery = null;
		if (this.props.defaultQuery) {
			defaultQuery = this.props.defaultQuery();
			if (defaultQuery.sort) {
				options.sort = defaultQuery.sort;
			}
		}

		this.props.setQueryOptions(this.props.componentId, options);
		this.setReact(this.props);

		if (defaultQuery) {
			let { sort, ...query } = defaultQuery;
			this.props.updateQuery({
				componentId: this.internalComponent,
				query
			});
		} else {
			this.props.updateQuery({
				componentId: this.internalComponent,
				query: null
			});
		}

		if (!this.props.pagination) {
			window.addEventListener("scroll", this.scrollHandler);
		}
	}

	componentWillReceiveProps(nextProps) {
		if (this.props.sortBy !== nextProps.sortBy || this.props.size !== nextProps.size) {
			const options = getQueryOptions(nextProps);
			if (this.props.sortBy) {
				options.sort = [{
					[this.props.dataField]: {
						order: this.props.sortBy
					}
				}];
			}
			this.props.setQueryOptions(this.props.componentId, options);
		}

		if (!isEqual(nextProps.react, this.props.react)) {
			this.setReact(nextProps);
		}

		// called when page is changed
		if (this.props.pagination && this.state.isLoading) {
			window.scrollTo(0,0);
			this.setState({
				isLoading: false
			});
		}

		if (!nextProps.pagination && this.props.hits && nextProps.hits && (this.props.hits.length < nextProps.hits.length || nextProps.hits.length === nextProps.total)) {
			this.setState({
				isLoading: false
			});
		}

		if (!nextProps.pagination && nextProps.hits && this.props.hits && nextProps.hits.length < this.props.hits.length) {
			window.scrollTo(0,0);
			this.setState({
				from: 0,
				isLoading: false
			});
		}

		if (nextProps.pagination && nextProps.total !== this.props.total) {
			this.setState({
				totalPages: nextProps.total / nextProps.size,
				currentPage: 0
			});
		}

		if (nextProps.pagination !== this.props.pagination) {
			if (nextProps.pagination) {
				window.addEventListener("scroll", this.scrollHandler);
			} else {
				window.removeEventListener("scroll", this.scrollHandler);
			}
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);
	}

	setReact = (props) => {
		const { react } = props;
		if (react) {
			const newReact = pushToAndClause(react, this.internalComponent)
			props.watchComponent(props.componentId, newReact);
		} else {
			props.watchComponent(props.componentId, { and: this.internalComponent });
		}
	};

	scrollHandler = () => {
		if (!this.state.isLoading && (window.innerHeight + window.scrollY + 300) >= document.body.offsetHeight) {
			this.loadMore();
		}
	};

	loadMore = () => {
		if (this.props.hits && !this.props.pagination && this.props.total !== this.props.hits.length) {
			const value = this.state.from + this.props.size;
			const options = getQueryOptions(this.props);
			this.setState({
				from: value,
				isLoading: true
			});
			this.props.loadMore(this.props.componentId, {
				...options,
				from: value
			}, true);
		} else if (this.state.isLoading) {
			this.setState({
				isLoading: false
			});
		}
	};

	setPage = (page) => {
		const value = this.props.size * page;
		const options = getQueryOptions(this.props);
		this.setState({
			from: value,
			isLoading: true,
			currentPage: page
		});
		this.props.loadMore(this.props.componentId, {
			...options,
			from: value
		}, false);
	};

	prevPage = () => {
		if (this.state.currentPage) {
			this.setPage(this.state.currentPage-1);
		}
	};

	nextPage = () => {
		if (this.state.currentPage < this.state.totalPages-1) {
			this.setPage(this.state.currentPage+1);
		}
	};

	getStart = () => {
		const midValue = parseInt(this.props.pages/2, 10);
		const start =  this.state.currentPage - midValue;
		return start > 1 ? start : 2;
	};

	renderPagination = () => {
		let start = this.getStart(),
			pages = [];

		for (let i = start; i < start + this.props.pages - 1; i++) {
			const pageBtn = (
				<Button primary={this.state.currentPage === i-1} key={i-1} onClick={() => this.setPage(i-1)}>
					{i}
				</Button>
			);
			if (i <= this.state.totalPages+1) {
				pages.push(pageBtn);
			}
		}

		if (!this.state.totalPages) {
			return null;
		}

		return (

				<Button disabled={this.state.currentPage === 0} onClick={this.prevPage}>
					Prev
				</Button>
				{
					<Button primary={this.state.currentPage === 0} onClick={() => this.setPage(0)}>
						1
					</Button>
				}
				{
					pages
				}
				<Button disabled={this.state.currentPage >= this.state.totalPages-1} onClick={this.nextPage}>
					Next
				</Button>

		)
	};

	highlightResults = (result) => {
		const data = { ...result };
		if (data.highlight) {
			Object.keys(data.highlight).forEach((highlightItem) => {
				const highlightValue = data.highlight[highlightItem][0];
				data._source = Object.assign({}, data._source, { [highlightItem]: highlightValue });
			});
		}
		return data;
	};

	parseHits = (hits) => {
		let results = null;
		if (hits) {
			results = [...hits].map(this.highlightResults);
		}
		return results;
	};

	renderAsCard = (item) => {
		const result = this.props.onData(item);
		return (<Card key={item._id} href={result.url}>
			<Image src={result.image}></Image>
			<Title>{result.title}</Title>

{result.desc}

		</Card>);
	};

	renderResultStats = () => {
		if (this.props.onResultStats) {
			return this.props.onResultStats(this.props.total, this.props.time);
		} else if (this.props.total) {
			return
{this.props.total} results found in {this.props.time}ms
;
		}
		return null;
	};

	render() {
		const results = this.parseHits(this.props.hits) || [];
		return (

				{this.props.isLoading && this.props.pagination && this.props.loader && this.props.loader}
				{
					this.props.showResultStats
						? this.renderResultStats()
						: null
				}
				{
					this.props.pagination && this.props.paginationAt !== "bottom"
						? this.renderPagination()
						: null
				}
				{
					this.props.pagination && this.props.paginationAt !== "bottom"
						? this.renderPagination()
						: null
				}

					{
						results.map(item => this.renderAsCard(item))
					}

				{
					this.state.isLoading && !this.props.pagination
						? (

							Loading...

)
						: null
				}
				{
					this.props.pagination && this.props.paginationAt !== "top"
						? this.renderPagination()
						: null
				}

		);
	}
}

ResultCard.propTypes = {
	addComponent: types.funcRequired,
	componentId: types.stringRequired,
	sortBy: types.sortBy,
	dataField: types.stringRequired,
	setQueryOptions: types.funcRequired,
	defaultQuery: types.func,
	updateQuery: types.funcRequired,
	size: types.number,
	react: types.react,
	pagination: types.bool,
	paginationAt: types.paginationAt,
	hits: types.hits,
	total: types.number,
	removeComponent: types.funcRequired,
	loadMore: types.funcRequired,
	pages: types.number,
	onAllData: types.func,
	onData: types.func,
	time: types.number,
	showResultStats: types.bool,
	onResultStats: types.func,
	loader: types.title,
	isLoading: types.bool,
	style: types.style,
	className: types.string
}

ResultCard.defaultProps = {
	pagination: false,
	paginationAt: "bottom",
	pages: 5,
	size: 10,
	from: 0,
	showResultStats: true,
	style: {},
	className: null
}

const mapStateToProps = (state, props) => ({
	hits: state.hits[props.componentId] && state.hits[props.componentId].hits,
	total: state.hits[props.componentId] && state.hits[props.componentId].total,
	time: state.hits[props.componentId] && state.hits[props.componentId].time || 0,
	isLoading: state.isLoading[props.componentId] || false
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	watchComponent: (component, react) => dispatch(watchComponent(component, react)),
	setQueryOptions: (component, props) => dispatch(setQueryOptions(component, props)),
	updateQuery: (updateQueryObject) => dispatch(updateQuery(updateQueryObject)),
	loadMore: (component, options, append) => dispatch(loadMore(component, options, append))
});

export default connect(mapStateToProps, mapDispatchtoProps)(ResultCard);
<|endoftext|>


<commit_before>/*
 * jQuery UIx FilterBuilder
 *
 * Authors:
 *  Yanick Rochon (yanick.rochon[at]gmail[dot]com)
 *
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 *
 * Filter ruiles : JS
 *
 */

(function ($) {

    var FIELD_ESCAPE_START = "";
    var FIELD_ESCAPE_END = "";
    var STRING_ESCAPE_START = "\"";
    var STRING_ESCAPE_END = "\"";

    function quoteField(value) {
        return FIELD_ESCAPE_START + value + FIELD_ESCAPE_END;
    };
    function quoteValue(value) {
        if (isNaN(parseFloat(value))) {
            value = STRING_ESCAPE_START + value + STRING_ESCAPE_END;
        }
        return value;
    };

    var rules = $.uix.filterbuilder.rules['js'] = {
        //features: {  // not implemented
        //    subClauses: true,           // are subclauses allowed?
        //    subClauseMaxDepth: 0,       // maximum depth of sub clauses
        //    clauseConditionCount: 0,    // maximum number of conditions per clause
        //},
        defaultClauseWrap: "(@1)",
        defaultClauseExpression: "expr.match.any",
        defaultFieldExpression: "expr.equal",

        // NOTE : operators may be referenced by expression patterns. Ex:
		//        "@1 {:eq} @2"                     resolves to "@1 == @2"
		//        "{:not}@1 {:neq} @2"  resolves to "!@1 != @2"
        operators: {
			"ieq": "===",
			"ineq": "!==",
			"eq": "==",
			"neq": "!=",
			"lt": "<",
			"lte": "<=",
			"gt": ">",
			"gte": ">=",
			"and": "&&",
			"or": "||",
            "not": "!"
        },

        clauseExpressions: {
			// expression clause grouping operator, where @1 and @2 are left and write clauses
			// if an array, first element is grouping left and right, second element wraps the entire clause
			"expr.match.all": { pattern: "@1 {:and} @2" },
			"expr.match.any": { pattern: "@1 {:or} @2" },
			"expr.match.none": { pattern: "@1 {:or} @2", wrap: "{:not}(@1)" },
        },

        fieldExpressions: {
			// field operators, where @1 is the field and @2, @3 are the field params
			"expr.equal": { pattern: "@1 {:ieq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.not.equal": { pattern: "@1 {:ineq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.match": { pattern: "@1 {:eq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.not.match": { pattern: "@1 {:neq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.null": { pattern: "@1 {:ieq} null {:or} @1 {:ieq} undefined", params: { "@1": "field" } },
			"expr.not.null": { pattern: "@1 {:ineq} null {:or} @1 {:ineq} undefined", params: { "@1": "field" } },
			"expr.between": { pattern: "(@1 {:gt} @2 {:and} @1 {:lt} @3)", params: { "@1": "field", "@2": "any", "@3": "any" } },
			"expr.between.inc": { pattern: "(@1 {:gte} @2 {:and} @1 {:lte} @3)", params: { "@1": "field", "@2": "any", "@3": "any" } },
			"expr.contain": { pattern: "@1.indexOf(@2) {:gte} -1", params: { "@1": "field", "@2": "any" } },
			"expr.not.contain": { pattern: "@1.indexOf(@2) {:ieq} -1", params: { "@1": "field", "@2": "any" } },
			"expr.start.with": { pattern: "@1.indexOf(@2) {:gte} 0", params: { "@1": "field", "@2": "any" } },
			"expr.not.start.with": { pattern: "@1.indexOf(@2) {:ineq} 0", params: { "@1": "field", "@2": "any" } },
			"expr.end.with": { pattern: "@1.indexOf(@2) {:ieq} ((''+@1).length - (''+@2).length)", params: { "@1": "field", "@2": "any" } },
			"expr.not.end.with": { pattern: "@1.indexOf(@2) {:ineq} ((''+@1).length - (''+@2).length)", params: { "@1": "field", "@2": "any" } },
			"expr.less.than": { pattern: "@1 {:lt} @2", params: { "@1": "field", "@2": "any" } },
			"expr.less.than.equal": { pattern: "@1 {:lte} @2", params: { "@1": "field", "@2": "any" } },
			"expr.greater.than": { pattern: "@1 {:gt} @2", params: { "@1": "field", "@2": "any" } },
			"expr.greater.than.equal": { pattern: "@1 {:gte} @2", params: { "@1": "field", "@2": "any" } }
        },

        paramHandlers: {
            "field": {
                render: function(value) {
                    return $("<input>").prop("type", "text").val(value || "").autocomplete({
                        source: this.options.fields
                    });
                },
                format: function(element) {
                    return [quoteField(element.val() || "")];
                },
                serialize: function(element) {
                    return element.data("param-name") + "=" + (element.val() || "");
                },
                deserialize: function(data) {
                    var parts = data.split("=");
                    return rules.paramHandlers["field"].render.call(this).attr("data-param-name", parts[0]).val(parts[1] || "");
                }
            },
            "any": {
            	render: function(value) {
            		var self = this;
                    var parts = (value || "").split("/");
                    var check = $("<input>").prop("type", "checkbox").prop("checked", !!parseInt(parts[0])).uniqueId()
						.on("click change", function () {
							input.autocomplete("option", "source", $(this).is(":checked") ? self.options.fields : []);
						});
                    var label = $("<label>").prop("for", check.prop("id")).text(this._t("param.check.field")).val(parts.slice(1).join("/") || "");
                    var input = $("<input>").prop("type", "text").autocomplete({
						source: !!parseInt(parts[0]) ? this.options.fields : []
                    });
                    return $("<nobr>").append(check).append(label).append(input);
                },
                format: function(element) {
                    var checked = element.filter("input:checkbox").is(":checked");
                    var val = element.filter("input[type='text']").val() || "";
                    if (checked) {
                        val = quoteField(val);
                    } else {
                        val = quoteValue(val);
                    }
                    return [val];
                },
                serialize: function(element) {
                    var checked = element.filter("input:checkbox").is(":checked");
                    var val = element.filter("input[type='text']").val() || "";
                    return element.data("param-name") + "=" + (checked ? 1 : 0) + "/" + val;
                },
                deserialize: function(data) {
                    var parts = data.split("=");
                    var vals = (parts[1] || "").split("/");
                    return rules.paramHandlers["any"].render.call(this)
                        .filter("input[type='checkbox']").prop("checked", !!parseInt(vals[0])).end()
                        .filter("input[type='text']").val(vals[1] || "").end();
                }
            }
        }

    };

})(jQuery);
<commit_msg>Update jquery.uix.filterbuilder_js.js<commit_after>/*
 * jQuery UIx FilterBuilder
 *
 * Authors:
 *  Yanick Rochon (yanick.rochon[at]gmail[dot]com)
 *
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 *
 * Filter ruiles : JS
 *
 */

(function ($) {

    var FIELD_ESCAPE_START = "";
    var FIELD_ESCAPE_END = "";
    var STRING_ESCAPE_START = "\"";
    var STRING_ESCAPE_END = "\"";

    function quoteField(value) {
        return FIELD_ESCAPE_START + value + FIELD_ESCAPE_END;
    };
    function quoteValue(value) {
        if (isNaN(parseFloat(value))) {
            value = STRING_ESCAPE_START + value + STRING_ESCAPE_END;
        }
        return value;
    };

    var rules = $.uix.filterbuilder.rules['js'] = {
        //features: {  // not implemented
        //    subClauses: true,           // are subclauses allowed?
        //    subClauseMaxDepth: 0,       // maximum depth of sub clauses
        //    clauseConditionCount: 0,    // maximum number of conditions per clause
        //},
        defaultClauseWrap: "(@1)",
        defaultClauseExpression: "expr.match.any",
        defaultFieldExpression: "expr.equal",

        // NOTE : operators may be referenced by expression patterns. Ex:
    	//        "@1 {:eq} @2"                     resolves to "@1 == @2"
		//        "{:not}@1 {:neq} @2"  resolves to "!@1 != @2"
        operators: {
			"ieq": "===",
			"ineq": "!==",
			"eq": "==",
			"neq": "!=",
			"lt": "<",
			"lte": "<=",
			"gt": ">",
			"gte": ">=",
			"and": "&&",
			"or": "||",
            "not": "!"
        },

        clauseExpressions: {
			// expression clause grouping operator, where @1 and @2 are left and write clauses
			// if an array, first element is grouping left and right, second element wraps the entire clause
			"expr.match.all": { pattern: "@1 {:and} @2" },
			"expr.match.any": { pattern: "@1 {:or} @2" },
			"expr.match.none": { pattern: "@1 {:or} @2", wrap: "{:not}(@1)" },
        },

        fieldExpressions: {
			// field operators, where @1 is the field and @2, @3 are the field params
			"expr.equal": { pattern: "@1 {:ieq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.not.equal": { pattern: "@1 {:ineq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.match": { pattern: "@1 {:eq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.not.match": { pattern: "@1 {:neq} @2", params: { "@1": "field", "@2": "any" } },
			"expr.null": { pattern: "@1 {:ieq} null {:or} @1 {:ieq} undefined", params: { "@1": "field" } },
			"expr.not.null": { pattern: "@1 {:ineq} null {:or} @1 {:ineq} undefined", params: { "@1": "field" } },
			"expr.between": { pattern: "(@1 {:gt} @2 {:and} @1 {:lt} @3)", params: { "@1": "field", "@2": "any", "@3": "any" } },
			"expr.between.inc": { pattern: "(@1 {:gte} @2 {:and} @1 {:lte} @3)", params: { "@1": "field", "@2": "any", "@3": "any" } },
			"expr.contain": { pattern: "@1.indexOf(@2) {:gte} -1", params: { "@1": "field", "@2": "any" } },
			"expr.not.contain": { pattern: "@1.indexOf(@2) {:ieq} -1", params: { "@1": "field", "@2": "any" } },
			"expr.start.with": { pattern: "@1.indexOf(@2) {:gte} 0", params: { "@1": "field", "@2": "any" } },
			"expr.not.start.with": { pattern: "@1.indexOf(@2) {:ineq} 0", params: { "@1": "field", "@2": "any" } },
			"expr.end.with": { pattern: "@1.indexOf(@2) {:ieq} ((''+@1).length - (''+@2).length)", params: { "@1": "field", "@2": "any" } },
			"expr.not.end.with": { pattern: "@1.indexOf(@2) {:ineq} ((''+@1).length - (''+@2).length)", params: { "@1": "field", "@2": "any" } },
			"expr.less.than": { pattern: "@1 {:lt} @2", params: { "@1": "field", "@2": "any" } },
			"expr.less.than.equal": { pattern: "@1 {:lte} @2", params: { "@1": "field", "@2": "any" } },
			"expr.greater.than": { pattern: "@1 {:gt} @2", params: { "@1": "field", "@2": "any" } },
			"expr.greater.than.equal": { pattern: "@1 {:gte} @2", params: { "@1": "field", "@2": "any" } }
        },

        paramHandlers: {
            "field": {
                render: function(value) {
                    return $("<input>").prop("type", "text").val(value || "").autocomplete({
                        source: this.options.fields
                    });
                },
                format: function(element) {
                    return [quoteField(element.val() || "")];
                },
                serialize: function(element) {
                    return element.data("param-name") + "=" + (element.val() || "");
                },
                deserialize: function(data) {
                    var parts = data.split("=");
                    return rules.paramHandlers["field"].render.call(this).attr("data-param-name", parts[0]).val(parts[1] || "");
                }
            },
            "any": {
            	render: function(value) {
            		var self = this;
                    var parts = (value || "").split("/");
                    var check = $("<input>").prop("type", "checkbox").prop("checked", !!parseInt(parts[0])).uniqueId()
						.on("click change", function () {
							input.autocomplete("option", "source", $(this).is(":checked") ? self.options.fields : []);
						});
                    var label = $("<label>").prop("for", check.prop("id")).text(this._t("param.check.field")).val(parts.slice(1).join("/") || "");
                    var input = $("<input>").prop("type", "text").autocomplete({
						source: !!parseInt(parts[0]) ? this.options.fields : []
                    });
                    return $("<nobr>").append(check).append(label).append(input);
                },
                format: function(element) {
                    var checked = element.filter("input:checkbox").is(":checked");
                    var val = element.filter("input[type='text']").val() || "";
                    if (checked) {
                        val = quoteField(val);
                    } else {
                        val = quoteValue(val);
                    }
                    return [val];
                },
                serialize: function(element) {
                    var checked = element.filter("input:checkbox").is(":checked");
                    var val = element.find("input[type='text']").val() || "";
                    return element.data("param-name") + "=" + (checked ? 1 : 0) + "/" + val;
                },
                deserialize: function(data) {
                    var parts = data.split("=");
                    var vals = (parts[1] || "").split("/");
                    return rules.paramHandlers["any"].render.call(this)
                        .find("input[type='checkbox']").prop("checked", !!parseInt(vals[0])).end()
                        .find("input[type='text']").val(vals[1] || "").end();
                }
            }
        }

    };

})(jQuery);
<|endoftext|>


<commit_before>"use strict";

const functions = require('firebase-functions')
const admin = require('firebase-admin')
const express = require('express')
const generate = require('./export.js')
const database = require('./database.js')
const app = express()

admin.initializeApp({
	credential: admin.credential.applicationDefault(),
	databaseURL: 'https://app-localization-2f645.firebaseio.com'
})

app.get('/export/:locale/android', (request, response) =>
{
	const localeCode = request.param('locale')

	database.localesRef(admin).once('value', localesSnap =>
	{
		const locale = database.localeByCode(localeCode, localesSnap)

		return database.translationsRef(admin).once('value', translationsSnap =>
		{
			response.set('content-disposition', `attachment; filename="strings-${localeCode}.xml"`)
			response.send(generate.android(locale.key, translationsSnap.val()))
		})
	})
})

app.get('/export/:locale/ios', (request, response) =>
{
	const localeCode = request.param('locale')

	database.localesRef(admin).once('value', localesSnap =>
	{
		const locale = database.localeByCode(localeCode, localesSnap)

		return database.translationsRef(admin).once('value', translationsSnap =>
		{
			response.set('content-disposition', `attachment; filename="Localizable-${localeCode}.strings"`)
			response.send(generate.ios(locale.key, translationsSnap.val()))
		})
	})
})

const api = express()
api.use('/api', app)

exports.api = functions.https.onRequest(api)

// https://github.com/firebase/functions-samples
// https://us-central1-app-localization-2f645.cloudfunctions.net/[function]
/*exports.example = functions.https.onRequest((request, response) =>
{
	response.json({property:123})
})*/

exports.addHistory = functions.database.ref('/translations/{translationId}/locales/{localeId}/value').onWrite(event =>
{
	const entry = {
		value: event.data.previous.val(),
		author: event.auth.variable.email
	}

	return event.data.ref.parent.child('history').push(entry)
})<commit_msg>Fixed error in history trigger<commit_after>"use strict";

const functions = require('firebase-functions')
const admin = require('firebase-admin')
const express = require('express')
const generate = require('./export.js')
const database = require('./database.js')
const app = express()

admin.initializeApp({
	credential: admin.credential.applicationDefault(),
	databaseURL: 'https://app-localization-2f645.firebaseio.com'
})

app.get('/export/:locale/android', (request, response) =>
{
	const localeCode = request.param('locale')

	database.localesRef(admin).once('value', localesSnap =>
	{
		const locale = database.localeByCode(localeCode, localesSnap)

		return database.translationsRef(admin).once('value', translationsSnap =>
		{
			response.set('content-disposition', `attachment; filename="strings-${localeCode}.xml"`)
			response.send(generate.android(locale.key, translationsSnap.val()))
		})
	})
})

app.get('/export/:locale/ios', (request, response) =>
{
	const localeCode = request.param('locale')

	database.localesRef(admin).once('value', localesSnap =>
	{
		const locale = database.localeByCode(localeCode, localesSnap)

		return database.translationsRef(admin).once('value', translationsSnap =>
		{
			response.set('content-disposition', `attachment; filename="Localizable-${localeCode}.strings"`)
			response.send(generate.ios(locale.key, translationsSnap.val()))
		})
	})
})

const api = express()
api.use('/api', app)

exports.api = functions.https.onRequest(api)

// https://github.com/firebase/functions-samples
// https://us-central1-app-localization-2f645.cloudfunctions.net/[function]
/*exports.example = functions.https.onRequest((request, response) =>
{
	response.json({property:123})
})*/

exports.addHistory = functions.database.ref('/translations/{translationId}/locales/{localeId}/value').onUpdate(event =>
{
	const entry = {
		value: event.data.previous.val(),
		author: event.auth.variable.email
	}

	return event.data.ref.parent.child('history').push(entry)
})<|endoftext|>


<commit_before>import React from 'react';
import types from '@appbaseio/reactivecore/lib/utils/types';
import MicIcon from '../../../styles/MicIcon';
import { getComponent, hasCustomRenderer } from '../../../utils';
import MicSvg from '../../shared/MicSvg';
import MuteSvg from '../../shared/MuteSvg';
import ListenSvg from '../../shared/ListenSvg';

const STATUS = {
	inactive: 'INACTIVE',
	stopped: 'STOPPED',
	active: 'ACTIVE',
	denied: 'DENIED',
};

class Mic extends React.Component {
	constructor() {
		super();
		this.state = {
			status: STATUS.inactive,
		};
		window.SpeechRecognition
			= window.webkitSpeechRecognition || window.SpeechRecognition || null;
		this.results = [];
	}

	handleClick = () => {
		this.results = [];
		if (window.SpeechRecognition) {
			const { status } = this.state;
			if (status === STATUS.active) {
				this.setState({
					status: STATUS.inactive,
				});
			}
			const {
				onResult, onNoMatch, onError, lang, getInstance,
			} = this.props;
			const { SpeechRecognition } = window;
			if (this.instance) {
				this.setState(
					{
						status: STATUS.inactive,
					},
					() => {
						this.instance.stop();
						this.instance = null;
					},
				);
				return;
			}
			this.instance = new SpeechRecognition();
			this.instance.continuous = true;
			this.instance.interimResults = true;
			this.instance.lang = lang;
			if (getInstance) {
				getInstance(this.instance);
			}
			this.instance.start();
			this.instance.onstart = () => {
				this.setState({
					status: STATUS.active,
				});
			};
			this.instance.onresult = ({ results, timeStamp }) => {
				this.setState({
					status: STATUS.inactive,
				});
				if (onResult) {
					onResult({ results, timeStamp });
				}
				this.results.push({ results, timeStamp });
			};
			this.instance.onnomatch = e => (onNoMatch ? onNoMatch(e) : console.warn(e));
			this.instance.onerror = (e) => {
				if (e.error === 'no-speech' || e.error === 'audio-capture') {
					this.setState({
						status: STATUS.inactive,
					});
				} else if (e.error === 'not-allowed') {
					this.setState({
						status: STATUS.denied,
					});
				}
				console.error(e);
				if (onError) {
					onError(e);
				}
			};

			/* Below Two methods run when Continuous is False */
			this.instance.onspeechend = () => {
				this.setState({
					status: STATUS.inactive,
				});
			};

			this.instance.onaudioend = () => {
				this.setState({
					status: STATUS.inactive,
				});
			};
		}
	};

	get Icon() {
		const { status } = this.state;
		const { className } = this.props;
		switch (status) {
			case STATUS.active:
				return <ListenSvg className={className} onClick={this.handleClick} />;
			case STATUS.stopped:
			case STATUS.denied:
				return <MuteSvg className={className} onClick={this.handleClick} />;
			default:
				return <MicSvg className={className} onClick={this.handleClick} />;
		}
	}

	getComponent() {
		const { status } = this.state;
		const data = {
			handleClick: this.handleClick,
			status,
		};
		return getComponent(data, this.props);
	}

	get hasCustomRenderer() {
		return hasCustomRenderer(this.props);
	}

	render() {
		const { iconPosition } = this.props;
		if (this.hasCustomRenderer) {
			return this.getComponent();
		}
		return <MicIcon iconPosition={iconPosition}>{this.Icon}</MicIcon>;
	}
}

Mic.defaultProps = {
	lang: 'en-US',
	iconPosition: 'left',
};

Mic.propTypes = {
	children: types.title,
	lang: types.string,
	iconPosition: types.string,
	onResult: types.func,
	onNoMatch: types.func,
	onError: types.func,
	getInstance: types.func,
	render: types.func,
	className: types.string,
};

export default Mic;
<commit_msg>fix(web): voice search issues<commit_after>import React from 'react';
import types from '@appbaseio/reactivecore/lib/utils/types';
import MicIcon from '../../../styles/MicIcon';
import { getComponent, hasCustomRenderer } from '../../../utils';
import MicSvg from '../../shared/MicSvg';
import MuteSvg from '../../shared/MuteSvg';
import ListenSvg from '../../shared/ListenSvg';

const STATUS = {
	inactive: 'INACTIVE',
	stopped: 'STOPPED',
	active: 'ACTIVE',
	denied: 'DENIED',
};

class Mic extends React.Component {
	constructor() {
		super();
		this.state = {
			status: STATUS.inactive,
		};
		window.SpeechRecognition
			= window.webkitSpeechRecognition || window.SpeechRecognition || null;
		this.results = [];
	}

	stopMic = () => {
		if (this.instance) {
			this.setState(
				{
					status: STATUS.inactive,
				},
				() => {
					this.instance.stop();
					this.instance = null;
				},
			);
		}
	};

	handleClick = () => {
		this.results = [];
		const { status } = this.state;
		if (window.SpeechRecognition && status !== STATUS.denied) {
			if (status === STATUS.active) {
				this.setState({
					status: STATUS.inactive,
				});
			}
			const {
				onResult, onNoMatch, onError, lang, getInstance,
			} = this.props;
			const { SpeechRecognition } = window;
			if (this.instance) {
				this.stopMic();
				return;
			}
			this.instance = new SpeechRecognition();
			this.instance.continuous = true;
			this.instance.interimResults = true;
			this.instance.lang = lang;
			if (getInstance) {
				getInstance(this.instance);
			}
			this.instance.start();
			this.instance.onstart = () => {
				this.setState({
					status: STATUS.active,
				});
			};
			this.instance.onresult = ({ results, timeStamp }) => {
				this.stopMic();
				if (onResult) {
					onResult({ results, timeStamp });
				}
				this.results.push({ results, timeStamp });
			};
			this.instance.onnomatch = e => (onNoMatch ? onNoMatch(e) : console.warn(e));
			this.instance.onerror = (e) => {
				if (e.error === 'no-speech' || e.error === 'audio-capture') {
					this.setState({
						status: STATUS.inactive,
					});
				} else if (e.error === 'not-allowed') {
					this.setState({
						status: STATUS.denied,
					});
				}
				console.error(e);
				if (onError) {
					onError(e);
				}
			};

			/* Below Two methods run when Continuous is False */
			this.instance.onspeechend = () => {
				this.setState({
					status: STATUS.inactive,
				});
			};

			this.instance.onaudioend = () => {
				this.setState({
					status: STATUS.inactive,
				});
			};
		}
	};

	get Icon() {
		const { status } = this.state;
		const { className } = this.props;
		switch (status) {
			case STATUS.active:
				return <ListenSvg className={className} onClick={this.handleClick} />;
			case STATUS.stopped:
			case STATUS.denied:
				return <MuteSvg className={className} onClick={this.handleClick} />;
			default:
				return <MicSvg className={className} onClick={this.handleClick} />;
		}
	}

	getComponent() {
		const { status } = this.state;
		const data = {
			handleClick: this.handleClick,
			status,
		};
		return getComponent(data, this.props);
	}

	get hasCustomRenderer() {
		return hasCustomRenderer(this.props);
	}

	render() {
		const { iconPosition } = this.props;
		if (this.hasCustomRenderer) {
			return this.getComponent();
		}
		return <MicIcon iconPosition={iconPosition}>{this.Icon}</MicIcon>;
	}
}

Mic.defaultProps = {
	lang: 'en-US',
	iconPosition: 'left',
};

Mic.propTypes = {
	children: types.title,
	lang: types.string,
	iconPosition: types.string,
	onResult: types.func,
	onNoMatch: types.func,
	onError: types.func,
	getInstance: types.func,
	render: types.func,
	className: types.string,
};

export default Mic;
<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 80 */
/*global require, db, assertEqual, assertTrue, ArangoCollection */

////////////////////////////////////////////////////////////////////////////////
/// @brief test the skip-list index
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var jsunity = require("jsunity");
var internal = require("internal");
var errors = internal.errors;

// -----------------------------------------------------------------------------
// --SECTION--                                                     basic methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: Creation
////////////////////////////////////////////////////////////////////////////////

function SkipListSuite() {
  var cn = "UnitTestsCollectionSkiplist";
  var collection = null;

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

  setUp : function () {
    internal.db._drop(cn);
    collection = internal.db._create(cn, { waitForSync : false });
  },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

  tearDown : function () {
    // try...catch is necessary as some tests delete the collection itself!
    try {
      collection.unload();
      collection.drop();
    }
    catch (err) {
    }

    collection = null;
    internal.wait(0.0);
  },

////////////////////////////////////////////////////////////////////////////////
/// @brief test: hash index creation
////////////////////////////////////////////////////////////////////////////////

    testCreationUniqueConstraint : function () {
      var idx = collection.ensureSkiplist("a");
      var id = idx.id;

      assertNotEqual(0, id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a"], idx.fields);
      assertEqual(true, idx.isNewlyCreated);

      idx = collection.ensureSkiplist("a");

      assertEqual(id, idx.id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a"], idx.fields);
      assertEqual(false, idx.isNewlyCreated);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test: permuted attributes
////////////////////////////////////////////////////////////////////////////////

    testCreationPermutedSkiplist : function () {
      var idx = collection.ensureSkiplist("a", "b");
      var id = idx.id;

      assertNotEqual(0, id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a","b"], idx.fields);
      assertEqual(true, idx.isNewlyCreated);

      idx = collection.ensureSkiplist("b", "a");

      assertNotEqual(id, idx.id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["b","a"], idx.fields);
      assertEqual(true, idx.isNewlyCreated);

    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test: find documents
////////////////////////////////////////////////////////////////////////////////

    testUniqueDocuments : function () {
      var idx = collection.ensureSkiplist("a");

      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a"].sort(), idx.fields.sort());
      assertEqual(true, idx.isNewlyCreated);

      var d1;
      var d2;
      var documents = [];
      var values = [];

      d2 = {};
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : null };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : false };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : true };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : 1 };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : 2 };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : 3 };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : "a" };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : "b" };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : "c" };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ 0 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ 1 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ 2 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ "a" ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ "a", 1 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ "b" ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { a : 1 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : 1 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : 2 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : 3 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : [ 4 ] } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : [ 4, 5 ] } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      var i;
      var j;

      // GREATER THAN OR EQUAL
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect = documents.slice(i);

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, ">=", expect], [i, ">=", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }).toArray();
            fail();
          }
          catch (err1) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err1.errorNum);
          }
        }
      }

      // GREATER THAN
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect = documents.slice(i + 1);

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [[">", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, ">", expect], [i, ">", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [[">", val]] }).toArray();
            fail();
          }
          catch (err2) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err2.errorNum);
          }
        }
      }

      // LESS THAN OR EQUAL
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect = documents.slice(1, i + 1);

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, "<=", expect], [i, "<=", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }).toArray();
            fail();
          }
          catch (err3) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err3.errorNum);
          }
        }
      }

      // LESS THAN
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect = documents.slice(1, i);

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [["<", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, "<", expect], [i, "<", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [["<", val]] }).toArray();
            fail();
          }
          catch (err4) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err4.errorNum);
          }
        }
      }

      // BETWEEN
      for (i = 1;  i < documents.length;  ++i) {
        var vali = values[i].a;

        for (j = 1;  j < documents.length;  ++j) {
          var valj = values[j].a;
          var expect = documents.slice(i, j + 1);

          var isValid = ! ((vali !== null && typeof vali === 'object'));
          if (isValid) {
            isValid &= ! ((valj !== null && typeof valj === 'object'));
          }

          if (isValid) {
            var res = collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }).toArray();
            var result = res.map(function(a) { return a._key; });

            assertEqual([i, ">= <=", expect], [i, ">= <=", result]);
          }
          else {
            try {
              collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }).toArray();
              fail();
            }
            catch (err5) {
              assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err5.errorNum);
            }
          }
        }
      }
    }

  };
}

// -----------------------------------------------------------------------------
// --SECTION--                                                              main
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////

jsunity.run(SkipListSuite);

return jsunity.done();

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}"
// End:
<commit_msg>Adjust test to new non-sparse skiplists.<commit_after>/*jslint indent: 2, nomen: true, maxlen: 80 */
/*global require, db, assertEqual, assertTrue, ArangoCollection */

////////////////////////////////////////////////////////////////////////////////
/// @brief test the skip-list index
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var jsunity = require("jsunity");
var internal = require("internal");
var errors = internal.errors;

// -----------------------------------------------------------------------------
// --SECTION--                                                     basic methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: Creation
////////////////////////////////////////////////////////////////////////////////

function SkipListSuite() {
  var cn = "UnitTestsCollectionSkiplist";
  var collection = null;

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

  setUp : function () {
    internal.db._drop(cn);
    collection = internal.db._create(cn, { waitForSync : false });
  },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

  tearDown : function () {
    // try...catch is necessary as some tests delete the collection itself!
    try {
      collection.unload();
      collection.drop();
    }
    catch (err) {
    }

    collection = null;
    internal.wait(0.0);
  },

////////////////////////////////////////////////////////////////////////////////
/// @brief test: hash index creation
////////////////////////////////////////////////////////////////////////////////

    testCreationUniqueConstraint : function () {
      var idx = collection.ensureSkiplist("a");
      var id = idx.id;

      assertNotEqual(0, id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a"], idx.fields);
      assertEqual(true, idx.isNewlyCreated);

      idx = collection.ensureSkiplist("a");

      assertEqual(id, idx.id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a"], idx.fields);
      assertEqual(false, idx.isNewlyCreated);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test: permuted attributes
////////////////////////////////////////////////////////////////////////////////

    testCreationPermutedSkiplist : function () {
      var idx = collection.ensureSkiplist("a", "b");
      var id = idx.id;

      assertNotEqual(0, id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a","b"], idx.fields);
      assertEqual(true, idx.isNewlyCreated);

      idx = collection.ensureSkiplist("b", "a");

      assertNotEqual(id, idx.id);
      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["b","a"], idx.fields);
      assertEqual(true, idx.isNewlyCreated);

    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test: find documents
////////////////////////////////////////////////////////////////////////////////

    testUniqueDocuments : function () {
      var idx = collection.ensureSkiplist("a");

      assertEqual("skiplist", idx.type);
      assertEqual(false, idx.unique);
      assertEqual(["a"].sort(), idx.fields.sort());
      assertEqual(true, idx.isNewlyCreated);

      var d1;
      var d2;
      var documents = [];
      var values = [];

      d2 = {};
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : null };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : false };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : true };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : 1 };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : 2 };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : 3 };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : "a" };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : "b" };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : "c" };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ 0 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ 1 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ 2 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ "a" ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ "a", 1 ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : [ "b" ] };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { a : 1 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : 1 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : 2 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : 3 } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : [ 4 ] } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      d2 = { a : { b : [ 4, 5 ] } };
      d1 = collection.save(d2);
      documents.push(d1._key);
      values.push(d2);

      var i;
      var j;

      // GREATER THAN OR EQUAL
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;

        var expect;
        if (i === 1) {
          // In the first case the document 0 (which is {}) is
          // returned as well, since the skiplist automatically takes
          // null as value of an unset attribute:
          expect = documents.slice(0);
        }
        else {
          expect = documents.slice(i);
        }

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, ">=", expect], [i, ">=", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [[">=", val]] }).toArray();
            fail();
          }
          catch (err1) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err1.errorNum);
          }
        }
      }

      // GREATER THAN
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect = documents.slice(i + 1);

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [[">", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, ">", expect], [i, ">", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [[">", val]] }).toArray();
            fail();
          }
          catch (err2) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err2.errorNum);
          }
        }
      }

      // LESS THAN OR EQUAL
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect = documents.slice(0, i + 1);

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, "<=", expect], [i, "<=", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [["<=", val]] }).toArray();
            fail();
          }
          catch (err3) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err3.errorNum);
          }
        }
      }

      // LESS THAN
      for (i = 1;  i < documents.length;  ++i) {
        var val = values[i].a;
        var expect;
        if (i === 1) {
          expect = [];
        }
        else {
          expect = documents.slice(0, i);
        }

        var isValid = ! ((val !== null && typeof val === 'object'));
        if (isValid) {
          var res = collection.byConditionSkiplist(idx.id, { a: [["<", val]] }).toArray();
          var result = res.map(function(a) { return a._key; });

          assertEqual([i, "<", expect], [i, "<", result]);
        }
        else {
          try {
            collection.byConditionSkiplist(idx.id, { a: [["<", val]] }).toArray();
            fail();
          }
          catch (err4) {
            assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err4.errorNum);
          }
        }
      }

      // BETWEEN
      for (i = 1;  i < documents.length;  ++i) {
        var vali = values[i].a;

        for (j = 1;  j < documents.length;  ++j) {
          var valj = values[j].a;
          var expect;
          if (i === 1) {
            expect = documents.slice(0, j + 1);
          }
          else {
            expect = documents.slice(i, j + 1);
          }

          var isValid = ! ((vali !== null && typeof vali === 'object'));
          if (isValid) {
            isValid &= ! ((valj !== null && typeof valj === 'object'));
          }

          if (isValid) {
            var res = collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }).toArray();
            var result = res.map(function(a) { return a._key; });

            assertEqual([i, j, ">= <=", expect], [i, j, ">= <=", result]);
          }
          else {
            try {
              collection.byConditionSkiplist(idx.id, { a: [[">=", vali], ["<=", valj]] }).toArray();
              fail();
            }
            catch (err5) {
              assertEqual(errors.ERROR_ARANGO_NO_INDEX.code, err5.errorNum);
            }
          }
        }
      }
    }

  };
}

// -----------------------------------------------------------------------------
// --SECTION--                                                              main
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////

jsunity.run(SkipListSuite);

return jsunity.done();

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}"
// End:
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2017 Elton.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
window.addEventListener('load', init);

function init() {
    configurarForm();
}

function configurarForm() {
    var cpf = document.querySelector("#cpf");
    var celular = document.querySelector("#celular");
    var telefone = document.querySelector("#telefone");
    var cep = document.querySelector("#cep");

    if (cpf !== null) {
        cpf.value = formatarCpf(cpf.value);
    }

    if (celular !== null) {
        celular.value = formatarTelefone(celular.value);
    }

    if (telefone !== null) {
        telefone.value = formatarTelefone(telefone.value);
    }

    if (cep !== null) {
        cep.value = formatarCep(cep.value);
    }
}

function formatarCpf(value) {
    var pattern = /^([\d]{3})([\d]{3})([\d]{3})([\d]{2})$/;
    value = value.replace(/[^\d]+/g, '');
    value = value.replace(pattern, '$1.$2.$3-$4');

    return value;
}

function formatarTelefone(value) {
    var pattern = /^([\d]{2})([\d]{4,5})([\d]{4})$/;
    value = value.replace(/[^\d]+/g, '');
    value = value.replace(pattern, '($1) $2-$3');

    return value;
}

function formatarCep(value) {
    var pattern = /^([\d]{5})([\d]{3})$/;
    value = value.replace(/[^\d]+/g, '');
    value = value.replace(pattern, '$1-$2');

    return value;
}
<commit_msg>Refatorado o arquivo programa.js para formatar os campos necessários.<commit_after>/*
 * The MIT License
 *
 * Copyright 2017 Elton.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
window.addEventListener('load', init);

function init() {
    configurarForm();
}

function configurarForm() {
    var cpf = document.querySelector("#cpf");
    var celular = document.querySelector("#celular");
    var telefone = document.querySelector("#telefone");
    var cep = document.querySelector("#cep");

    if (cpf !== null) {
        cpf.value = formatarCpf(cpf.value);
        cpf.addEventListener('focusout', function () {
            this.value = formatarCpf(this.value);
        });
    }

    if (celular !== null) {
        celular.value = formatarTelefone(celular.value);
        celular.addEventListener('focusout', function () {
           this.value = formatarTelefone(this.value);
        });
    }

    if (telefone !== null) {
        telefone.value = formatarTelefone(telefone.value);
        celular.addEventListener('focusout', function () {
           this.value = formatarTelefone(this.value);
        });
    }

    if (cep !== null) {
        cep.value = formatarCep(cep.value);
        celular.addEventListener('focusout', function () {
           this.value = formatarTelefone(this.value);
        });
    }
}

function formatarCpf(value) {
    var pattern = /^([\d]{3})([\d]{3})([\d]{3})([\d]{2})$/;
    value = value.replace(/[^\d]+/g, '');
    value = value.replace(pattern, '$1.$2.$3-$4');

    return value;
}

function formatarTelefone(value) {
    var pattern = /^([\d]{2})([\d]{4,5})([\d]{4})$/;
    value = value.replace(/[^\d]+/g, '');
    value = value.replace(pattern, '($1) $2-$3');

    return value;
}

function formatarCep(value) {
    var pattern = /^([\d]{5})([\d]{3})$/;
    value = value.replace(/[^\d]+/g, '');
    value = value.replace(pattern, '$1-$2');

    return value;
}
<|endoftext|>


<commit_before>// Load modules

var Nipple = require('nipple');
var Hapi = require('../lib');

// Declare internals

var internals = {};

internals.main = function () {

    var server = new Hapi.Server(8000);

    var mapper = function (request, callback) {

        callback(null, 'http://www.google.com/search?q=' + request.params.term);
    };

    server.route({ method: '*', path: '/{p*}', handler: { proxy: { host: 'google.com', port: 80, redirects: 5 } } });
    server.route({ method: 'GET', path: '/hapi/{term}', handler: { proxy: { mapUri: mapper } } });
    server.start();
};

internals.main();
<commit_msg>Remove unused dependency in proxy example.<commit_after>// Load modules

var Hapi = require('../lib');

// Declare internals

var internals = {};

internals.main = function () {

    var server = new Hapi.Server(8000);

    var mapper = function (request, callback) {

        callback(null, 'http://www.google.com/search?q=' + request.params.term);
    };

    server.route({ method: '*', path: '/{p*}', handler: { proxy: { host: 'google.com', port: 80, redirects: 5 } } });
    server.route({ method: 'GET', path: '/hapi/{term}', handler: { proxy: { mapUri: mapper } } });
    server.start();
};

internals.main();
<|endoftext|>


<commit_before>// Contains data for past work experience

import React from 'react';
import { Link } from 'react-router-dom';
import Company from './Company';
import urls from './urls';

const novaly = new Company('Novaly Studios', urls.novaly);
const roblox = new Company('Roblox Corporation', urls.roblox);
// const bitsquid = new Company('Bitsquid Games', urls.bitsquid);

const experiences = [
	{
		job: 'Software Engineering Intern',
		company: roblox,
		description: 'Working remotely amindst the COVID-19 pandemic for 10 weeks to improve the Roblox platform.',
		wasInHouse: true,
		startDate: new Date(2020, 5),
		// endDate: new Date(2020, 7),
	},

	// {
	// 	job: 'Frontend Programmer',
	// 	company: bitsquid,
	// 	description: 'All-purpose programmer primarily writing React style code for frontend UI.',
	// 	wasInHouse: false,
	// 	startDate: new Date(2020, 0),
	// },

	{
		job: 'Level Designer',
		company: novaly,
		description: 'Currently crafting an immersive city and world for a new hit social racing game.',
		wasInHouse: false,
		startDate: new Date(2017, 5),
		endDate: new Date(2020, 1),
	},

	{
		job: 'Software Engineering Intern',
		company: roblox,
		description: '10 weeks of working in house at Roblox HQ on the application layer of the platform. Removed bloat, helped set best practices, and worked with full-time employees to make their existing workflows better.',
		wasInHouse: true,
		startDate: new Date(2019, 5),
		endDate: new Date(2019, 7),
	},

	{
		job: 'Programmer',
		company: novaly,
		description: Squashed bugs and created the Robbery feature for Bandit Simulator, introducing a brand new way to play the game.,
		wasInHouse: false,
		startDate: new Date(2018, 10),
		endDate: new Date(2019, 0),
	},

	{
		job: 'Level Design contractor',
		company: roblox,
		description: Worked for Roblox to create <Link to='/projects/aquaman'>Aquaman: City of Rolantis</Link> for a Warner Bros. sponsorship.,
		wasInHouse: false,
		startDate: new Date(2018, 6),
		endDate: new Date(2018, 10),
	},

	{
		job: 'Accelerator Intern',
		company: roblox,
		description: '3 month sprint to create a game working in house at Roblox HQ.',
		wasInHouse: true,
		startDate: new Date(2018, 5),
		endDate: new Date(2018, 7),
	},
];

export default experiences;
<commit_msg>See you next year :)<commit_after>// Contains data for past work experience

import React from 'react';
import { Link } from 'react-router-dom';
import Company from './Company';
import urls from './urls';

const novaly = new Company('Novaly Studios', urls.novaly);
const roblox = new Company('Roblox Corporation', urls.roblox);
// const bitsquid = new Company('Bitsquid Games', urls.bitsquid);

const experiences = [
	{
		job: 'Software Engineering Intern',
		company: roblox,
		description: 'Working remotely amindst the COVID-19 pandemic for 10 weeks to improve the Roblox platform.',
		wasInHouse: true,
		startDate: new Date(2020, 5),
		endDate: new Date(2020, 7),
	},

	// {
	// 	job: 'Frontend Programmer',
	// 	company: bitsquid,
	// 	description: 'All-purpose programmer primarily writing React style code for frontend UI.',
	// 	wasInHouse: false,
	// 	startDate: new Date(2020, 0),
	// },

	{
		job: 'Level Designer',
		company: novaly,
		description: 'Currently crafting an immersive city and world for a new hit social racing game.',
		wasInHouse: false,
		startDate: new Date(2017, 5),
		endDate: new Date(2020, 1),
	},

	{
		job: 'Software Engineering Intern',
		company: roblox,
		description: '10 weeks of working in house at Roblox HQ on the application layer of the platform. Removed bloat, helped set best practices, and worked with full-time employees to make their existing workflows better.',
		wasInHouse: true,
		startDate: new Date(2019, 5),
		endDate: new Date(2019, 7),
	},

	{
		job: 'Programmer',
		company: novaly,
		description: Squashed bugs and created the Robbery feature for Bandit Simulator, introducing a brand new way to play the game.,
		wasInHouse: false,
		startDate: new Date(2018, 10),
		endDate: new Date(2019, 0),
	},

	{
		job: 'Level Design contractor',
		company: roblox,
		description: Worked for Roblox to create <Link to='/projects/aquaman'>Aquaman: City of Rolantis</Link> for a Warner Bros. sponsorship.,
		wasInHouse: false,
		startDate: new Date(2018, 6),
		endDate: new Date(2018, 10),
	},

	{
		job: 'Accelerator Intern',
		company: roblox,
		description: '3 month sprint to create a game working in house at Roblox HQ.',
		wasInHouse: true,
		startDate: new Date(2018, 5),
		endDate: new Date(2018, 7),
	},
];

export default experiences;
<|endoftext|>