<commit_before>/**
 * Overview component for SearchFunnelWidget.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useContext, Fragment } from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { Grid, Row, Cell } from '../../../../../material-components';
import {
	VIEW_CONTEXT_DASHBOARD,
	VIEW_CONTEXT_PAGE_DASHBOARD,
} from '../../../../../googlesitekit/constants';
import { extractSearchConsoleDashboardData } from '../../../util';
import { calculateChange } from '../../../../../util';
import { CORE_MODULES } from '../../../../../googlesitekit/modules/datastore/constants';
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { MODULES_ANALYTICS } from '../../../../analytics/datastore/constants';
import { CORE_LOCATION } from '../../../../../googlesitekit/datastore/location/constants';
import { MODULES_SEARCH_CONSOLE } from '../../../datastore/constants';
import { useFeature } from '../../../../../hooks/useFeature';
import CompleteModuleActivationCTA from '../../../../../components/CompleteModuleActivationCTA';
import ActivateModuleCTA from '../../../../../components/ActivateModuleCTA';
import CTA from '../../../../../components/notifications/CTA';
import ViewContextContext from '../../../../../components/Root/ViewContextContext';
import DataBlock from '../../../../../components/DataBlock';
import ProgressBar from '../../../../../components/ProgressBar';
import ReportZero from '../../../../../components/ReportZero';
const { useSelect, useInViewSelect } = Data;

function getDatapointAndChange( [ report ], selectedStat, divider = 1 ) {
	return {
		datapoint:
			report?.data?.totals?.[ 0 ]?.values?.[ selectedStat ] / divider,
		change: calculateChange(
			report?.data?.totals?.[ 1 ]?.values?.[ selectedStat ],
			report?.data?.totals?.[ 0 ]?.values?.[ selectedStat ]
		),
	};
}

const Overview = ( {
	analyticsData,
	analyticsGoalsData,
	analyticsVisitorsData,
	searchConsoleData,
	selectedStats,
	handleStatsSelection,
	dateRangeLength,
	error,
	WidgetReportError,
} ) => {
	const viewContext = useContext( ViewContextContext );
	const zeroDataStatesEnabled = useFeature( 'zeroDataStates' );

	const analyticsModuleConnected = useSelect( ( select ) =>
		select( CORE_MODULES ).isModuleConnected( 'analytics' )
	);
	const analyticsModuleActive = useSelect( ( select ) =>
		select( CORE_MODULES ).isModuleActive( 'analytics' )
	);
	const analyticsModuleActiveAndConnected =
		analyticsModuleActive && analyticsModuleConnected;

	const adminReauthURL = useSelect( ( select ) =>
		select( MODULES_ANALYTICS ).getAdminReauthURL()
	);
	const isNavigatingToReauthURL = useSelect( ( select ) =>
		select( CORE_LOCATION ).isNavigatingTo( adminReauthURL )
	);
	const isAnalyticsGatheringData = useInViewSelect( ( select ) =>
		analyticsModuleActiveAndConnected
			? select( MODULES_ANALYTICS ).isGatheringData()
			: false
	);
	const isSearchConsoleGatheringData = useInViewSelect( ( select ) =>
		select( MODULES_SEARCH_CONSOLE ).isGatheringData()
	);

	const {
		totalClicks,
		totalImpressions,
		totalClicksChange,
		totalImpressionsChange,
	} = extractSearchConsoleDashboardData( searchConsoleData, dateRangeLength );

	let analyticsGoalsChange = null;
	let analyticsGoalsDatapoint = null;
	let analyticsBounceDatapoint = null;
	let analyticsBounceChange = null;
	let analyticsVisitorsDatapoint = null;
	let analyticsVisitorsChange = null;

	if (
		analyticsModuleActive &&
		Array.isArray( analyticsData ) &&
		Array.isArray( analyticsVisitorsData )
	) {
		( { change: analyticsGoalsChange } = getDatapointAndChange(
			analyticsData,
			0,
			100
		) );
		analyticsGoalsDatapoint =
			analyticsData?.[ 0 ]?.data?.totals?.[ 0 ]?.values[ 0 ];

		( {
			datapoint: analyticsBounceDatapoint,
			change: analyticsBounceChange,
		} = getDatapointAndChange( analyticsData, 1, 100 ) );

		analyticsVisitorsDatapoint =
			analyticsVisitorsData?.[ 0 ]?.data?.totals?.[ 0 ]?.values[ 0 ];
		( { change: analyticsVisitorsChange } = getDatapointAndChange(
			analyticsVisitorsData,
			0,
			100
		) );
	}

	const quarterCellProps = {
		smSize: 2,
		mdSize: 2,
		lgSize: 3,
	};

	const halfCellProps = {
		smSize: 4,
		mdSize: 4,
		lgSize: 6,
	};

	const supportURL = useSelect( ( select ) =>
		select( CORE_SITE ).getGoogleSupportURL( {
			path: '/analytics/answer/1032415',
			hash: 'create_or_edit_goals',
		} )
	);

	return (
		<Grid>
			<Row>
				<Cell { ...quarterCellProps }>
					<DataBlock
						stat={ 0 }
						className="googlesitekit-data-block--impressions googlesitekit-data-block--button-1"
						title={ __( 'Total Impressions', 'google-site-kit' ) }
						datapoint={ totalImpressions }
						change={ totalImpressionsChange }
						changeDataUnit="%"
						context="button"
						selected={ selectedStats === 0 }
						handleStatSelection={ handleStatsSelection }
						gatheringData={ isSearchConsoleGatheringData }
					/>
				</Cell>

				<Cell { ...quarterCellProps }>
					<DataBlock
						stat={ 1 }
						className="googlesitekit-data-block--clicks googlesitekit-data-block--button-2"
						title={ __( 'Total Clicks', 'google-site-kit' ) }
						datapoint={ totalClicks }
						change={ totalClicksChange }
						changeDataUnit="%"
						context="button"
						selected={ selectedStats === 1 }
						handleStatSelection={ handleStatsSelection }
						gatheringData={ isSearchConsoleGatheringData }
					/>
				</Cell>

				{ isNavigatingToReauthURL && (
					<Cell
						{ ...halfCellProps }
						className="googlesitekit-data-block__loading"
					>
						<ProgressBar />
					</Cell>
				) }

				{ ( ! analyticsModuleConnected || ! analyticsModuleActive ) &&
					! isNavigatingToReauthURL && (
						<Cell { ...halfCellProps }>
							{ ! analyticsModuleActive && (
								<ActivateModuleCTA moduleSlug="analytics" />
							) }

							{ analyticsModuleActive &&
								! analyticsModuleConnected && (
									<CompleteModuleActivationCTA moduleSlug="analytics" />
								) }
						</Cell>
					) }

				{ analyticsModuleActiveAndConnected && error && (
					<Cell { ...halfCellProps }>
						<WidgetReportError
							moduleSlug="analytics"
							error={ error }
						/>
					</Cell>
				) }

				{ isAnalyticsGatheringData &&
					! error &&
					! zeroDataStatesEnabled && (
						<Cell { ...halfCellProps }>
							{ /* We need to use ReportZero rather than WidgetReportZero to not associate a zero state for the whole widget. */ }
							<ReportZero moduleSlug="analytics" />
						</Cell>
					) }

				{ ( ( analyticsModuleConnected &&
					! isAnalyticsGatheringData &&
					! zeroDataStatesEnabled &&
					! error ) ||
					( analyticsModuleConnected &&
						zeroDataStatesEnabled &&
						! error ) ) && (
					<Fragment>
						<Cell { ...quarterCellProps }>
							<DataBlock
								stat={ 2 }
								className="googlesitekit-data-block--visitors googlesitekit-data-block--button-3"
								title={ __(
									'Unique Visitors from Search',
									'google-site-kit'
								) }
								datapoint={ analyticsVisitorsDatapoint }
								change={ analyticsVisitorsChange }
								changeDataUnit="%"
								context="button"
								selected={ selectedStats === 2 }
								handleStatSelection={ handleStatsSelection }
								gatheringData={ isAnalyticsGatheringData }
							/>
						</Cell>

						<Cell { ...quarterCellProps }>
							{ viewContext === VIEW_CONTEXT_DASHBOARD &&
								! analyticsGoalsData?.items?.length && (
									<CTA
										title={ __(
											'Use goals to measure success',
											'google-site-kit'
										) }
										description={ __(
											'Goals measure how well your site or app fulfills your target objectives',
											'google-site-kit'
										) }
										ctaLink={ supportURL }
										ctaLabel={ __(
											'Create a new goal',
											'google-site-kit'
										) }
										ctaLinkExternal
									/>
								) }
							{ viewContext === VIEW_CONTEXT_DASHBOARD &&
								analyticsGoalsData?.items?.length > 0 && (
									<DataBlock
										stat={ 3 }
										className="googlesitekit-data-block--goals googlesitekit-data-block--button-4"
										title={ __(
											'Goals',
											'google-site-kit'
										) }
										datapoint={ analyticsGoalsDatapoint }
										change={ analyticsGoalsChange }
										changeDataUnit="%"
										context="button"
										selected={ selectedStats === 3 }
										handleStatSelection={
											handleStatsSelection
										}
										gatheringData={
											isAnalyticsGatheringData
										}
									/>
								) }

							{ viewContext === VIEW_CONTEXT_PAGE_DASHBOARD && (
								<DataBlock
									stat={ 4 }
									className="googlesitekit-data-block--bounce googlesitekit-data-block--button-4"
									title={ __(
										'Bounce Rate',
										'google-site-kit'
									) }
									datapoint={ analyticsBounceDatapoint }
									datapointUnit="%"
									change={ analyticsBounceChange }
									changeDataUnit="%"
									context="button"
									selected={ selectedStats === 4 }
									handleStatSelection={ handleStatsSelection }
									gatheringData={ isAnalyticsGatheringData }
									invertChangeColor
								/>
							) }
						</Cell>
					</Fragment>
				) }
			</Row>
		</Grid>
	);
};

Overview.propTypes = {
	analyticsData: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.object ),
		PropTypes.object,
	] ),
	analyticsGoalsData: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.object ),
		PropTypes.object,
	] ),
	analyticsVisitorsData: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.object ),
		PropTypes.object,
	] ),
	searchConsoleData: PropTypes.arrayOf( PropTypes.object ),
	selectedStats: PropTypes.number.isRequired,
	handleStatsSelection: PropTypes.func.isRequired,
	error: PropTypes.object,
	WidgetReportError: PropTypes.elementType.isRequired,
};

export default Overview;
<commit_msg>Use new Analytics CTA components in Search Funnel.<commit_after>/**
 * Overview component for SearchFunnelWidget.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useContext, Fragment } from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { Grid, Row, Cell } from '../../../../../material-components';
import {
	VIEW_CONTEXT_DASHBOARD,
	VIEW_CONTEXT_PAGE_DASHBOARD,
} from '../../../../../googlesitekit/constants';
import { extractSearchConsoleDashboardData } from '../../../util';
import { calculateChange } from '../../../../../util';
import { CORE_MODULES } from '../../../../../googlesitekit/modules/datastore/constants';
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { MODULES_ANALYTICS } from '../../../../analytics/datastore/constants';
import { CORE_LOCATION } from '../../../../../googlesitekit/datastore/location/constants';
import { MODULES_SEARCH_CONSOLE } from '../../../datastore/constants';
import { useFeature } from '../../../../../hooks/useFeature';
import CompleteModuleActivationCTA from '../../../../../components/CompleteModuleActivationCTA';
import ActivateModuleCTA from '../../../../../components/ActivateModuleCTA';
import ActivateAnalyticsCTA from './ActivateAnalyticsCTA';
import CreateGoalCTA from './CreateGoalCTA';
import CTA from '../../../../../components/notifications/CTA';
import ViewContextContext from '../../../../../components/Root/ViewContextContext';
import DataBlock from '../../../../../components/DataBlock';
import ProgressBar from '../../../../../components/ProgressBar';
import ReportZero from '../../../../../components/ReportZero';
const { useSelect, useInViewSelect } = Data;

function getDatapointAndChange( [ report ], selectedStat, divider = 1 ) {
	return {
		datapoint:
			report?.data?.totals?.[ 0 ]?.values?.[ selectedStat ] / divider,
		change: calculateChange(
			report?.data?.totals?.[ 1 ]?.values?.[ selectedStat ],
			report?.data?.totals?.[ 0 ]?.values?.[ selectedStat ]
		),
	};
}

const Overview = ( {
	analyticsData,
	analyticsGoalsData,
	analyticsVisitorsData,
	searchConsoleData,
	selectedStats,
	handleStatsSelection,
	dateRangeLength,
	error,
	WidgetReportError,
} ) => {
	const viewContext = useContext( ViewContextContext );
	const zeroDataStatesEnabled = useFeature( 'zeroDataStates' );

	const analyticsModuleConnected = useSelect( ( select ) =>
		select( CORE_MODULES ).isModuleConnected( 'analytics' )
	);
	const analyticsModuleActive = useSelect( ( select ) =>
		select( CORE_MODULES ).isModuleActive( 'analytics' )
	);
	const analyticsModuleActiveAndConnected =
		analyticsModuleActive && analyticsModuleConnected;

	const adminReauthURL = useSelect( ( select ) =>
		select( MODULES_ANALYTICS ).getAdminReauthURL()
	);
	const isNavigatingToReauthURL = useSelect( ( select ) =>
		select( CORE_LOCATION ).isNavigatingTo( adminReauthURL )
	);
	const isAnalyticsGatheringData = useInViewSelect( ( select ) =>
		analyticsModuleActiveAndConnected
			? select( MODULES_ANALYTICS ).isGatheringData()
			: false
	);
	const isSearchConsoleGatheringData = useInViewSelect( ( select ) =>
		select( MODULES_SEARCH_CONSOLE ).isGatheringData()
	);

	const {
		totalClicks,
		totalImpressions,
		totalClicksChange,
		totalImpressionsChange,
	} = extractSearchConsoleDashboardData( searchConsoleData, dateRangeLength );

	let analyticsGoalsChange = null;
	let analyticsGoalsDatapoint = null;
	let analyticsBounceDatapoint = null;
	let analyticsBounceChange = null;
	let analyticsVisitorsDatapoint = null;
	let analyticsVisitorsChange = null;

	if (
		analyticsModuleActive &&
		Array.isArray( analyticsData ) &&
		Array.isArray( analyticsVisitorsData )
	) {
		( { change: analyticsGoalsChange } = getDatapointAndChange(
			analyticsData,
			0,
			100
		) );
		analyticsGoalsDatapoint =
			analyticsData?.[ 0 ]?.data?.totals?.[ 0 ]?.values[ 0 ];

		( {
			datapoint: analyticsBounceDatapoint,
			change: analyticsBounceChange,
		} = getDatapointAndChange( analyticsData, 1, 100 ) );

		analyticsVisitorsDatapoint =
			analyticsVisitorsData?.[ 0 ]?.data?.totals?.[ 0 ]?.values[ 0 ];
		( { change: analyticsVisitorsChange } = getDatapointAndChange(
			analyticsVisitorsData,
			0,
			100
		) );
	}

	const quarterCellProps = {
		smSize: 2,
		mdSize: 2,
		lgSize: 3,
	};

	const halfCellProps = {
		smSize: 4,
		mdSize: 4,
		lgSize: 6,
	};

	const supportURL = useSelect( ( select ) =>
		select( CORE_SITE ).getGoogleSupportURL( {
			path: '/analytics/answer/1032415',
			hash: 'create_or_edit_goals',
		} )
	);

	return (
		<Grid>
			<Row>
				<Cell { ...quarterCellProps }>
					<DataBlock
						stat={ 0 }
						className="googlesitekit-data-block--impressions googlesitekit-data-block--button-1"
						title={ __( 'Total Impressions', 'google-site-kit' ) }
						datapoint={ totalImpressions }
						change={ totalImpressionsChange }
						changeDataUnit="%"
						context="button"
						selected={ selectedStats === 0 }
						handleStatSelection={ handleStatsSelection }
						gatheringData={ isSearchConsoleGatheringData }
					/>
				</Cell>

				<Cell { ...quarterCellProps }>
					<DataBlock
						stat={ 1 }
						className="googlesitekit-data-block--clicks googlesitekit-data-block--button-2"
						title={ __( 'Total Clicks', 'google-site-kit' ) }
						datapoint={ totalClicks }
						change={ totalClicksChange }
						changeDataUnit="%"
						context="button"
						selected={ selectedStats === 1 }
						handleStatSelection={ handleStatsSelection }
						gatheringData={ isSearchConsoleGatheringData }
					/>
				</Cell>

				{ isNavigatingToReauthURL && (
					<Cell
						{ ...halfCellProps }
						className="googlesitekit-data-block__loading"
					>
						<ProgressBar />
					</Cell>
				) }

				{ ( ! analyticsModuleConnected || ! analyticsModuleActive ) &&
					! isNavigatingToReauthURL && (
						<Cell { ...halfCellProps }>
							{ ! analyticsModuleActive &&
								( zeroDataStatesEnabled ? (
									<ActivateAnalyticsCTA />
								) : (
									<ActivateModuleCTA moduleSlug="analytics" />
								) ) }

							{ analyticsModuleActive &&
								! analyticsModuleConnected && (
									<CompleteModuleActivationCTA moduleSlug="analytics" />
								) }
						</Cell>
					) }

				{ analyticsModuleActiveAndConnected && error && (
					<Cell { ...halfCellProps }>
						<WidgetReportError
							moduleSlug="analytics"
							error={ error }
						/>
					</Cell>
				) }

				{ isAnalyticsGatheringData &&
					! error &&
					! zeroDataStatesEnabled && (
						<Cell { ...halfCellProps }>
							{ /* We need to use ReportZero rather than WidgetReportZero to not associate a zero state for the whole widget. */ }
							<ReportZero moduleSlug="analytics" />
						</Cell>
					) }

				{ ( ( analyticsModuleConnected &&
					! isAnalyticsGatheringData &&
					! zeroDataStatesEnabled &&
					! error ) ||
					( analyticsModuleConnected &&
						zeroDataStatesEnabled &&
						! error ) ) && (
					<Fragment>
						<Cell { ...quarterCellProps }>
							<DataBlock
								stat={ 2 }
								className="googlesitekit-data-block--visitors googlesitekit-data-block--button-3"
								title={ __(
									'Unique Visitors from Search',
									'google-site-kit'
								) }
								datapoint={ analyticsVisitorsDatapoint }
								change={ analyticsVisitorsChange }
								changeDataUnit="%"
								context="button"
								selected={ selectedStats === 2 }
								handleStatSelection={ handleStatsSelection }
								gatheringData={ isAnalyticsGatheringData }
							/>
						</Cell>

						<Cell { ...quarterCellProps }>
							{ viewContext === VIEW_CONTEXT_DASHBOARD &&
							! analyticsGoalsData?.items?.length &&
							zeroDataStatesEnabled ? (
								<CreateGoalCTA />
							) : (
								<CTA
									title={ __(
										'Use goals to measure success',
										'google-site-kit'
									) }
									description={ __(
										'Goals measure how well your site or app fulfills your target objectives',
										'google-site-kit'
									) }
									ctaLink={ supportURL }
									ctaLabel={ __(
										'Create a new goal',
										'google-site-kit'
									) }
									ctaLinkExternal
								/>
							) }
							{ viewContext === VIEW_CONTEXT_DASHBOARD &&
								analyticsGoalsData?.items?.length > 0 && (
									<DataBlock
										stat={ 3 }
										className="googlesitekit-data-block--goals googlesitekit-data-block--button-4"
										title={ __(
											'Goals',
											'google-site-kit'
										) }
										datapoint={ analyticsGoalsDatapoint }
										change={ analyticsGoalsChange }
										changeDataUnit="%"
										context="button"
										selected={ selectedStats === 3 }
										handleStatSelection={
											handleStatsSelection
										}
										gatheringData={
											isAnalyticsGatheringData
										}
									/>
								) }

							{ viewContext === VIEW_CONTEXT_PAGE_DASHBOARD && (
								<DataBlock
									stat={ 4 }
									className="googlesitekit-data-block--bounce googlesitekit-data-block--button-4"
									title={ __(
										'Bounce Rate',
										'google-site-kit'
									) }
									datapoint={ analyticsBounceDatapoint }
									datapointUnit="%"
									change={ analyticsBounceChange }
									changeDataUnit="%"
									context="button"
									selected={ selectedStats === 4 }
									handleStatSelection={ handleStatsSelection }
									gatheringData={ isAnalyticsGatheringData }
									invertChangeColor
								/>
							) }
						</Cell>
					</Fragment>
				) }
			</Row>
		</Grid>
	);
};

Overview.propTypes = {
	analyticsData: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.object ),
		PropTypes.object,
	] ),
	analyticsGoalsData: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.object ),
		PropTypes.object,
	] ),
	analyticsVisitorsData: PropTypes.oneOfType( [
		PropTypes.arrayOf( PropTypes.object ),
		PropTypes.object,
	] ),
	searchConsoleData: PropTypes.arrayOf( PropTypes.object ),
	selectedStats: PropTypes.number.isRequired,
	handleStatsSelection: PropTypes.func.isRequired,
	error: PropTypes.object,
	WidgetReportError: PropTypes.elementType.isRequired,
};

export default Overview;
<|endoftext|>


<commit_before>/*!
 * Module dependencies
 */

var Command = require('./util/command'),
    cordova = require('cordova-lib').cordova,
    project = require('./util/project'),
    platforms = require('./util/platform'),
    shell = require('shelljs'),
    util = require('util');

/*!
 * Command setup.
 */

module.exports = {
    create: function(phonegap) {
        return new LocalInstallCommand(phonegap);
    }
};

function LocalInstallCommand(phonegap) {
    return Command.apply(this, arguments);
}

util.inherits(LocalInstallCommand, Command);

/**
 * Install a Local App.
 *
 * Install an app from the local system.
 *
 * Options:
 *
 *   - `options` {Object}
 *     - `platforms` {Array} is a list of platforms (limited to 1).
 *     - [`device`] {Boolean} is true when only using device.
 *     - [`emulator`] {Boolean} is true when only using emulator.
 *     - [`target`] {String} way to pass device arguments to emulator
 *   - [`callback`] {Function} is triggered after completion.
 *     - `e` {Error} is null unless there is an error.
 *
 * Returns:
 *
 *   {PhoneGap} for chaining.
 */

LocalInstallCommand.prototype.run = function(options, callback) {
    // require options
    if (!options) throw new Error('requires option parameter');
    if (!options.platforms) throw new Error('requires option.platforms parameter');

    // optional callback
    callback = callback || function() {};

    // install app
    this.execute(options, callback);

    return this.phonegap;
};

/*!
 * Execute.
 */

LocalInstallCommand.prototype.execute = function(options, callback) {
    var self = this,
        installed,
        platform = platforms.names(options.platforms)[0];

    // change to project directory and delegate errors
    if (!project.cd({ emitter: self.phonegap, callback: callback })) return;

    // simplfy callback
    var _callback = function(e) {
        if (e) {
            self.phonegap.emit('error', e);
        }
        callback(e);
    };

    // check for existing platform installations
    installed = project.listPlatforms('.');
    if (installed.indexOf(options.platforms[0]) > -1) {
        cordova.platform('add', options.platforms, null, function(e){
            if (e) {
                this.phonegap.emit('error', e);
            } else {
               self.install(options, _callback);
            }
        });
    }

};

LocalInstallCommand.prototype.install = function (options, callback) {
    var self = this,
        platform = platforms.names(options.platforms)[0];

    // install app to device
    if (options.device) {
        self.phonegap.emit('log', 'installing app onto device');
        cordova.raw.run([ platform.local ], callback);
    }
    // instal app to emulator
    else if (options.emulator) {
        self.phonegap.emit('log', 'installing app onto emulator');
        cordovaEmulate(self, platform);
        emulate_opts = [ platform.local ];
        if (options.target)  {
            emulate_opts = {platforms: [ platform.local ],
                            options: "--target="+options.target};
        }
        cordova.raw.emulate(emulate_opts, callback);
    }
    // when no target is specified: try device and fallback on emulator
    else {
        self.phonegap.emit('log', 'trying to install app onto device');
        self.phonegap.cordova.raw.run([ platform.local ], function(e) {
            if (e) {
                self.phonegap.emit('log', 'no device was found');
                self.phonegap.emit('log', 'trying to install app onto emulator');
                cordovaEmulate(self, platform);
                emulate_opts = [ platform.local ];
                if (options.target)  {
                    emulate_opts = {platforms: [ platform.local ],
                                    options: "--target="+options.target};
                }
                self.phonegap.cordova.raw.emulate(emulate_opts, function(e) {
                    if (!e) {
                        self.phonegap.emit('log', 'successfully installed onto emulator');
                    }
                    callback(e);
                });
            }
            else {
                self.phonegap.emit('log', 'successfully installed onto device');
                callback(null);
            }
        });
    }

};

/**
 * Validate the emulate requirements.
 *
 * This can be removed when Xcode 5 replaces ios-sim.
 *
 * Options:
 *
 *   - `self` {Object} is `this` of the calling Command.
 *   - `platform` {Object} is the platform to check.
 */

function cordovaEmulate(self, platform) {
    // warn about missing ios-sim requirement
    if (platform.local === 'ios' && !shell.which('ios-sim')) {
        self.phonegap.emit('warn', 'missing ios-sim');
        self.phonegap.emit('warn', 'install ios-sim from',
                                   'http://github.com/phonegap/ios-sim');
    }
}
<commit_msg>[#437] fixed local install<commit_after>/*!
 * Module dependencies
 */

var Command = require('./util/command'),
    cordova = require('cordova-lib').cordova,
    project = require('./util/project'),
    platforms = require('./util/platform'),
    shell = require('shelljs'),
    util = require('util');

/*!
 * Command setup.
 */

module.exports = {
    create: function(phonegap) {
        return new LocalInstallCommand(phonegap);
    }
};

function LocalInstallCommand(phonegap) {
    return Command.apply(this, arguments);
}

util.inherits(LocalInstallCommand, Command);

/**
 * Install a Local App.
 *
 * Install an app from the local system.
 *
 * Options:
 *
 *   - `options` {Object}
 *     - `platforms` {Array} is a list of platforms (limited to 1).
 *     - [`device`] {Boolean} is true when only using device.
 *     - [`emulator`] {Boolean} is true when only using emulator.
 *     - [`target`] {String} way to pass device arguments to emulator
 *   - [`callback`] {Function} is triggered after completion.
 *     - `e` {Error} is null unless there is an error.
 *
 * Returns:
 *
 *   {PhoneGap} for chaining.
 */

LocalInstallCommand.prototype.run = function(options, callback) {
    // require options
    if (!options) throw new Error('requires option parameter');
    if (!options.platforms) throw new Error('requires option.platforms parameter');

    // optional callback
    callback = callback || function() {};

    // install app
    this.execute(options, callback);

    return this.phonegap;
};

/*!
 * Execute.
 */

LocalInstallCommand.prototype.execute = function(options, callback) {
    var self = this,
        installed,
        platform = platforms.names(options.platforms)[0];

    // change to project directory and delegate errors
    if (!project.cd({ emitter: self.phonegap, callback: callback })) return;

    // simplfy callback
    var _callback = function(e) {
        if (e) {
            self.phonegap.emit('error', e);
        }
        callback(e);
    };

    // check for existing platform installations
    installed = project.listPlatforms('.');
    if (installed.indexOf(options.platforms[0]) > -1) {
        cordova.platform('add', options.platforms, null, function(e){
            if (e && e.message.search('already added') === -1) {
                self.phonegap.emit('error', e);
            } else {
               self.install(options, _callback);
            }
        });
    }

};

LocalInstallCommand.prototype.install = function (options, callback) {
    var self = this,
        platform = platforms.names(options.platforms)[0];

    // install app to device
    if (options.device) {
        self.phonegap.emit('log', 'installing app onto device');
        cordova.raw.run([ platform.local ], callback);
    }
    // instal app to emulator
    else if (options.emulator) {
        self.phonegap.emit('log', 'installing app onto emulator');
        cordovaEmulate(self, platform);
        emulate_opts = [ platform.local ];
        if (options.target)  {
            emulate_opts = {platforms: [ platform.local ],
                            options: "--target="+options.target};
        }
        cordova.raw.emulate(emulate_opts, callback);
    }
    // when no target is specified: try device and fallback on emulator
    else {
        self.phonegap.emit('log', 'trying to install app onto device');
        self.phonegap.cordova.raw.run([ platform.local ], function(e) {
            if (e) {
                self.phonegap.emit('log', 'no device was found');
                self.phonegap.emit('log', 'trying to install app onto emulator');
                cordovaEmulate(self, platform);
                emulate_opts = [ platform.local ];
                if (options.target)  {
                    emulate_opts = {platforms: [ platform.local ],
                                    options: "--target="+options.target};
                }
                self.phonegap.cordova.raw.emulate(emulate_opts, function(e) {
                    if (!e) {
                        self.phonegap.emit('log', 'successfully installed onto emulator');
                    }
                    callback(e);
                });
            }
            else {
                self.phonegap.emit('log', 'successfully installed onto device');
                callback(null);
            }
        });
    }

};

/**
 * Validate the emulate requirements.
 *
 * This can be removed when Xcode 5 replaces ios-sim.
 *
 * Options:
 *
 *   - `self` {Object} is `this` of the calling Command.
 *   - `platform` {Object} is the platform to check.
 */

function cordovaEmulate(self, platform) {
    // warn about missing ios-sim requirement
    if (platform.local === 'ios' && !shell.which('ios-sim')) {
        self.phonegap.emit('warn', 'missing ios-sim');
        self.phonegap.emit('warn', 'install ios-sim from',
                                   'http://github.com/phonegap/ios-sim');
    }
}
<|endoftext|>


<commit_before>$(function() {
	var $prompt = $("#global-browser-prompt");

	// we don't show the message when the cookie warning is also there
	if($("#global-cookie-warning").length === 0){
		if ( suchi.isOld(navigator.userAgent) ) {
			if(getCookie('not_first_visit') !== null && getCookie('browser_upgrade_dismissed') === null){
				$prompt.show();
				$prompt.find(".dismiss").on("click", function(){
					$prompt.hide();
					// the warning is dismissable for 2 weeks
					setCookie('browser_upgrade_dismissed', 'yes', 14);
					return false;
				});
			};
		};

		// We're not showing the message on first visit
		setCookie('not_first_visit', 'yes', 28);
	};
});
<commit_msg>Updating cookie names<commit_after>$(function() {
	var $prompt = $("#global-browser-prompt");

	// we don't show the message when the cookie warning is also there
	if($("#global-cookie-warning").length === 0){
		if ( suchi.isOld(navigator.userAgent) ) {
			if(getCookie('not_first_visit') !== null && getCookie('govuk_browser_upgrade_dismissed') === null){
				$prompt.show();
				$prompt.find(".dismiss").on("click", function(){
					$prompt.hide();
					// the warning is dismissable for 2 weeks
					setCookie('browser_upgrade_dismissed', 'yes', 14);
					return false;
				});
			};
		};

		// We're not showing the message on first visit
		setCookie('govuk_not_first_visit', 'yes', 28);
	};
});
<|endoftext|>


<commit_before>/*
Input Mask plugin for jquery
http://github.com/RobinHerbots/jquery.inputmask
Copyright (c) 2010 Robin Herbots
Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
Version: 0.0.7

This plugin is based on the masked input plugin written by Josh Bush (digitalbush.com)
*/

(function($) {

    $.fn.inputmask = function(fn, options) {
        //options default
        var defaults = {
            placeholder: "_",
            mask: null,
            onComplete: null,
            repeat: 0, //repetitions of the mask
            greedy: true, //true: allocated buffer for all mask repetitions - false: allocate only if needed
            definitions: {
                '9': {
                    "validator": "[0-9]",
                    "cardinality": 1,
                    'prevalidator': null
                },
                'a': {
                    "validator": "[A-Za-z]",
                    "cardinality": 1,
                    "prevalidator": null
                },
                '*': {
                    "validator": "[A-Za-z0-9]",
                    "cardinality": 1,
                    "prevalidator": null
                },
                'd': { //day
                    "validator": "0[1-9]|[12][0-9]|3[01]",
                    "cardinality": 2,
                    "prevalidator": [{ "validator": "[0-3]", "cardinality": 1}]
                },
                'm': { //month
                    "validator": "0[1-9]|1[012]",
                    "cardinality": 2,
                    "prevalidator": [{ "validator": "[01]", "cardinality": 1}]
                },
                'y': { //year
                    "validator": "(19|20)\\d\\d",
                    "cardinality": 4,
                    "prevalidator": [
                        { "validator": "[12]", "cardinality": 1 },
                        { "validator": "(19|20)", "cardinality": 2 },
                        { "validator": "(19|20)\\d", "cardinality": 3 }
                        ]
                }
            },
            keyCode: { ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108,
                NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91
            }
        };

        var opts = $.extend({}, defaults, options);

        if (typeof fn == "string") {
            if (fn == 'mask') {
                //init buffer
                var _buffer = getMaskTemplate();
                var pasteEventName = $.browser.msie ? 'paste' : 'input';
                var iPhone = (window.orientation != undefined);
                var tests = getTestingChain();

                return this.each(function() {
                    mask($(this));
                });
            } else if (fn == 'unmaskedvalue') {
                var el = $(this);
                var tests = el.data('tests');
                var _buffer = el.data('_buffer');
                return unmaskedvalue(el);
            } else if (fn == 'setvalue') {
                var el = $(this);
                var tests = el.data('tests');
                var _buffer = el.data('_buffer');
                setvalue(el, options); //options in this case the value
            }
            else { //maybe fn is a mask so we try
                //set mask
                opts.mask = fn;

                //init buffer
                var _buffer = getMaskTemplate();
                var pasteEventName = $.browser.msie ? 'paste' : 'input';
                var iPhone = (window.orientation != undefined);
                var tests = getTestingChain();

                return this.each(function() {
                    mask($(this));
                });
            }
        } if (typeof fn == "object") {
            opts = $.extend({}, defaults, fn);

            //init buffer
            var _buffer = getMaskTemplate();
            var pasteEventName = $.browser.msie ? 'paste' : 'input';
            var iPhone = (window.orientation != undefined);
            var tests = getTestingChain();

            return this.each(function() {
                mask($(this));
            });
        }

        //helper functions
        function getMaskTemplate() {
            var singleMask = $.map(opts.mask.split(""), function(element, index) {
                var outElem = [];
                var maskdef = opts.definitions[element];
                if (maskdef) {
                    for (i = 0; i < maskdef.cardinality; i++) {
                        outElem.push(opts.placeholder);
                    }
                } else outElem.push(element);

                return outElem;
            });

            //allocate repetitions
            var repeatedMask = singleMask.slice();
            for (var i = 0; i < opts.repeat && opts.greedy; i++) {
                repeatedMask = repeatedMask.concat(singleMask.slice());
            }
            return repeatedMask;
        }

        function getTestingChain() {
            return $.map(opts.mask.split(""), function(element, index) {
                var outElem = [];
                var maskdef = opts.definitions[element];
                if (maskdef) {
                    for (i = 1; i < maskdef.cardinality; i++) {
                        var prevalidator = maskdef.prevalidator[i - 1];
                        outElem.push([new RegExp(prevalidator.validator), prevalidator.cardinality]);
                    }
                    outElem.push([new RegExp(maskdef.validator), maskdef.cardinality]);
                } else outElem.push(null);

                return outElem;
            });
        }

        function isValid(pos, c, buffer) {
            var testPos = determineTestPosition(pos);

            var loopend = 0;
            if (c) { loopend = 1; ; }

            var chrs = '';
            for (var i = tests[testPos][1]; i > loopend; i--) {
                chrs += getBufferElement(buffer, testPos - (i - 1));
            }

            if (c) { chrs += c; }

            return tests[testPos][0].test(chrs);
        }

        function isMask(pos) {
            return tests[determineTestPosition(pos)];
        }

        function determineTestPosition(pos) {
            return pos % tests.length;
        }

        function getMaskLength() {
            return _buffer.length;
        }

        function seekNext(pos) { //check for non greedy mask repeats //TODO
            while (++pos <= getMaskLength() && !isMask(pos));
            return pos;
        }
        //these are needed to handle the non-greedy mask repetitions
        function setBufferElement(buffer, position, element) {
            buffer[position] = element;
        }
        function getBufferElement(buffer, position) {
            return buffer[position];
        }

        function writeBuffer(input, buffer) { return input.val(buffer.join('')).val(); };
        function clearBuffer(buffer, start, end) {
            for (var i = start; i < end && i < getMaskLength(); i++) {
                setBufferElement(buffer, i, getBufferElement(_buffer, i));
            }
        };

        function checkVal(input, buffer, clearInvalid) {
            var inputValue = input.val();
            clearBuffer(buffer, 0, getMaskLength());
            var lastMatch = -1;
            for (var i = 0; i < inputValue.length; i++) {
                for (var pos = lastMatch + 1; pos < getMaskLength(); pos++) {
                    if (isMask(pos)) {
                        setBufferElement(buffer, pos, opts.placeholder);
                        if (isValid(pos, inputValue.charAt(i), buffer)) {
                            setBufferElement(buffer, pos, inputValue.charAt(i));
                            lastMatch = pos;
                        }
                        break;
                    } else {   //nonmask
                        lastMatch++;
                    }
                }
            }
            if (clearInvalid) {
                writeBuffer(input, buffer);
            }
            return seekNext(lastMatch);
        }

        //functionality fn
        function setvalue(el, value) {
            if (tests) {
                var buffer = _buffer.slice();
                el.val(value);
                checkVal(el, buffer, true);
            }
        }

        function unmaskedvalue(el) {

            if (tests) {
                var buffer = _buffer.slice();
                checkVal(el, buffer, true);
                return $.map(el.val().split(""), function(element, index) {
                    return isMask(index) && element != getBufferElement(_buffer, index) ? element : null;
                }).join('');
            }
            else {
                return el.val();
            }
        }

        function mask(el) {
            var input = $(el);
            //store tests & original buffer in the input element - used to get the unmasked value
            input.data('tests', tests);
            input.data('_buffer', _buffer);

            //init buffer
            var buffer = _buffer.slice();
            var undoBuffer = input.val();
            var ignore = false;              //Variable for ignoring control keys

            //bind events
            if (!input.attr("readonly")) {
                input.bind("focus", function() {
                    input.addClass('focus');
                    undoBuffer = input.val();
                    var pos = checkVal(input, buffer, true);
                    setTimeout(function() {
                        if (pos >= _buffer.length)
                            caret(input, 0, pos);
                        else
                            caret(input, pos);
                    }, 0);
                }).bind("mouseenter", function() {
                    if (!input.hasClass('focus') && input.val().length == 0) {
                        buffer = _buffer.slice();
                        writeBuffer(input, buffer);
                    }
                }).bind("blur", function() {
                    input.removeClass('focus');
                    if (input.val() == _buffer.join('')) {
                        input.val('');
                    } else {
                        checkVal(input, buffer);
                        if (input.val() != undoBuffer)
                            input.change();
                    }
                }).bind("mouseleave", function() {
                    if (!input.hasClass('focus') && input.val() == _buffer.join(''))
                        input.val('');
                }).bind("keydown", keydownEvent
                ).bind("keypress", keypressEvent
                ).bind(pasteEventName, function() {
                    setTimeout(function() { caret(input, checkVal(input, buffer, true)); }, 0);
                });

            }

            checkVal(input, buffer);

            //private functions
            function shiftL(pos) {
                while (!isMask(pos) && --pos >= 0);
                for (var i = pos; i < getMaskLength(); i++) {
                    if (isMask(i)) {
                        setBufferElement(buffer, i, opts.placeholder);
                        var j = seekNext(i);
                        if (j < getMaskLength() && isValid(i, getBufferElement(buffer, j), buffer)) {
                            setBufferElement(buffer, i, getBufferElement(buffer, j));
                        } else
                            break;
                    }
                }
                writeBuffer(input, buffer);
                caret(input, pos);
            };

            function shiftR(pos) {
                for (var i = pos, c = opts.placeholder; i < getMaskLength(); i++) {
                    if (isMask(i)) {
                        var j = seekNext(i);
                        var t = getBufferElement(buffer, i);
                        setBufferElement(buffer, i, c);
                        if (j < getMaskLength() && isValid(j, t, buffer))
                            c = t;
                        else
                            break;
                    }
                }
            };

            function caret(input, begin, end) {
                if (input.length == 0) return;
                if (typeof begin == 'number') {
                    end = (typeof end == 'number') ? end : begin;
                    return input.each(function() {
                        if (this.setSelectionRange) {
                            this.focus();
                            this.setSelectionRange(begin, end);
                        } else if (this.createTextRange) {
                            var range = this.createTextRange();
                            range.collapse(true);
                            range.moveEnd('character', end);
                            range.moveStart('character', begin);
                            range.select();
                        }
                    });
                } else {
                    if (input[0].setSelectionRange) {
                        begin = input[0].selectionStart;
                        end = input[0].selectionEnd;
                    } else if (document.selection && document.selection.createRange) {
                        var range = document.selection.createRange();
                        begin = 0 - range.duplicate().moveStart('character', -100000);
                        end = begin + range.text.length;
                    }
                    return { begin: begin, end: end };
                }
            };

            function keydownEvent(e) {
                var pos = caret($(this));
                var k = e.keyCode;
                ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));

                //delete selection before proceeding
                if ((pos.begin - pos.end) != 0 && (!ignore || k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE))
                    clearBuffer(buffer, pos.begin, pos.end);

                //backspace, delete, and escape get special treatment
                if (k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE || (iPhone && k == 127)) {//backspace/delete
                    shiftL(pos.begin + (k == opts.keyCode.DELETE ? 0 : -1));
                    return false;
                } else if (k == opts.keyCode.ESCAPE) {//escape
                    input.val(undoBuffer);
                    caret(input, 0, checkVal(input, buffer));
                    return false;
                }
            }

            function keypressEvent(e) {
                if (ignore) {
                    ignore = false;
                    //Fixes Mac FF bug on backspace
                    return (e.keyCode == opts.keyCode.BACKSPACE) ? false : null;
                }
                e = e || window.event;
                var k = e.charCode || e.keyCode || e.which;
                var pos = caret($(this));

                if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore
                    return true;
                } else if ((k >= 32 && k <= 125) || k > 186) {//typeable characters
                    var p = seekNext(pos.begin - 1);
                    if (p < getMaskLength()) {
                        var c = String.fromCharCode(k);
                        if (isValid(p, c, buffer)) {
                            shiftR(p);
                            setBufferElement(buffer, p, c);
                            writeBuffer(input, buffer);
                            var next = seekNext(p);
                            caret($(this), next);
                            if (opts.onComplete && next == getMaskLength())
                                opts.onComplete.call(input);
                        }
                    }
                }
                return false;
            }

        }
    };

})(jQuery);<commit_msg>Implemented non-greedy mask, ... allows for optional repetitions of the mask ex:  $(selector).inputmask({ "mask": "9", "repeat": 10, "greedy": false}); => number of max 10 chars but not necessarely 10 chars<commit_after>/*
Input Mask plugin for jquery
http://github.com/RobinHerbots/jquery.inputmask
Copyright (c) 2010 Robin Herbots
Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
Version: 0.0.8

This plugin is based on the masked input plugin written by Josh Bush (digitalbush.com)
*/

(function($) {

    $.fn.inputmask = function(fn, options) {
        //options default
        var defaults = {
            placeholder: "_",
            mask: null,
            onComplete: null,
            repeat: 0, //repetitions of the mask
            greedy: true, //true: allocated buffer for all mask repetitions - false: allocate only if needed
            definitions: {
                '9': {
                    "validator": "[0-9]",
                    "cardinality": 1,
                    'prevalidator': null
                },
                'a': {
                    "validator": "[A-Za-z]",
                    "cardinality": 1,
                    "prevalidator": null
                },
                '*': {
                    "validator": "[A-Za-z0-9]",
                    "cardinality": 1,
                    "prevalidator": null
                },
                'd': { //day
                    "validator": "0[1-9]|[12][0-9]|3[01]",
                    "cardinality": 2,
                    "prevalidator": [{ "validator": "[0-3]", "cardinality": 1}]
                },
                'm': { //month
                    "validator": "0[1-9]|1[012]",
                    "cardinality": 2,
                    "prevalidator": [{ "validator": "[01]", "cardinality": 1}]
                },
                'y': { //year
                    "validator": "(19|20)\\d\\d",
                    "cardinality": 4,
                    "prevalidator": [
                        { "validator": "[12]", "cardinality": 1 },
                        { "validator": "(19|20)", "cardinality": 2 },
                        { "validator": "(19|20)\\d", "cardinality": 3 }
                        ]
                }
            },
            keyCode: { ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108,
                NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91
            }
        };

        var opts = $.extend({}, defaults, options);

        if (typeof fn == "string") {
            if (fn == 'mask') {
                //init buffer
                var _buffer = getMaskTemplate();
                var pasteEventName = $.browser.msie ? 'paste' : 'input';
                var iPhone = (window.orientation != undefined);
                var tests = getTestingChain();

                return this.each(function() {
                    mask($(this));
                });
            } else if (fn == 'unmaskedvalue') {
                var el = $(this);
                var tests = el.data('tests');
                var _buffer = el.data('_buffer');
                return unmaskedvalue(el);
            } else if (fn == 'setvalue') {
                var el = $(this);
                var tests = el.data('tests');
                var _buffer = el.data('_buffer');
                setvalue(el, options); //options in this case the value
            }
            else { //maybe fn is a mask so we try
                //set mask
                opts.mask = fn;

                //init buffer
                var _buffer = getMaskTemplate();
                var pasteEventName = $.browser.msie ? 'paste' : 'input';
                var iPhone = (window.orientation != undefined);
                var tests = getTestingChain();

                return this.each(function() {
                    mask($(this));
                });
            }
        } if (typeof fn == "object") {
            opts = $.extend({}, defaults, fn);

            //init buffer
            var _buffer = getMaskTemplate();
            var pasteEventName = $.browser.msie ? 'paste' : 'input';
            var iPhone = (window.orientation != undefined);
            var tests = getTestingChain();

            return this.each(function() {
                mask($(this));
            });
        }

        //helper functions
        function getMaskTemplate() {
            var singleMask = $.map(opts.mask.split(""), function(element, index) {
                var outElem = [];
                var maskdef = opts.definitions[element];
                if (maskdef) {
                    for (i = 0; i < maskdef.cardinality; i++) {
                        outElem.push(opts.placeholder);
                    }
                } else outElem.push(element);

                return outElem;
            });

            //allocate repetitions
            var repeatedMask = singleMask.slice();
            for (var i = 0; i < opts.repeat && opts.greedy; i++) {
                repeatedMask = repeatedMask.concat(singleMask.slice());
            }
            return repeatedMask;
        }

        function getTestingChain() {
            return $.map(opts.mask.split(""), function(element, index) {
                var outElem = [];
                var maskdef = opts.definitions[element];
                if (maskdef) {
                    for (i = 1; i < maskdef.cardinality; i++) {
                        var prevalidator = maskdef.prevalidator[i - 1];
                        outElem.push([new RegExp(prevalidator.validator), prevalidator.cardinality]);
                    }
                    outElem.push([new RegExp(maskdef.validator), maskdef.cardinality]);
                } else outElem.push(null);

                return outElem;
            });
        }

        function isValid(pos, c, buffer) {
            var testPos = determineTestPosition(pos);

            var loopend = 0;
            if (c) { loopend = 1; ; }

            var chrs = '';
            for (var i = tests[testPos][1]; i > loopend; i--) {
                chrs += getBufferElement(buffer, testPos - (i - 1));
            }

            if (c) { chrs += c; }

            return tests[testPos][0].test(chrs);
        }

        function isMask(pos) {
            return tests[determineTestPosition(pos)];
        }

        function determineTestPosition(pos) {
            return pos % tests.length;
        }

        function getMaskLength() {
            var calculatedLength = _buffer.length;
            if (!opts.greedy) {
                calculatedLength += (_buffer.length * opts.repeat)
            }
            return calculatedLength;
        }

        function seekNext(pos) {
            while (++pos <= getMaskLength() && !isMask(pos));
            return pos;
        }
        //these are needed to handle the non-greedy mask repetitions
        function setBufferElement(buffer, position, element) {
            while (buffer.length <= position && buffer.length < getMaskLength()) {
                $.merge(buffer, _buffer);
            }
            buffer[position] = element;
        }
        function getBufferElement(buffer, position) {
            while (buffer.length <= position && buffer.length < getMaskLength()) {
                $.merge(buffer, _buffer);
            }
            return buffer[position];
        }

        function writeBuffer(input, buffer) { return input.val(buffer.join('')).val(); };
        function clearBuffer(buffer, start, end) {
            for (var i = start; i < end && i < getMaskLength(); i++) {
                setBufferElement(buffer, i, getBufferElement(_buffer.slice(), i));
            }
        };

        function checkVal(input, buffer, clearInvalid) {
            var inputValue = input.val().replace(new RegExp(_buffer.join('') + "$"), "");
            clearBuffer(buffer, 0, buffer.length);
            buffer.length = _buffer.length; //reset the buffer to its original size
            var lastMatch = -1;
            for (var i = 0; i < inputValue.length; i++) {
                for (var pos = lastMatch + 1; pos < getMaskLength(); pos++) {
                    if (isMask(pos)) {
                        if (isValid(pos, inputValue.charAt(i), buffer)) {
                            setBufferElement(buffer, pos, inputValue.charAt(i));
                            lastMatch = pos;
                        } else {
                            setBufferElement(buffer, pos, opts.placeholder);
                        }
                        break;
                    } else {   //nonmask
                        lastMatch++;
                    }
                }
            }
            if (clearInvalid) {
                writeBuffer(input, buffer);
            }
            return seekNext(lastMatch);
        }

        //functionality fn
        function setvalue(el, value) {
            el.val(value);
            if (tests) {
                var buffer = _buffer.slice();
                checkVal(el, buffer, true);
            }
        }

        function unmaskedvalue(el) {

            if (tests) {
                var buffer = _buffer.slice();
                checkVal(el, buffer, true);
                return $.map(el.val().split(""), function(element, index) {
                    return isMask(index) && element != getBufferElement(_buffer, index) ? element : null;
                }).join('');
            }
            else {
                return el.val();
            }
        }

        function mask(el) {
            var input = $(el);
            //store tests & original buffer in the input element - used to get the unmasked value
            input.data('tests', tests);
            input.data('_buffer', _buffer);

            //init buffer
            var buffer = _buffer.slice();
            var undoBuffer = input.val();
            var ignore = false;              //Variable for ignoring control keys

            //bind events
            if (!input.attr("readonly")) {
                input.bind("focus", function() {
                    input.addClass('focus');
                    undoBuffer = input.val();
                    var pos = checkVal(input, buffer, true);
                    setTimeout(function() {
                        if (pos >= _buffer.length)
                            caret(input, 0, pos);
                        else
                            caret(input, pos);
                    }, 0);
                }).bind("mouseenter", function() {
                    if (!input.hasClass('focus') && input.val().length == 0) {
                        buffer = _buffer.slice();
                        writeBuffer(input, buffer);
                    }
                }).bind("blur", function() {
                    input.removeClass('focus');
                    checkVal(input, buffer);
                    writeBuffer(input, buffer);
                    if (input.val() == _buffer.join('')) {
                        input.val('');
                    } else {
                        if (input.val() != undoBuffer)
                            input.change();
                    }
                }).bind("mouseleave", function() {
                    if (!input.hasClass('focus') && input.val() == _buffer.join(''))
                        input.val('');
                }).bind("keydown", keydownEvent
                ).bind("keypress", keypressEvent
                ).bind(pasteEventName, function() {
                    setTimeout(function() { caret(input, checkVal(input, buffer, true)); }, 0);
                });

            }

            checkVal(input, buffer);

            //private functions
            function shiftL(pos) {
                while (!isMask(pos) && --pos >= 0);
                for (var i = pos; i < getMaskLength(); i++) {
                    if (isMask(i)) {
                        setBufferElement(buffer, i, opts.placeholder);
                        var j = seekNext(i);
                        if (j < getMaskLength() && isValid(i, getBufferElement(buffer, j), buffer)) {
                            setBufferElement(buffer, i, getBufferElement(buffer, j));
                        } else
                            break;
                    }
                }
                writeBuffer(input, buffer);
                caret(input, pos);
            };

            function shiftR(pos) {
                for (var i = pos, c = opts.placeholder; i < getMaskLength(); i++) {
                    if (isMask(i)) {
                        var j = seekNext(i);
                        var t = getBufferElement(buffer, i);
                        setBufferElement(buffer, i, c);
                        if (j < getMaskLength() && isValid(j, t, buffer))
                            c = t;
                        else
                            break;
                    }
                }
            };

            function caret(input, begin, end) {
                if (input.length == 0) return;
                if (typeof begin == 'number') {
                    end = (typeof end == 'number') ? end : begin;
                    return input.each(function() {
                        if (this.setSelectionRange) {
                            this.focus();
                            this.setSelectionRange(begin, end);
                        } else if (this.createTextRange) {
                            var range = this.createTextRange();
                            range.collapse(true);
                            range.moveEnd('character', end);
                            range.moveStart('character', begin);
                            range.select();
                        }
                    });
                } else {
                    if (input[0].setSelectionRange) {
                        begin = input[0].selectionStart;
                        end = input[0].selectionEnd;
                    } else if (document.selection && document.selection.createRange) {
                        var range = document.selection.createRange();
                        begin = 0 - range.duplicate().moveStart('character', -100000);
                        end = begin + range.text.length;
                    }
                    return { begin: begin, end: end };
                }
            };

            function keydownEvent(e) {
                var pos = caret($(this));
                var k = e.keyCode;
                ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));

                //delete selection before proceeding
                if ((pos.begin - pos.end) != 0 && (!ignore || k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE))
                    clearBuffer(buffer, pos.begin, pos.end);

                //backspace, delete, and escape get special treatment
                if (k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE || (iPhone && k == 127)) {//backspace/delete
                    shiftL(pos.begin + (k == opts.keyCode.DELETE ? 0 : -1));
                    return false;
                } else if (k == opts.keyCode.ESCAPE) {//escape
                    input.val(undoBuffer);
                    caret(input, 0, checkVal(input, buffer));
                    return false;
                }
            }

            function keypressEvent(e) {
                if (ignore) {
                    ignore = false;
                    //Fixes Mac FF bug on backspace
                    return (e.keyCode == opts.keyCode.BACKSPACE) ? false : null;
                }
                e = e || window.event;
                var k = e.charCode || e.keyCode || e.which;
                var pos = caret($(this));

                if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore
                    return true;
                } else if ((k >= 32 && k <= 125) || k > 186) {//typeable characters
                    var p = seekNext(pos.begin - 1);
                    if (p < getMaskLength()) {
                        var c = String.fromCharCode(k);
                        if (isValid(p, c, buffer)) {
                            shiftR(p);
                            setBufferElement(buffer, p, c);
                            writeBuffer(input, buffer);
                            var next = seekNext(p);
                            caret($(this), next);
                            if (opts.onComplete && next == getMaskLength())
                                opts.onComplete.call(input);
                        }
                    }
                }
                return false;
            }

        }
    };

})(jQuery);<|endoftext|>


<commit_before>'use strict'

var express = require('express'),
	versions = require('./versions'),
	scrub = require('./scrub'),
	genId = require('./genId'),
	APIError = require('./APIError'),
	openAPI = require('./openAPI'),
	bodyParser = require('body-parser')

/**
 * Represent a lifted API
 *
 * Instances of this class are created internally for you.
 * *You don't need to use this constructor directly.*
 *
 * @class
 * @param {external:lift-it.Lifted} lifted
 * @param {Object} options
 * @param {Array<RegExp>} options.dataScrub
 * @param {Function} options.callToJSON
 * @param {?Function} options.onsuccess
 * @param {?Function} options.onfailure
 */
function API(lifted, options) {
	/** @member {external:express.Router} */
	this.router = new express.Router

	/** @member {number} */
	this.minVersion = 0

	/** @member {number} */
	this.maxVersion = 0

	/**
	 * The list of supported versions, ordered from oldest to newest.
	 * Example: `['v3', 'v4']`
	 * @member {Array<string>}
	 */
	this.versions = 0

	/** @member {Array<Endpoint>} */
	this.endpoints = []

	/**
	 * The map from url to an Endpoint instance
	 * @member {Object<Endpoint>}
	 */
	this.endpointByUrl = Object.create(null)

	/**
	 * @member {lift-it:Lifted}
	 * @private
	 */
	this._lifted = lifted

	/**
	 * @member {Object}
	 * @private
	 */
	this._options = options

	/**
	 * @member {Array<RegExp>}
	 * @private
	 */
	this._dataScrub = options.dataScrub

	/**
	 * @member {Function}
	 * @private
	 */
	this._callToJSON = options.callToJSON

	/**
	 * @member {?Function}
	 * @private
	 */
	this._onsuccess = options.onsuccess

	/**
	 * @member {?Function}
	 * @private
	 */
	this._onfailure = options.onfailure

	/**
	 * @member {Function}
	 * @private
	 */
	this._bodyParse = bodyParser.json(options.bodyParser)
}

module.exports = API

/**
 * Execute an endpoint in this api
 * @param {string} url - like '/v1/user/create' or '/v-last/user/create'
 * @param {Object} body
 * @param {Object} [runInfo={}] - data available as `process.domain.runInfo`. See more info in {@link https://www.npmjs.com/package/run-it|run-it} module
 * @param {number} [runInfo.beginTime=Date.now()]
 * @param {string} [runInfo.requestId=genId()]
 * @param {Function} callback - async cb(out)
 */
API.prototype.run = function (url, body, runInfo, callback) {
	// runInfo is optional
	if (typeof runInfo === 'function') {
		callback = runInfo
		runInfo = {}
	}

	runInfo = this._prepareRunInfo(runInfo)
	var that = this,
		endpoint = this._translateURL(url)

	if (!endpoint) {
		// Always async
		return process.nextTick(function () {
			that._handleNotFound(url, body, runInfo, callback)
		})
	}
	this._runEndpoint(endpoint, body, runInfo, callback)
}

/**
 * Return the OpenAPI (Swagger) description object of this api.
 * Both prepareEndpoint and prepareSpec will be applied.
 * @param {number} [version] - version to consider (if empty, returns all versions)
 * @returns {Object}
 */
API.prototype.getOpenAPISpec = function (version) {
	return openAPI(this, version)
}

/**
 * Translates a web request into an endpoint execution in this api
 * @param {Object} req
 * @param {Object} [req.runInfo]
 * @param {Object} res
 * @param {Function} callback - async cb(err, out)
 * @private
 */
API.prototype._runRequest = function (req, res, callback) {
	req.runInfo = this._prepareRunInfo(req.runInfo)

	var endpoint = this._translateURL(req.url),
		that = this

	if (!endpoint) {
		// If endpoint is not found, we parse the body with component's
		// default parser for logging pourposes
		that._bodyParse(req, res, callback)
		return process.nextTick(function () {
			that._handleNotFound(req.url, req.body, req.runInfo, function (out) {
				callback(null, out)
			})
		})
	}

	endpoint.action.module.bodyParse(req, res, function (err) {
		if (err || !req.body) {
			return callback(err)
		}

		that._runEndpoint(endpoint, req.body, req.runInfo, function (out) {
			callback(null, out)
		})
	})
}

/**
 * Prepares a runInfo object with the default data
 * @param {Object} [req.runInfo={}]
 * @param {number} [req.runInfo.beginTime=Date.now()]
 * @param {string} [req.runInfo.requestId=genId()]
 * @returns {Object}
 * @private
 */
API.prototype._prepareRunInfo = function (runInfo) {
	runInfo = runInfo || {}
	runInfo.beginTime = runInfo.beginTime || Date.now()
	runInfo.requestId = runInfo.requestId || genId()
	return runInfo
}

/**
 * Finds an endpoint from the given url
 * @param {string} url - like '/v1/user/create' or '/v-last/user/create'
 * @returns {Endpoint}
 * @private
 */
API.prototype._translateURL = function (url) {
	// Translate 'v-last'
	if (url.indexOf('/v-last/') === 0) {
		url = '/v' + this.maxVersion + '/' + url.substr(8)
	}

	return this.endpointByUrl[url]
}

/**
 * Execute an endpoint in this api
 * @param {Endpoint} endpoint
 * @param {Object} body
 * @param {Object} runInfo
 * @param {Function} callback - async cb(out)
 * @private
 */
API.prototype._runEndpoint = function (endpoint, body, runInfo, callback) {
	var that = this,
		action = endpoint.action,
		profile = action.profile
	action.getRunner().runInfo(runInfo).exec(body, function (err, out) {
		if (profile) {
			runInfo.profileData = arguments[arguments.length - 1]
		}

		if (err) {
			return that._handleError(err, body, runInfo, endpoint, callback)
		}

		out = profile && arguments.length === 2 ? {} : (out || {})
		if (typeof out !== 'object') {
			throw new Error('The response must be an object')
		}
		out.failure = null
		if (that._onsuccess) {
			that._onsuccess(out, runInfo, scrub(body, that._dataScrub, that._callToJSON), endpoint)
		}
		callback(out)
	})
}

/**
 * List the endpoint from action names
 * @param {number} minVersion
 * @private
 */
API.prototype._prepareEndpoints = function (minVersion) {
	var data = versions(minVersion, this._lifted.actions)

	this.minVersion = data.minVersion
	this.maxVersion = data.maxVersion
	this.versions = data.versions
	this.endpoints = data.endpoints
	this.endpointByUrl = data.endpointByUrl
}

/**
 * Provide a friendly message if the endpoint is not found
 * @param {string} url
 * @param {Object} body
 * @param {Object} runInfo
 * @param {Function} callback - cb(out)
 * @private
 */
API.prototype._handleNotFound = function (url, body, runInfo, callback) {
	var match = url.match(/^\/(v\d+)\/(.*)$/),
		err, version, action

	if (!match) {
		err = APIError.create(199,
			'Invalid path format, expected something like /' +
			this.versions[this.versions.length - 1] + '/user/create')
	} else {
		version = match[1]
		action = match[2]
		if (this.versions.indexOf(version) === -1) {
			err = APIError.create(199,
				'Version ' + version + ' is not supported. Supported versions are: ' +
				this.versions.join(', '))
		} else {
			err = APIError.create(199,
				'The action ' + action + ' does not exists in version ' + version)
		}
	}

	this._handleError(err, body, runInfo, null, callback)
}

/**
 * Treat error cases, formating them to a failure object
 * @param {Object} err
 * @param {Object} body
 * @param {Object} runInfo
 * @param {?Endpoint} endpoint
 * @param {Function} callback - cb(out)
 * @private
 */
API.prototype._handleError = function (err, body, runInfo, endpoint, callback) {
	var code, message

	if (err instanceof APIError) {
		code = err.code
		message = err.message
	} else {
		code = 100
		message = err.message || String(err) || 'Unknown error'
	}

	var out = {
		failure: {
			code: code,
			message: message
		}
	}
	if (this._onfailure) {
		this._onfailure(out, runInfo, scrub(body, this._dataScrub, this._callToJSON), endpoint, err)
	}
	callback(out)
}<commit_msg>Rename API#_translateURL to API#_getEndpoint<commit_after>'use strict'

var express = require('express'),
	versions = require('./versions'),
	scrub = require('./scrub'),
	genId = require('./genId'),
	APIError = require('./APIError'),
	openAPI = require('./openAPI'),
	bodyParser = require('body-parser')

/**
 * Represent a lifted API
 *
 * Instances of this class are created internally for you.
 * *You don't need to use this constructor directly.*
 *
 * @class
 * @param {external:lift-it.Lifted} lifted
 * @param {Object} options
 * @param {Array<RegExp>} options.dataScrub
 * @param {Function} options.callToJSON
 * @param {?Function} options.onsuccess
 * @param {?Function} options.onfailure
 */
function API(lifted, options) {
	/** @member {external:express.Router} */
	this.router = new express.Router

	/** @member {number} */
	this.minVersion = 0

	/** @member {number} */
	this.maxVersion = 0

	/**
	 * The list of supported versions, ordered from oldest to newest.
	 * Example: `['v3', 'v4']`
	 * @member {Array<string>}
	 */
	this.versions = 0

	/** @member {Array<Endpoint>} */
	this.endpoints = []

	/**
	 * The map from url to an Endpoint instance
	 * @member {Object<Endpoint>}
	 */
	this.endpointByUrl = Object.create(null)

	/**
	 * @member {lift-it:Lifted}
	 * @private
	 */
	this._lifted = lifted

	/**
	 * @member {Object}
	 * @private
	 */
	this._options = options

	/**
	 * @member {Array<RegExp>}
	 * @private
	 */
	this._dataScrub = options.dataScrub

	/**
	 * @member {Function}
	 * @private
	 */
	this._callToJSON = options.callToJSON

	/**
	 * @member {?Function}
	 * @private
	 */
	this._onsuccess = options.onsuccess

	/**
	 * @member {?Function}
	 * @private
	 */
	this._onfailure = options.onfailure

	/**
	 * @member {Function}
	 * @private
	 */
	this._bodyParse = bodyParser.json(options.bodyParser)
}

module.exports = API

/**
 * Execute an endpoint in this api
 * @param {string} url - like '/v1/user/create' or '/v-last/user/create'
 * @param {Object} body
 * @param {Object} [runInfo={}] - data available as `process.domain.runInfo`. See more info in {@link https://www.npmjs.com/package/run-it|run-it} module
 * @param {number} [runInfo.beginTime=Date.now()]
 * @param {string} [runInfo.requestId=genId()]
 * @param {Function} callback - async cb(out)
 */
API.prototype.run = function (url, body, runInfo, callback) {
	// runInfo is optional
	if (typeof runInfo === 'function') {
		callback = runInfo
		runInfo = {}
	}

	runInfo = this._prepareRunInfo(runInfo)
	var that = this,
		endpoint = this._getEndpoint(url)

	if (!endpoint) {
		// Always async
		return process.nextTick(function () {
			that._handleNotFound(url, body, runInfo, callback)
		})
	}
	this._runEndpoint(endpoint, body, runInfo, callback)
}

/**
 * Return the OpenAPI (Swagger) description object of this api.
 * Both prepareEndpoint and prepareSpec will be applied.
 * @param {number} [version] - version to consider (if empty, returns all versions)
 * @returns {Object}
 */
API.prototype.getOpenAPISpec = function (version) {
	return openAPI(this, version)
}

/**
 * Translates a web request into an endpoint execution in this api
 * @param {Object} req
 * @param {Object} [req.runInfo]
 * @param {Object} res
 * @param {Function} callback - async cb(err, out)
 * @private
 */
API.prototype._runRequest = function (req, res, callback) {
	req.runInfo = this._prepareRunInfo(req.runInfo)

	var endpoint = this._getEndpoint(req.url),
		that = this

	if (!endpoint) {
		// If endpoint is not found, we parse the body with component's
		// default parser for logging pourposes
		that._bodyParse(req, res, callback)
		return process.nextTick(function () {
			that._handleNotFound(req.url, req.body, req.runInfo, function (out) {
				callback(null, out)
			})
		})
	}

	endpoint.action.module.bodyParse(req, res, function (err) {
		if (err || !req.body) {
			return callback(err)
		}

		that._runEndpoint(endpoint, req.body, req.runInfo, function (out) {
			callback(null, out)
		})
	})
}

/**
 * Prepares a runInfo object with the default data
 * @param {Object} [req.runInfo={}]
 * @param {number} [req.runInfo.beginTime=Date.now()]
 * @param {string} [req.runInfo.requestId=genId()]
 * @returns {Object}
 * @private
 */
API.prototype._prepareRunInfo = function (runInfo) {
	runInfo = runInfo || {}
	runInfo.beginTime = runInfo.beginTime || Date.now()
	runInfo.requestId = runInfo.requestId || genId()
	return runInfo
}

/**
 * Finds an endpoint from the given url
 * @param {string} url - like '/v1/user/create' or '/v-last/user/create'
 * @returns {Endpoint}
 * @private
 */
API.prototype._getEndpoint = function (url) {
	// Translate 'v-last'
	if (url.indexOf('/v-last/') === 0) {
		url = '/v' + this.maxVersion + '/' + url.substr(8)
	}

	return this.endpointByUrl[url]
}

/**
 * Execute an endpoint in this api
 * @param {Endpoint} endpoint
 * @param {Object} body
 * @param {Object} runInfo
 * @param {Function} callback - async cb(out)
 * @private
 */
API.prototype._runEndpoint = function (endpoint, body, runInfo, callback) {
	var that = this,
		action = endpoint.action,
		profile = action.profile
	action.getRunner().runInfo(runInfo).exec(body, function (err, out) {
		if (profile) {
			runInfo.profileData = arguments[arguments.length - 1]
		}

		if (err) {
			return that._handleError(err, body, runInfo, endpoint, callback)
		}

		out = profile && arguments.length === 2 ? {} : (out || {})
		if (typeof out !== 'object') {
			throw new Error('The response must be an object')
		}
		out.failure = null
		if (that._onsuccess) {
			that._onsuccess(out, runInfo, scrub(body, that._dataScrub, that._callToJSON), endpoint)
		}
		callback(out)
	})
}

/**
 * List the endpoint from action names
 * @param {number} minVersion
 * @private
 */
API.prototype._prepareEndpoints = function (minVersion) {
	var data = versions(minVersion, this._lifted.actions)

	this.minVersion = data.minVersion
	this.maxVersion = data.maxVersion
	this.versions = data.versions
	this.endpoints = data.endpoints
	this.endpointByUrl = data.endpointByUrl
}

/**
 * Provide a friendly message if the endpoint is not found
 * @param {string} url
 * @param {Object} body
 * @param {Object} runInfo
 * @param {Function} callback - cb(out)
 * @private
 */
API.prototype._handleNotFound = function (url, body, runInfo, callback) {
	var match = url.match(/^\/(v\d+)\/(.*)$/),
		err, version, action

	if (!match) {
		err = APIError.create(199,
			'Invalid path format, expected something like /' +
			this.versions[this.versions.length - 1] + '/user/create')
	} else {
		version = match[1]
		action = match[2]
		if (this.versions.indexOf(version) === -1) {
			err = APIError.create(199,
				'Version ' + version + ' is not supported. Supported versions are: ' +
				this.versions.join(', '))
		} else {
			err = APIError.create(199,
				'The action ' + action + ' does not exists in version ' + version)
		}
	}

	this._handleError(err, body, runInfo, null, callback)
}

/**
 * Treat error cases, formating them to a failure object
 * @param {Object} err
 * @param {Object} body
 * @param {Object} runInfo
 * @param {?Endpoint} endpoint
 * @param {Function} callback - cb(out)
 * @private
 */
API.prototype._handleError = function (err, body, runInfo, endpoint, callback) {
	var code, message

	if (err instanceof APIError) {
		code = err.code
		message = err.message
	} else {
		code = 100
		message = err.message || String(err) || 'Unknown error'
	}

	var out = {
		failure: {
			code: code,
			message: message
		}
	}
	if (this._onfailure) {
		this._onfailure(out, runInfo, scrub(body, this._dataScrub, this._callToJSON), endpoint, err)
	}
	callback(out)
}<|endoftext|>


<commit_before>// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
TileMill.templates = {};
TileMill.template = function(template, data) {
  // Figure out if we're getting a template, or if we need to
  // load the template - and be sure to cache the result.
  var fn = TileMill.templates[template];
  if (!fn) {
    fn = TileMill.templates[template] = new Function("obj",
      "var p=[],print=function(){p.push.apply(p,arguments);};" +
      // Introduce the data as local variables using with(){}
      "with(obj){p.push('" +
      // Convert the template into pure JavaScript
      $('script[name=' + template + ']').html()
        .replace(/[\r\t\n]/g, " ")
        .split("<%").join("\t")
        .replace(/((^|%>)[^\t]*)'/g, "$1\r")
        .split("'").join("\\'")
        .replace(/\t=(.*?)%>/g, "',$1,'")
        .split("\t").join("');")
        .split("%>").join("p.push('")
        .split("\r").join("\\'")
    + "');}return p.join('');");
  }
  // Provide some basic currying to the user
  return data ? fn( data ) : fn;
};
<commit_msg>Removing old template system<commit_after><|endoftext|>


<commit_before>$(document).ready(function(){
  $('form').on('submit', function(event){
    event.preventDefault();
    if (checkForm() == true) {
      //submit data
    }
    else {
      if ($('#_street_number').val().length < 1) {
        $('#_street_number').val("Insert a street number.");
      }
      if ($('#_street_address').val().length < 1) {
        $('#_street_address').val("Insert a street.");
      }
      if ($('#_city').val().length < 1) {
        $('#_city').val("Insert a city.");
      }
      if ($('#_state').val().length < 1) {
        $('#_state').val("Insert a state.");
      }
      if ($('#_zip').val().length < 1) {
        $('#_zip').val("Insert a zip code.");
      }
    }
    // getCandidates($(this).serialize());
  });
});

var checkForm = function() {
  if (($('#_street_number').val().length > 1) && ($('#_street_address').val().length > 1) && ($('#_city').val().length > 1) && ($('#_zip').val().length > 1) && ($('#_state').val().length > 1)) {
    return true;
  }
  else {
    return false;
  }
}<commit_msg>Make ajax request to get candidate data from votesmart<commit_after>$(document).ready(function(){
  $('form').on('submit', function(event){
    event.preventDefault();
    if (checkForm() == true) {
      insertComma();
      getCandidates();
    }
    else {
      if ($('#_street_number').val().length < 1) {
        $('#_street_number').val("Insert a street number.");
      }
      if ($('#_street_address').val().length < 1) {
        $('#_street_address').val("Insert a street.");
      }
      if ($('#_city').val().length < 1) {
        $('#_city').val("Insert a city.");
      }
      if ($('#_state').val().length < 1) {
        $('#_state').val("Insert a state.");
      }
      if ($('#_zip').val().length < 1) {
        $('#_zip').val("Insert a zip code.");
      }
    }
  });
});

var checkForm = function() {
  if (($('#_street_number').val().length > 1) && ($('#_street_address').val().length > 1) && ($('#_city').val().length > 1) && ($('#_zip').val().length > 1) && ($('#_state').val().length > 1)) {
    return true;
  }
  else {
    return false;
  }
}

var insertComma = function() {
   $('#_city').val($('#_city').val() + ',');
}

var getCandidates = function() {
  formattedUrl = 'http://votesmart.org/x/search?s=' + $('#_street_number').val() + '%20' + $('#_street_address').val() + '%20' + $('#_city').val() + '%20' + $('#_state').val() + '%20' + $('#_zip').val();
  var candidatesRequest = $.ajax({
   method: 'get',
   url: formattedUrl
  });
 candidatesRequest.done(function(response){
  var candidateCreateRequest = $.ajax({
    url: "/candidates/create",
    data: response,
    method: 'post'
  });
  candidateCreateRequest.done(function(response){
    alert(response);
  });
 });
};
<|endoftext|>