<commit_before>/**
 * WordPress dependencies
 */
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import domReady from '@wordpress/dom-ready';
import { select, subscribe, dispatch } from '@wordpress/data';
import { registerPlugin } from '@wordpress/plugins';
import {
	getDefaultBlockName,
	setDefaultBlockName,
	getBlockTypes,
	unregisterBlockType,
	registerBlockType,
	registerBlockStyle,
	unregisterBlockStyle,
} from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import {
	withAmpStorySettings,
	withPageNumber,
	withEditFeaturedImage,
	withStoryFeaturedImageNotice,
	withWrapperProps,
	withCroppedFeaturedImage,
	withActivePageState,
	withStoryBlockDropZone,
	withCallToActionValidation,
	withVideoPosterImageNotice,
} from '../components';
import {
	maybeEnqueueFontStyle,
	setBlockParent,
	filterBlockAttributes,
	addAMPAttributes,
	addAMPExtraProps,
	getTotalAnimationDuration,
	renderStoryComponents,
	maybeInitializeAnimations,
	maybeRemoveImageCaption,
	maybeSetInitialPositioning,
	maybeSetInitialSize,
	maybeSetTagName,
	maybeUpdateAutoAdvanceAfterMedia,
	wrapBlocksInGridLayer,
	getMinimumStoryPosterDimensions,
} from './helpers';

import { ALLOWED_BLOCKS } from './constants';

import store from './store';

const {
	getSelectedBlockClientId,
	getBlocksByClientId,
	getClientIdsWithDescendants,
	getBlockRootClientId,
	getBlockOrder,
	getBlock,
	getBlockAttributes,
} = select( 'core/block-editor' );

const {
	moveBlockToPosition,
	updateBlockAttributes,
} = dispatch( 'core/block-editor' );

const { getEditorMode, isFeatureActive } = select( 'core/edit-post' );
const { toggleFeature } = dispatch( 'core/edit-post' );

const {
	isReordering,
	getBlockOrder: getCustomBlockOrder,
	getCurrentPage,
	getAnimatedBlocks,
} = select( 'amp/story' );

const {	setCurrentPage } = dispatch( 'amp/story' );

/**
 * Initialize editor integration.
 */
domReady( () => {
	// Ensure that the default block is page when no block is selected.
	setDefaultBlockName( 'amp/amp-story-page' );

	// Remove all blocks that aren't whitelisted.
	const disallowedBlockTypes = getBlockTypes().filter( ( { name } ) => ! ALLOWED_BLOCKS.includes( name ) );

	for ( const blockType of disallowedBlockTypes ) {
		unregisterBlockType( blockType.name );
	}

	const allBlocks = getBlocksByClientId( getClientIdsWithDescendants() );

	// Set initially shown page.
	const firstPage = allBlocks.find( ( { name } ) => name === 'amp/amp-story-page' );
	setCurrentPage( firstPage ? firstPage.clientId : undefined );

	for ( const block of allBlocks ) {
		// Load all needed fonts.
		if ( block.attributes.ampFontFamily ) {
			maybeEnqueueFontStyle( block.attributes.ampFontFamily );
		}
	}

	// Enforce fixed toolbar.
	if ( ! isFeatureActive( 'fixedToolbar' ) ) {
		toggleFeature( 'fixedToolbar' );
	}

	renderStoryComponents();

	// Prevent WritingFlow component from focusing on last text field when clicking below the carousel.
	document.querySelector( '.block-editor-writing-flow__click-redirect' ).remove();

	for ( const roundedBlock of [ 'amp/amp-story-text', 'amp/amp-story-post-author', 'amp/amp-story-post-date', 'amp/amp-story-post-title' ] ) {
		registerBlockStyle( roundedBlock, {
			name: 'rounded',
			label: __( 'Rounded', 'amp' ),
		} );
	}

	registerBlockStyle( 'amp/amp-story-text', {
		name: 'half-rounded',
		label: __( 'Half Rounded', 'amp' ),
	} );

	registerBlockStyle( 'core/image', {
		name: 'rounded',
		label: __( 'Rounded', 'amp' ),
	} );

	registerBlockStyle( 'core/quote', {
		name: 'white',
		label: __( 'White', 'amp' ),
	} );

	unregisterBlockStyle( 'core/quote', 'large' );
} );

let blockOrder = getBlockOrder();
let allBlocksWithChildren = getClientIdsWithDescendants();

let editorMode = getEditorMode();

subscribe( async () => {
	maybeInitializeAnimations();

	const defaultBlockName = getDefaultBlockName();
	const selectedBlockClientId = getSelectedBlockClientId();

	// Switch default block depending on context
	if ( selectedBlockClientId ) {
		const selectedBlock = getBlock( selectedBlockClientId );

		if ( 'amp/amp-story-page' === selectedBlock.name && 'amp/amp-story-page' !== defaultBlockName ) {
			setDefaultBlockName( 'amp/amp-story-page' );
		} else if ( 'amp/amp-story-page' !== selectedBlock.name && 'amp/amp-story-text' !== defaultBlockName ) {
			setDefaultBlockName( 'amp/amp-story-text' );
		}
	} else if ( ! selectedBlockClientId && 'amp/amp-story-page' !== defaultBlockName ) {
		setDefaultBlockName( 'amp/amp-story-page' );
	}

	const newBlockOrder = getBlockOrder();
	const newlyAddedPages = newBlockOrder.find( ( block ) => ! blockOrder.includes( block ) );
	const deletedPages = blockOrder.filter( ( block ) => ! newBlockOrder.includes( block ) );

	if ( deletedPages.includes( getCurrentPage() ) ) {
		// Change current page if it has been deleted.
		const nextIndex = Math.max( 0, blockOrder.indexOf( getCurrentPage() ) - 1 );

		blockOrder = newBlockOrder;

		setCurrentPage( blockOrder[ nextIndex ] );
	}

	blockOrder = newBlockOrder;

	// If a new page has been inserted, make it the current one.
	if ( newlyAddedPages ) {
		setCurrentPage( newlyAddedPages );
	}

	for ( const block of allBlocksWithChildren ) {
		maybeSetInitialPositioning( block );
		maybeRemoveImageCaption( block );
		maybeUpdateAutoAdvanceAfterMedia( block );
		maybeSetTagName( block );
		maybeSetInitialSize( block );
	}

	allBlocksWithChildren = getClientIdsWithDescendants();

	// Re-add controls when switching back from code to visual editor.
	const newEditorMode = getEditorMode();
	if ( 'visual' === newEditorMode && newEditorMode !== editorMode ) {
		while ( ! document.querySelector( '.editor-block-list__layout' ) ) {
			await new Promise( ( r ) => setTimeout( r, 200 ) );
		}

		renderStoryComponents();
	}

	editorMode = newEditorMode;
} );

store.subscribe( () => {
	const editorBlockOrder = getBlockOrder();
	const customBlockOrder = getCustomBlockOrder();

	// The block order has changed, let's re-order.
	if ( ! isReordering() && customBlockOrder.length > 0 && editorBlockOrder !== customBlockOrder ) {
		for ( const [ index, page ] of customBlockOrder.entries() ) {
			moveBlockToPosition( page, '', '', index );
		}
	}

	const animatedBlocks = getAnimatedBlocks();

	// Update pages and blocks based on updated animation data.
	for ( const page in animatedBlocks ) {
		if ( ! animatedBlocks.hasOwnProperty( page ) || ! getBlock( page ) ) {
			continue;
		}

		const pageAttributes = getBlockAttributes( page );

		const animatedBlocksPerPage = animatedBlocks[ page ].filter( ( { id } ) => page === getBlockRootClientId( id ) );

		const totalAnimationDuration = getTotalAnimationDuration( animatedBlocksPerPage );
		const totalAnimationDurationInSeconds = Math.ceil( totalAnimationDuration / 1000 );

		if ( 'time' === pageAttributes.autoAdvanceAfter ) {
			// Enforce minimum value for manually set time.
			if ( totalAnimationDurationInSeconds > pageAttributes.autoAdvanceAfterDuration ) {
				updateBlockAttributes( page, { autoAdvanceAfterDuration: totalAnimationDurationInSeconds } );
			}
		} else {
			updateBlockAttributes( page, { autoAdvanceAfterDuration: totalAnimationDurationInSeconds } );
		}

		for ( const item of animatedBlocksPerPage ) {
			const { id, parent, animationType, duration, delay } = item;

			const parentBlock = parent ? getBlock( parent ) : undefined;

			updateBlockAttributes( id, {
				ampAnimationAfter: parentBlock ? parentBlock.attributes.anchor : undefined,
				ampAnimationType: animationType,
				ampAnimationDuration: duration,
				ampAnimationDelay: delay,
			} );
		}
	}
} );

const plugins = require.context( './plugins', true, /.*\.js$/ );

plugins.keys().forEach( ( modulePath ) => {
	const { name, render, isActive = true } = plugins( modulePath );

	if ( isActive ) {
		registerPlugin( name, { render } );
	}
} );

addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/setBlockParent', setBlockParent );
addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/addAttributes', addAMPAttributes );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addStorySettings', withAmpStorySettings );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addPageNumber', withPageNumber );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addEditFeaturedImage', withEditFeaturedImage );
addFilter( 'editor.PostFeaturedImage', 'ampStoryEditorBlocks/addFeaturedImageNotice', withStoryFeaturedImageNotice );
addFilter( 'editor.BlockListBlock', 'ampStoryEditorBlocks/withActivePageState', withActivePageState );
addFilter( 'editor.BlockListBlock', 'ampStoryEditorBlocks/addWrapperProps', withWrapperProps );
addFilter( 'editor.MediaUpload', 'ampStoryEditorBlocks/addCroppedFeaturedImage', withCroppedFeaturedImage );
addFilter( 'editor.MediaUpload', 'ampStoryEditorBlocks/addPosterImageNotice', withVideoPosterImageNotice );
addFilter( 'editor.MediaUpload', 'ampStoryEditorBlocks/addCroppedFeaturedImage', ( InitialMediaUpload ) => withCroppedFeaturedImage( InitialMediaUpload, getMinimumStoryPosterDimensions() ) );
addFilter( 'blocks.getSaveContent.extraProps', 'ampStoryEditorBlocks/addExtraAttributes', addAMPExtraProps );
addFilter( 'blocks.getSaveElement', 'ampStoryEditorBlocks/wrapBlocksInGridLayer', wrapBlocksInGridLayer );
addFilter( 'editor.BlockDropZone', 'ampStoryEditorBlocks/withStoryBlockDropZone', withStoryBlockDropZone );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/withCallToActionValidation', withCallToActionValidation );
addFilter( 'blocks.getBlockAttributes', 'ampStoryEditorBlocks/filterBlockAttributes', filterBlockAttributes );

const blocks = require.context( './blocks', true, /(?<!test\/)index\.js$/ );

// Block types need to be register *after* all the filters have been applied.
blocks.keys().forEach( ( modulePath ) => {
	const { name, settings } = blocks( modulePath );
	registerBlockType( name, settings );
} );
<commit_msg>Fix issue after merge<commit_after>/**
 * WordPress dependencies
 */
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import domReady from '@wordpress/dom-ready';
import { select, subscribe, dispatch } from '@wordpress/data';
import { registerPlugin } from '@wordpress/plugins';
import {
	getDefaultBlockName,
	setDefaultBlockName,
	getBlockTypes,
	unregisterBlockType,
	registerBlockType,
	registerBlockStyle,
	unregisterBlockStyle,
} from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import {
	withAmpStorySettings,
	withPageNumber,
	withEditFeaturedImage,
	withStoryFeaturedImageNotice,
	withWrapperProps,
	withCroppedFeaturedImage,
	withActivePageState,
	withStoryBlockDropZone,
	withCallToActionValidation,
	withVideoPosterImageNotice,
} from '../components';
import {
	maybeEnqueueFontStyle,
	setBlockParent,
	filterBlockAttributes,
	addAMPAttributes,
	addAMPExtraProps,
	getTotalAnimationDuration,
	renderStoryComponents,
	maybeInitializeAnimations,
	maybeRemoveImageCaption,
	maybeSetInitialPositioning,
	maybeSetInitialSize,
	maybeSetTagName,
	maybeUpdateAutoAdvanceAfterMedia,
	wrapBlocksInGridLayer,
	getMinimumStoryPosterDimensions,
} from './helpers';

import { ALLOWED_BLOCKS } from './constants';

import store from './store';

const {
	getSelectedBlockClientId,
	getBlocksByClientId,
	getClientIdsWithDescendants,
	getBlockRootClientId,
	getBlockOrder,
	getBlock,
	getBlockAttributes,
} = select( 'core/block-editor' );

const {
	moveBlockToPosition,
	updateBlockAttributes,
} = dispatch( 'core/block-editor' );

const { getEditorMode, isFeatureActive } = select( 'core/edit-post' );
const { toggleFeature } = dispatch( 'core/edit-post' );

const {
	isReordering,
	getBlockOrder: getCustomBlockOrder,
	getCurrentPage,
	getAnimatedBlocks,
} = select( 'amp/story' );

const {	setCurrentPage } = dispatch( 'amp/story' );

/**
 * Initialize editor integration.
 */
domReady( () => {
	// Ensure that the default block is page when no block is selected.
	setDefaultBlockName( 'amp/amp-story-page' );

	// Remove all blocks that aren't whitelisted.
	const disallowedBlockTypes = getBlockTypes().filter( ( { name } ) => ! ALLOWED_BLOCKS.includes( name ) );

	for ( const blockType of disallowedBlockTypes ) {
		unregisterBlockType( blockType.name );
	}

	const allBlocks = getBlocksByClientId( getClientIdsWithDescendants() );

	// Set initially shown page.
	const firstPage = allBlocks.find( ( { name } ) => name === 'amp/amp-story-page' );
	setCurrentPage( firstPage ? firstPage.clientId : undefined );

	for ( const block of allBlocks ) {
		// Load all needed fonts.
		if ( block.attributes.ampFontFamily ) {
			maybeEnqueueFontStyle( block.attributes.ampFontFamily );
		}
	}

	// Enforce fixed toolbar.
	if ( ! isFeatureActive( 'fixedToolbar' ) ) {
		toggleFeature( 'fixedToolbar' );
	}

	renderStoryComponents();

	// Prevent WritingFlow component from focusing on last text field when clicking below the carousel.
	document.querySelector( '.block-editor-writing-flow__click-redirect' ).remove();

	for ( const roundedBlock of [ 'amp/amp-story-text', 'amp/amp-story-post-author', 'amp/amp-story-post-date', 'amp/amp-story-post-title' ] ) {
		registerBlockStyle( roundedBlock, {
			name: 'rounded',
			label: __( 'Rounded', 'amp' ),
		} );
	}

	registerBlockStyle( 'amp/amp-story-text', {
		name: 'half-rounded',
		label: __( 'Half Rounded', 'amp' ),
	} );

	registerBlockStyle( 'core/image', {
		name: 'rounded',
		label: __( 'Rounded', 'amp' ),
	} );

	registerBlockStyle( 'core/quote', {
		name: 'white',
		label: __( 'White', 'amp' ),
	} );

	unregisterBlockStyle( 'core/quote', 'large' );
} );

let blockOrder = getBlockOrder();
let allBlocksWithChildren = getClientIdsWithDescendants();

let editorMode = getEditorMode();

subscribe( async () => {
	maybeInitializeAnimations();

	const defaultBlockName = getDefaultBlockName();
	const selectedBlockClientId = getSelectedBlockClientId();

	// Switch default block depending on context
	if ( selectedBlockClientId ) {
		const selectedBlock = getBlock( selectedBlockClientId );

		if ( 'amp/amp-story-page' === selectedBlock.name && 'amp/amp-story-page' !== defaultBlockName ) {
			setDefaultBlockName( 'amp/amp-story-page' );
		} else if ( 'amp/amp-story-page' !== selectedBlock.name && 'amp/amp-story-text' !== defaultBlockName ) {
			setDefaultBlockName( 'amp/amp-story-text' );
		}
	} else if ( ! selectedBlockClientId && 'amp/amp-story-page' !== defaultBlockName ) {
		setDefaultBlockName( 'amp/amp-story-page' );
	}

	const newBlockOrder = getBlockOrder();
	const newlyAddedPages = newBlockOrder.find( ( block ) => ! blockOrder.includes( block ) );
	const deletedPages = blockOrder.filter( ( block ) => ! newBlockOrder.includes( block ) );

	if ( deletedPages.includes( getCurrentPage() ) ) {
		// Change current page if it has been deleted.
		const nextIndex = Math.max( 0, blockOrder.indexOf( getCurrentPage() ) - 1 );

		blockOrder = newBlockOrder;

		setCurrentPage( blockOrder[ nextIndex ] );
	}

	blockOrder = newBlockOrder;

	// If a new page has been inserted, make it the current one.
	if ( newlyAddedPages ) {
		setCurrentPage( newlyAddedPages );
	}

	for ( const block of allBlocksWithChildren ) {
		maybeSetInitialPositioning( block );
		maybeRemoveImageCaption( block );
		maybeUpdateAutoAdvanceAfterMedia( block );
		maybeSetTagName( block );
		maybeSetInitialSize( block );
	}

	allBlocksWithChildren = getClientIdsWithDescendants();

	// Re-add controls when switching back from code to visual editor.
	const newEditorMode = getEditorMode();
	if ( 'visual' === newEditorMode && newEditorMode !== editorMode ) {
		while ( ! document.querySelector( '.editor-block-list__layout' ) ) {
			await new Promise( ( r ) => setTimeout( r, 200 ) );
		}

		renderStoryComponents();
	}

	editorMode = newEditorMode;
} );

store.subscribe( () => {
	const editorBlockOrder = getBlockOrder();
	const customBlockOrder = getCustomBlockOrder();

	// The block order has changed, let's re-order.
	if ( ! isReordering() && customBlockOrder.length > 0 && editorBlockOrder !== customBlockOrder ) {
		for ( const [ index, page ] of customBlockOrder.entries() ) {
			moveBlockToPosition( page, '', '', index );
		}
	}

	const animatedBlocks = getAnimatedBlocks();

	// Update pages and blocks based on updated animation data.
	for ( const page in animatedBlocks ) {
		if ( ! animatedBlocks.hasOwnProperty( page ) || ! getBlock( page ) ) {
			continue;
		}

		const pageAttributes = getBlockAttributes( page );

		const animatedBlocksPerPage = animatedBlocks[ page ].filter( ( { id } ) => page === getBlockRootClientId( id ) );

		const totalAnimationDuration = getTotalAnimationDuration( animatedBlocksPerPage );
		const totalAnimationDurationInSeconds = Math.ceil( totalAnimationDuration / 1000 );

		if ( 'time' === pageAttributes.autoAdvanceAfter ) {
			// Enforce minimum value for manually set time.
			if ( totalAnimationDurationInSeconds > pageAttributes.autoAdvanceAfterDuration ) {
				updateBlockAttributes( page, { autoAdvanceAfterDuration: totalAnimationDurationInSeconds } );
			}
		} else {
			updateBlockAttributes( page, { autoAdvanceAfterDuration: totalAnimationDurationInSeconds } );
		}

		for ( const item of animatedBlocksPerPage ) {
			const { id, parent, animationType, duration, delay } = item;

			const parentBlock = parent ? getBlock( parent ) : undefined;

			updateBlockAttributes( id, {
				ampAnimationAfter: parentBlock ? parentBlock.attributes.anchor : undefined,
				ampAnimationType: animationType,
				ampAnimationDuration: duration,
				ampAnimationDelay: delay,
			} );
		}
	}
} );

const plugins = require.context( './plugins', true, /.*\.js$/ );

plugins.keys().forEach( ( modulePath ) => {
	const { name, render, isActive = true } = plugins( modulePath );

	if ( isActive ) {
		registerPlugin( name, { render } );
	}
} );

addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/setBlockParent', setBlockParent );
addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/addAttributes', addAMPAttributes );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addStorySettings', withAmpStorySettings );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addPageNumber', withPageNumber );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addEditFeaturedImage', withEditFeaturedImage );
addFilter( 'editor.PostFeaturedImage', 'ampStoryEditorBlocks/addFeaturedImageNotice', withStoryFeaturedImageNotice );
addFilter( 'editor.BlockListBlock', 'ampStoryEditorBlocks/withActivePageState', withActivePageState );
addFilter( 'editor.BlockListBlock', 'ampStoryEditorBlocks/addWrapperProps', withWrapperProps );
addFilter( 'editor.MediaUpload', 'ampStoryEditorBlocks/addCroppedFeaturedImage', ( InitialMediaUpload ) => withCroppedFeaturedImage( InitialMediaUpload, getMinimumStoryPosterDimensions() ) );
addFilter( 'editor.MediaUpload', 'ampStoryEditorBlocks/addPosterImageNotice', withVideoPosterImageNotice );
addFilter( 'blocks.getSaveContent.extraProps', 'ampStoryEditorBlocks/addExtraAttributes', addAMPExtraProps );
addFilter( 'blocks.getSaveElement', 'ampStoryEditorBlocks/wrapBlocksInGridLayer', wrapBlocksInGridLayer );
addFilter( 'editor.BlockDropZone', 'ampStoryEditorBlocks/withStoryBlockDropZone', withStoryBlockDropZone );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/withCallToActionValidation', withCallToActionValidation );
addFilter( 'blocks.getBlockAttributes', 'ampStoryEditorBlocks/filterBlockAttributes', filterBlockAttributes );

const blocks = require.context( './blocks', true, /(?<!test\/)index\.js$/ );

// Block types need to be register *after* all the filters have been applied.
blocks.keys().forEach( ( modulePath ) => {
	const { name, settings } = blocks( modulePath );
	registerBlockType( name, settings );
} );
<|endoftext|>


<commit_before>/**
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	// Define changes to default configuration here.
	// For complete reference see:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
		{ name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
		{ name: 'links' },
		{ name: 'insert' },
		{ name: 'forms' },
		{ name: 'tools' },
		{ name: 'document',	   groups: [ 'mode', 'document', 'doctools' ] },
		{ name: 'others' },
		'/',
		{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
		{ name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
		{ name: 'styles' },
		{ name: 'colors' },
		{ name: 'about' }
	];

	// Remove some buttons provided by the standard plugins, which are
	// not needed in the Standard(s) toolbar.
	config.removeButtons = 'Underline,Subscript,Superscript';

	// Set the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Simplify the dialog windows.
	config.removeDialogTabs = 'image:advanced;link:advanced';

	config.extraAllowedContent = 'div[*](*); ol[*](*); li[*](*); span[*](*); h4[*](*); a[*](*); section[*](*);';

	// ALLOW empy (no text) <i> and <span> tags for glyphicon
	config.protectedSource.push(/<span[^>]*><\/span>/g);
	config.protectedSource.push(/<i[^>]*><\/i>/g);

	//custome simple cms faqItem plugin
	config.extraPlugins = 'faqItem';
};
<commit_msg>added img to extraAllowedContent<commit_after>/**
 * @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	// Define changes to default configuration here.
	// For complete reference see:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
		{ name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
		{ name: 'links' },
		{ name: 'insert' },
		{ name: 'forms' },
		{ name: 'tools' },
		{ name: 'document',	   groups: [ 'mode', 'document', 'doctools' ] },
		{ name: 'others' },
		'/',
		{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
		{ name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
		{ name: 'styles' },
		{ name: 'colors' },
		{ name: 'about' }
	];

	// Remove some buttons provided by the standard plugins, which are
	// not needed in the Standard(s) toolbar.
	config.removeButtons = 'Underline,Subscript,Superscript';

	// Set the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Simplify the dialog windows.
	config.removeDialogTabs = 'image:advanced;link:advanced';

	config.extraAllowedContent = 'div[*](*); ol[*](*); li[*](*); span[*](*); h4[*](*); a[*](*); section[*](*); img[*](*);';

	// ALLOW empy (no text) <i> and <span> tags for glyphicon
	config.protectedSource.push(/<span[^>]*><\/span>/g);
	config.protectedSource.push(/<i[^>]*><\/i>/g);

	//custome simple cms faqItem plugin
	config.extraPlugins = 'faqItem';
};
<|endoftext|>


<commit_before>ferryScheduleApp.controller('NavCtrl', function ($scope) {

  $scope.routes = [
    {id: 'clinton-mukilteo', title: 'Clinton-Mukilteo'},
    {id: 'kingston-edmonds', title: 'Kingston-Edmonds'},
    {id: 'bainbridge-seattle', title: 'Bainbridge-Seattle'},
    {id: 'bremerton-seattle', title: 'Bremerton-Seattle'}
  ];

});
<commit_msg>Updated the structure of the NavCtrl.routes model.<commit_after>ferryScheduleApp.controller('NavCtrl', function ($scope) {

  $scope.routes = [
    {id: 'clinton-mukilteo',   westPort: 'Clinton',    eastPort: 'Mukilteo'},
    {id: 'kingston-edmonds',   westPort: 'Kingston',   eastPort: 'Edmonds'},
    {id: 'bainbridge-seattle', westPort: 'Bainbridge', eastPort: 'Seattle'},
    {id: 'bremerton-seattle',  westPort: 'Bremerton',  eastPort: 'Seattle'}
  ];

});
<|endoftext|>


<commit_before>/**
 * Created by julia on 17.08.2016.
 */
var X2 = require('x2js');
var x2js = new X2();
var request = require('request');
var general = require('../../utility/general');
var rule34 = function (bot,message,messageSplit) {
    if (typeof (messageSplit[1]) !== 'undefined') {
        var messageSearch = "";
        for (var i = 1 ; i < messageSplit.length; i++) {
            if (i === 1) {
                messageSearch = messageSplit[i];
            } else {
                messageSearch = messageSearch + "%20" + messageSplit[i];
            }
        }
        request.get('http://rule34.xxx/index.php?page=dapi&s=post&q=index&tags=' + messageSearch,function (error, response, body) {
            if (error) {
                bot.reply(message, 'a error occured!');
            }
            if (!error && response.statusCode == 200) {
                var jsonObj = x2js.xml2js(body);
                if (typeof (jsonObj.posts.post) !== 'undefined') {
                    var random = general.random(0, jsonObj.posts.post.length);
                    random = Math.floor(random);
                    if (typeof (jsonObj.posts.post[random]._file_url) !== 'undefined') {
                        bot.sendMessage(message.channel, 'http:' + jsonObj.posts.post[random]._file_url, function (err, message) {
                            if (err) return console.log(err);
                        });
                    }
            } else {
                    bot.reply(message, 'No images found with Tags: ' + messageSearch.replace(/%20/g, " "));
                }
            }
        });
    } else {
        bot.reply(message, 'No Search Term entered!');
    }
};
module.exports = rule34;<commit_msg>Fixed a r34 bug<commit_after>/**
 * Created by julia on 17.08.2016.
 */
var X2 = require('x2js');
var x2js = new X2();
var request = require('request');
var general = require('../../utility/general');
var rule34 = function (bot,message,messageSplit) {
    if (typeof (messageSplit[1]) !== 'undefined') {
        var messageSearch = "";
        for (var i = 1 ; i < messageSplit.length; i++) {
            if (i === 1) {
                messageSearch = messageSplit[i];
            } else {
                messageSearch = messageSearch + "+" + messageSplit[i];
            }
        }
        request.get('http://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags=' + messageSearch,function (error, response, body) {
            if (error) {
                bot.reply(message, 'a error occured!');
            }
            if (!error && response.statusCode == 200) {
                var jsonObj = x2js.xml2js(body);
                if (typeof (jsonObj.posts.post) !== 'undefined') {
                    var random = general.random(0, jsonObj.posts.post.length);
                    random = Math.floor(random);
                    if (typeof(jsonObj.posts.post[random]) !== 'undefined' && typeof (jsonObj.posts.post[random]._file_url) !== 'undefined') {
                        bot.sendMessage(message.channel, 'http:' + jsonObj.posts.post[random]._file_url, function (err, message) {
                            if (err) return console.log(err);
                        });
                    } else {

                    }
            } else {
                    bot.reply(message, 'No images found with Tags: ' + messageSearch.replace(/%20/g, " "));
                }
            }
        });
    } else {
        bot.reply(message, 'No Search Term entered!');
    }
};
module.exports = rule34;<|endoftext|>


<commit_before>var _ = require('lodash')
var path = require('path')
var debug = require('depurar')('lanyon')
// var lanyonDir = __dirname
var projectDir = process.env.PROJECT_DIR || '../..'
var projectPackageFile = path.join(projectDir, '/package.json')
var projectPackage = require(projectPackageFile)
var lanyonPackage = require('./package.json')
var mergedCfg = _.defaults(projectPackage.lanyon || {}, lanyonPackage.lanyon)
debug({mergedCfg: mergedCfg})

module.exports = {
  'port': mergedCfg.portContent,
  'proxy': 'http://localhost:' + mergedCfg.portAssets,
  'serveStatic': [ projectDir + '/_site' ],
  'watchOptions': {
    'ignoreInitial': true,
    'ignored': [
      '.git'
    ]
  },
  'files': [
    '.'
  ],
  'reloadDelay': 200
}
<commit_msg>Fix path<commit_after>var _ = require('lodash')
var path = require('path')
var debug = require('depurar')('lanyon')
// var lanyonDir = __dirname
var projectDir = process.env.PROJECT_DIR || '../..'
var projectPackageFile = path.join(projectDir, '/package.json')
var projectPackage = require(projectPackageFile)
var lanyonPackage = require('./package.json')
var mergedCfg = _.defaults(projectPackage.lanyon || {}, lanyonPackage.lanyon)
debug({mergedCfg: mergedCfg})

module.exports = {
  'port': mergedCfg.portContent,
  'proxy': 'http://localhost:' + mergedCfg.portAssets,
  'serveStatic': [ projectDir + '/_site' ],
  'watchOptions': {
    'ignoreInitial': true,
    'ignored': [
      '.git'
    ]
  },
  'files': [
    projectDir + '/_site'
  ],
  'reloadDelay': 200
}
<|endoftext|>


<commit_before>import React from 'react';
import { Message } from 'retranslate';
import { PropTypes as Types } from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import StatusBoxRow from './statusBoxRow';

export const StatusBox = ({
  conversion,
  memberNumber,
  age,
  loading,
  secondPillarFunds,
  thirdPillarFunds,
}) => {
  const joinTulevaSoon = age >= 49;
  const joinTuleva2 = !(
    conversion.secondPillar.selectionComplete && conversion.secondPillar.transfersComplete
  );
  const joinTuleva3 = !(
    conversion.thirdPillar.selectionComplete && conversion.thirdPillar.transfersComplete
  );

  const isTulevaMember = memberNumber != null;

  const tulevaData = isTulevaMember
    ? [<Message params={{ memberNumber }}>account.member.statement</Message>]
    : [<Message>account.non.member.statement</Message>];

  return (
    <>

              <Message>account.status.choices</Message>

        <StatusBoxRow
          ok={!joinTuleva2 && !joinTulevaSoon}
          showAction={!loading}
          name={<Message>account.status.choice.pillar.second</Message>}
          lines={secondPillarFunds.filter(fund => fund.activeFund).map(({ name }) => name)}
        >
          {joinTuleva2 && !joinTulevaSoon && (
            <Link to="/2nd-pillar-flow" className="btn btn-light">
              <Message>account.status.choice.join.tuleva.2</Message>
            </Link>
          )}

          {joinTulevaSoon && (

                <Message>account.status.choice.1970.coming.soon</Message>

          )}
        </StatusBoxRow>

        <StatusBoxRow
          ok={!joinTuleva3}
          showAction={!loading}
          name={<Message>account.status.choice.pillar.third</Message>}
          lines={thirdPillarFunds.filter(fund => fund.activeFund).map(({ name }) => name)}
        >
          {joinTuleva3 && (
            <Link to="/3rd-pillar-flow" className="btn btn-light">
              <Message>account.status.choice.join.tuleva.3</Message>
            </Link>
          )}
        </StatusBoxRow>

        <StatusBoxRow
          last
          ok={isTulevaMember}
          showAction={!loading}
          name={<Message>account.status.choice.tuleva</Message>}
          lines={tulevaData}
        >
          {!isTulevaMember && (

                <Message>account.status.choice.join.tuleva</Message>

          )}
        </StatusBoxRow>

    </>
  );
};

StatusBox.defaultProps = {
  memberNumber: null,
  age: null,
  conversion: {},
  loading: false,
  secondPillarFunds: [],
  thirdPillarFunds: [],
};

StatusBox.propTypes = {
  memberNumber: Types.number,
  age: Types.number,
  conversion: Types.shape({}),
  loading: Types.bool,
  secondPillarFunds: Types.arrayOf(Types.shape({})),
  thirdPillarFunds: Types.arrayOf(Types.shape({})),
};

const mapStateToProps = state => ({
  memberNumber: (state.login.user || {}).memberNumber,
  age: (state.login.user || {}).age,
  conversion: state.login.userConversion,
  loading: state.login.loadingUserConversion,
  secondPillarFunds: state.exchange.sourceFunds,
  thirdPillarFunds: state.thirdPillar.sourceFunds,
});

export default connect(mapStateToProps)(StatusBox);
<commit_msg>Remove age logic from the status box<commit_after>import React from 'react';
import { Message } from 'retranslate';
import { PropTypes as Types } from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import StatusBoxRow from './statusBoxRow';

export const StatusBox = ({
  conversion,
  memberNumber,
  loading,
  secondPillarFunds,
  thirdPillarFunds,
}) => {
  const joinTuleva2 = !(
    conversion.secondPillar.selectionComplete && conversion.secondPillar.transfersComplete
  );
  const joinTuleva3 = !(
    conversion.thirdPillar.selectionComplete && conversion.thirdPillar.transfersComplete
  );

  const isTulevaMember = memberNumber != null;

  const tulevaData = isTulevaMember
    ? [<Message params={{ memberNumber }}>account.member.statement</Message>]
    : [<Message>account.non.member.statement</Message>];

  return (
    <>

              <Message>account.status.choices</Message>

        <StatusBoxRow
          ok={!joinTuleva2}
          showAction={!loading}
          name={<Message>account.status.choice.pillar.second</Message>}
          lines={secondPillarFunds.filter(fund => fund.activeFund).map(({ name }) => name)}
        >
          {joinTuleva2 && (
            <Link to="/2nd-pillar-flow" className="btn btn-light">
              <Message>account.status.choice.join.tuleva.2</Message>
            </Link>
          )}
        </StatusBoxRow>

        <StatusBoxRow
          ok={!joinTuleva3}
          showAction={!loading}
          name={<Message>account.status.choice.pillar.third</Message>}
          lines={thirdPillarFunds.filter(fund => fund.activeFund).map(({ name }) => name)}
        >
          {joinTuleva3 && (
            <Link to="/3rd-pillar-flow" className="btn btn-light">
              <Message>account.status.choice.join.tuleva.3</Message>
            </Link>
          )}
        </StatusBoxRow>

        <StatusBoxRow
          last
          ok={isTulevaMember}
          showAction={!loading}
          name={<Message>account.status.choice.tuleva</Message>}
          lines={tulevaData}
        >
          {!isTulevaMember && (

                <Message>account.status.choice.join.tuleva</Message>

          )}
        </StatusBoxRow>

    </>
  );
};

StatusBox.defaultProps = {
  memberNumber: null,
  conversion: {},
  loading: false,
  secondPillarFunds: [],
  thirdPillarFunds: [],
};

StatusBox.propTypes = {
  memberNumber: Types.number,
  conversion: Types.shape({}),
  loading: Types.bool,
  secondPillarFunds: Types.arrayOf(Types.shape({})),
  thirdPillarFunds: Types.arrayOf(Types.shape({})),
};

const mapStateToProps = state => ({
  memberNumber: (state.login.user || {}).memberNumber,
  conversion: state.login.userConversion,
  loading: state.login.loadingUserConversion,
  secondPillarFunds: state.exchange.sourceFunds,
  thirdPillarFunds: state.thirdPillar.sourceFunds,
});

export default connect(mapStateToProps)(StatusBox);
<|endoftext|>


<commit_before>$(function() {
    var geocoder = new google.maps.Geocoder();
    var data2;

    $.ajax({
        type: "POST",
        url: "placesnames",
        cache: false,
        dataType: 'json',
        success: function(data) {
            data2 = data;
            $(".search").keyup(function() {
                //$( ".search" ).addClass( "ui-autocomplete-loading" );
                $("#autocomplete-result").empty();
                var searchid = $(this).val();
                if (searchid != '') {
                    getAddress(searchid);
                    getPlaces(searchid);

                }
                return false;
            });
        }
    });

    function getPlaces(name) {
        var checkedFood = $("#food-checkbox").is(":checked");
        var checkedDrink = $("#drink-checkbox").is(":checked");
        var checkedAll = checkedFood ^ checkedDrink;
        for (var i = 0; i < data2.length; i++) {
            if (data2[i].placeName.toLowerCase().indexOf(name) != -1) {
                var category = data2[i].category.toLowerCase();
                if (checkedFood && category != "food" && checkedAll) {
                    continue;
                }
                if (checkedDrink && category != "drink" && checkedAll) {
                    continue;
                }
                var div = $('<div/>', {
                    class: "show",
                    align: "left"
                });
                var span = $('<span/>', {
                    class: "name",
                    text: data2[i].placeName
                });
                var category = data2[i].category ? data2[i].category : "food";
                var icon = $('<div/>', {
                    class: category.toLowerCase() + " category",
                });
                $(div).append(icon);
                $(div).append(span);
                $("#autocomplete-result").append(div);
            }
        }
    }

//    function getAddress(name) {
//        var addr = $('<div/>', {
//            id: "addr-auto"
//        });
//        $("#autocomplete-result").append(addr);
//        address = name + " ,Cluj Napoca, Romania";
//        geocoder.geocode({'address': address}, function(results, status) {
//            if (status == google.maps.GeocoderStatus.OK) {
//                res = results[0].formatted_address;
//                //for (var i = 0; i < results.length; i++) {
//                latitude = results[0].geometry.location.lat();
//                longitude = results[0].geometry.location.lng();
//                $("#search-lat").val(latitude);
//                $("#search-lng").val(longitude);
//                var addr = results[0].formatted_address;
////                    if (i > 0) {
////                        res2 = results[i].formatted_address;
////                    } else {
////                        res2 = "";
////                    }
////                    if (res != res2) {
//                var span = $('<span/>', {
//                    class: "name",
//                    text: addr
//                });
//                var div = $('<div/>', {
//                    class: "show",
//                    align: "left",
//                });
//                var icon = $('<div/>', {
//                    class: "address-marker",
//                });
//                $(div).append(icon);
//                $(div).append(span);
//                $("#addr-auto").append(div);
//                // }
//                //  }
//            }
//        });
//
//    }

    function getAddress(name) {

        var addr = $('<div/>', {
            id: "addr-auto"
                    //text: ""
        });
        $("#autocomplete-result").append(addr);

        var request = {
            input: name ,
            //bounds: defaultBounds,
            types: ['geocode'],
            componentRestrictions: {country: 'ro'}

        };
        var nr = 0;
        autocomplete.getPlacePredictions(request, function(predictions, status) {
            if (status === google.maps.places.PlacesServiceStatus.OK) {
                for (var i = 0; i < predictions.length; i++) {
                    var loc = predictions[i].description;
                    if (loc.indexOf("Cluj-Napoca") != -1) {
                        var span = $('<span/>', {
                            class: "name",
                            text: loc
                        });
                        var div = $('<div/>', {
                            class: "show",
                            align: "left",
                        });
                        var icon = $('<div/>', {
                            class: "address-marker",
                        });
                        $(div).append(icon);
                        $(div).append(span);
                        nr++;
                        $("#addr-auto").append(div);
                      break;
                    }
                }
            }
        });
    }

    jQuery("#autocomplete-result").on("click", function(e) {
        var $clicked = $(e.target);
        //var $name = $clicked.parent().find('.name').html();
        //alert($name);
        var $name = $clicked.find('.name').html();
        if (typeof $name == 'undefined') {
            $name = $clicked.parent().find('.name').html();
        }
        //alert($name);
        var decoded = $("<div/>").html($name).text();
        $('#searchh').val(decoded);
    });
    jQuery(document).on("click", function(e) {
        var $clicked = $(e.target);
        if (!$clicked.hasClass("search")) {
            jQuery("#autocomplete-result").fadeOut();
        }
    });
    $('#searchh').click(function() {
        jQuery("#autocomplete-result").fadeIn();
    });

});<commit_msg>fixed autocomplete<commit_after>$(function() {
    var geocoder = new google.maps.Geocoder();
    var data2;

    $.ajax({
        type: "POST",
        url: "placesnames",
        cache: false,
        dataType: 'json',
        success: function(data) {
            data2 = data;
            $(".search").keyup(function() {
                //$( ".search" ).addClass( "ui-autocomplete-loading" );
                $("#autocomplete-result").empty();
                var searchid = $(this).val();
                if (searchid != '') {
                    getAddress(searchid);
                    getPlaces(searchid);

                }
                return false;
            });
        }
    });

    function getPlaces(name) {
        var checkedFood = $("#food-checkbox").is(":checked");
        var checkedDrink = $("#drink-checkbox").is(":checked");
        var checkedAll = checkedFood ^ checkedDrink;
        for (var i = 0; i < data2.length; i++) {
            if (data2[i].placeName.toLowerCase().indexOf(name) != -1) {
                var category = data2[i].category.toLowerCase();
                if (checkedFood && category != "food" && checkedAll) {
                    continue;
                }
                if (checkedDrink && category != "drink" && checkedAll) {
                    continue;
                }
                var div = $('<div/>', {
                    class: "show",
                    align: "left"
                });
                var span = $('<span/>', {
                    class: "name",
                    text: data2[i].placeName
                });
                var category = data2[i].category ? data2[i].category : "food";
                var icon = $('<div/>', {
                    class: category.toLowerCase() + " category",
                });
                $(div).append(icon);
                $(div).append(span);
                $("#autocomplete-result").append(div);
            }
        }
    }

//    function getAddress(name) {
//        var addr = $('<div/>', {
//            id: "addr-auto"
//        });
//        $("#autocomplete-result").append(addr);
//        address = name + " ,Cluj Napoca, Romania";
//        geocoder.geocode({'address': address}, function(results, status) {
//            if (status == google.maps.GeocoderStatus.OK) {
//                res = results[0].formatted_address;
//                //for (var i = 0; i < results.length; i++) {
//                latitude = results[0].geometry.location.lat();
//                longitude = results[0].geometry.location.lng();
//                $("#search-lat").val(latitude);
//                $("#search-lng").val(longitude);
//                var addr = results[0].formatted_address;
////                    if (i > 0) {
////                        res2 = results[i].formatted_address;
////                    } else {
////                        res2 = "";
////                    }
////                    if (res != res2) {
//                var span = $('<span/>', {
//                    class: "name",
//                    text: addr
//                });
//                var div = $('<div/>', {
//                    class: "show",
//                    align: "left",
//                });
//                var icon = $('<div/>', {
//                    class: "address-marker",
//                });
//                $(div).append(icon);
//                $(div).append(span);
//                $("#addr-auto").append(div);
//                // }
//                //  }
//            }
//        });
//
//    }

    function getAddress(name) {

        var addr = $('<div/>', {
            id: "addr-auto"
                    //text: ""
        });
        $("#autocomplete-result").append(addr);

          var autocomplete = new google.maps.places.AutocompleteService();

        var request = {
            input: name ,
            //bounds: defaultBounds,
            types: ['geocode'],
            componentRestrictions: {country: 'ro'}

        };
        var nr = 0;
        autocomplete.getPlacePredictions(request, function(predictions, status) {
            if (status === google.maps.places.PlacesServiceStatus.OK) {
                for (var i = 0; i < predictions.length; i++) {
                    var loc = predictions[i].description;
                    if (loc.indexOf("Cluj-Napoca") != -1) {
                        var span = $('<span/>', {
                            class: "name",
                            text: loc
                        });
                        var div = $('<div/>', {
                            class: "show",
                            align: "left",
                        });
                        var icon = $('<div/>', {
                            class: "address-marker",
                        });
                        $(div).append(icon);
                        $(div).append(span);
                        nr++;
                        $("#addr-auto").append(div);
                      break;
                    }
                }
            }
        });
    }

    jQuery("#autocomplete-result").on("click", function(e) {
        var $clicked = $(e.target);
        //var $name = $clicked.parent().find('.name').html();
        //alert($name);
        var $name = $clicked.find('.name').html();
        if (typeof $name == 'undefined') {
            $name = $clicked.parent().find('.name').html();
        }
        //alert($name);
        var decoded = $("<div/>").html($name).text();
        $('#searchh').val(decoded);
    });
    jQuery(document).on("click", function(e) {
        var $clicked = $(e.target);
        if (!$clicked.hasClass("search")) {
            jQuery("#autocomplete-result").fadeOut();
        }
    });
    $('#searchh').click(function() {
        jQuery("#autocomplete-result").fadeIn();
    });

});<|endoftext|>


<commit_before>var React = require('react');

// Enable React Touch Events
React.initializeTouchEvents(true);

function getTouchProps(touch) {
	if (!touch) return {};
	return {
		pageX: touch.pageX,
		pageY: touch.pageY,
		clientX: touch.clientX,
		clientY: touch.clientY
	};
}

function isDataOrAriaProp(key) {
	return key.indexOf('data-') === 0 || key.indexOf('aria-') === 0;
}

function getPinchProps(touches) {
	return {
		touches: Array.prototype.map.call(touches, function copyTouch(touch) {
			return { identifier: touch.identifier, pageX: touch.pageX, pageY: touch.pageY };
		}),
		center: { x: (touches[0].pageX + touches[1].pageX) / 2, y: (touches[0].pageY + touches[1].pageY) / 2 },
		angle: Math.atan() * (touches[1].pageY - touches[0].pageY) / (touches[1].pageX - touches[0].pageX) * 180 / Math.PI,
		distance: Math.sqrt(Math.pow(Math.abs(touches[1].pageX - touches[0].pageX), 2) + Math.pow(Math.abs(touches[1].pageY - touches[0].pageY), 2))
	};
}

var extend = require('react/lib/Object.assign');

/**
 * Tappable Mixin
 * ==============
 */

var Mixin = {
	propTypes: {
		moveThreshold: React.PropTypes.number,       // pixels to move before cancelling tap
		pressDelay: React.PropTypes.number,          // ms to wait before detecting a press
		pressMoveThreshold: React.PropTypes.number,  // pixels to move before cancelling press
		preventDefault: React.PropTypes.bool,        // whether to preventDefault on all events
		stopPropagation: React.PropTypes.bool,       // whether to stopPropagation on all events

		onTap: React.PropTypes.func,                 // fires when a tap is detected
		onPress: React.PropTypes.func,               // fires when a press is detected
		onTouchStart: React.PropTypes.func,          // pass-through touch event
		onTouchMove: React.PropTypes.func,           // pass-through touch event
		onTouchEnd: React.PropTypes.func,            // pass-through touch event
		onMouseDown: React.PropTypes.func,           // pass-through mouse event
		onMouseUp: React.PropTypes.func,             // pass-through mouse event
		onMouseMove: React.PropTypes.func,           // pass-through mouse event
		onMouseOut: React.PropTypes.func,            // pass-through mouse event

		onPinchStart: React.PropTypes.func,          // fires when a pinch gesture is started
		onPinchMove: React.PropTypes.func,           // fires on every touch-move when a pinch action is active
		onPinchEnd: React.PropTypes.func             // fires when a pinch action ends
	},

	getDefaultProps: function() {
		return {
			moveThreshold: 100,
			pressDelay: 1000,
			pressMoveThreshold: 5
		};
	},

	getInitialState: function() {
		return {
			isActive: false,
			touchActive: false,
			pinchActive: false
		};
	},

	componentWillUnmount: function() {
		this.cleanupScrollDetection();
		this.cancelPressDetection();
	},

	processEvent: function(event) {
		if (this.props.preventDefault) event.preventDefault();
		if (this.props.stopPropagation) event.stopPropagation();
	},

	onTouchStart: function(event) {
		if (this.props.onTouchStart && this.props.onTouchStart(event) === false) return;
		this.processEvent(event);
		window._blockMouseEvents = true;

		if (event.touches.length === 1) {
			this._initialTouch = this._lastTouch = getTouchProps(event.touches[0]);
			this.initScrollDetection();
			this.initPressDetection(this.endTouch);
			this.setState({
				isActive: true
			});
		} else if ((this.props.onPinchStart || this.props.onPinchMove || this.props.onPinchEnd) && event.touches.length === 2) {
			this.onPinchStart(event);
		}
	},

	onPinchStart: function(event) {
		// in case the two touches didn't start exactly at the same time
		if (this._initialTouch) this.endTouch();

		var touches = event.touches;

		this._initialPinch = getPinchProps(touches);

		this._initialPinch = extend(this._initialPinch, {
			displacement: { x: 0, y: 0 },
			displacementVelocity: { x: 0, y: 0 },
			rotation: 0,
			rotationVelocity: 0,
			zoom: 1,
			zoomVelocity: 0,
			time: Date.now()
		});

		this._lastPinch = this._initialPinch;

		this.props.onPinchStart && this.props.onPinchStart(this._initialPinch, event);
	},

	onPinchMove: function(event) {
		if (this._initialTouch) this.endTouch();

		var touches = event.touches;

		if(touches.length !== 2){
			return this.onPinchEnd(event) // bail out before disaster
		}

		var currentPinch =
			touches[0].identifier === this._initialPinch.touches[0].identifier && touches[1].identifier === this._initialPinch.touches[1].identifier ?
				getPinchProps(touches) // the touches are in the correct order
			: touches[1].identifier === this._initialPinch.touches[0].identifier && touches[0].identifier === this._initialPinch.touches[1].identifier ?
				getPinchProps(touches.reverse()) // the touches have somehow changed order
			:
				getPinchProps(touches); // something is wrong, but we still have two touch-points, so we try not to fail

		currentPinch.displacement = {
			x: currentPinch.center.x - this._initialPinch.center.x,
			y: currentPinch.center.y - this._initialPinch.center.y
		};

		currentPinch.time = Date.now();
		var timeSinceLastPinch = currentPinch.time - this._lastPinch.time;

		currentPinch.displacementVelocity = {
			x: (currentPinch.displacement.x - this._lastPinch.displacement.x) / timeSinceLastPinch,
			y: (currentPinch.displacement.y - this._lastPinch.displacement.y) / timeSinceLastPinch
		};

		currentPinch.rotation = currentPinch.angle - this._initialPinch.angle;
		currentPinch.rotationVelocity = currentPinch.rotation - this._lastPinch.rotation / timeSinceLastPinch;

		currentPinch.zoom = currentPinch.distance / this._initialPinch.distance;
		currentPinch.zoomVelocity = (currentPinch.zoom - this._lastPinch.zoom) / timeSinceLastPinch;

		this.props.onPinchMove && this.props.onPinchMove(currentPinch, event);

		this._lastPinch = currentPinch;
	},

	onPinchEnd: function(event) {
		// TODO use helper to order touches by identifier and use actual values on touchEnd.
		var currentPinch = extend({}, this._lastPinch);
		currentPinch.time = Date.now();

		if (currentPinch.time - this._lastPinch.time > 16) {
			currentPinch.displacementVelocity = 0;
			currentPinch.rotationVelocity = 0;
			currentPinch.zoomVelocity = 0;
		}

		this.props.onPinchEnd && this.props.onPinchEnd(currentPinch, event);

		this._initialPinch = this._lastPinch = null;

		// If one finger is still on screen, it should start a new touch event for swiping etc
		// But it should never fire an onTap or onPress event.
		// Since there is no support swipes yet, this should be disregarded for now
		// if (event.touches.length === 1) {
		// 	this.onTouchStart(event);
		// }
	},

	initScrollDetection: function() {
		this._scrollParents = [];
		this._scrollPos = { top: 0, left: 0 };
		var node = this.getDOMNode();
		while (node) {
			if (node.scrollHeight > node.offsetHeight || node.scrollWidth > node.offsetWidth) {
				this._scrollParents.push(node);
				this._scrollPos.top += node.scrollTop;
				this._scrollPos.left += node.scrollLeft;
			}
			node = node.parentNode;
		}
	},

	calculateMovement: function(touch) {
		return {
			x: Math.abs(touch.clientX - this._initialTouch.clientX),
			y: Math.abs(touch.clientY - this._initialTouch.clientY)
		};
	},

	detectScroll: function() {
		var currentScrollPos = { top: 0, left: 0 };
		for (var i = 0; i < this._scrollParents.length; i++) {
			currentScrollPos.top += this._scrollParents[i].scrollTop;
			currentScrollPos.left += this._scrollParents[i].scrollLeft;
		}
		return !(currentScrollPos.top === this._scrollPos.top && currentScrollPos.left === this._scrollPos.left);
	},

	cleanupScrollDetection: function() {
		this._scrollParents = undefined;
		this._scrollPos = undefined;
	},

	initPressDetection: function(callback) {
		if (!this.props.onPress) return;
		this._pressTimeout = setTimeout(function() {
			this.props.onPress();
			callback();
		}.bind(this), this.props.pressDelay);
	},

	cancelPressDetection: function() {
		clearTimeout(this._pressTimeout);
	},

	onTouchMove: function(event) {
		if (this._initialTouch) {
			this.processEvent(event);

			if (this.detectScroll()) return this.endTouch(event);

			this.props.onTouchMove && this.props.onTouchMove(event);
			this._lastTouch = getTouchProps(event.touches[0]);
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x > this.props.pressMoveThreshold || movement.y > this.props.pressMoveThreshold) {
				this.cancelPressDetection();
			}
			if (movement.x > this.props.moveThreshold || movement.y > this.props.moveThreshold) {
				if (this.state.isActive) {
					this.setState({
						isActive: false
					});
				}
			} else {
				if (!this.state.isActive) {
					this.setState({
						isActive: true
					});
				}
			}
		} else if (this._initialPinch && event.touches.length === 2) {
			this.onPinchMove(event);
			event.preventDefault();
		}
	},

	onTouchEnd: function(event) {
		if (this._initialTouch) {
			this.processEvent(event);
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x <= this.props.moveThreshold && movement.y <= this.props.moveThreshold && this.props.onTap) {
				this.props.onTap(event);
			}
			this.endTouch(event);
		} else if (this._initialPinch && (event.touches.length + event.changedTouches.length) === 2) {
			this.onPinchEnd(event);
			event.preventDefault();
		}
	},

	endTouch: function(event) {
		this.cancelPressDetection();
		if (event && this.props.onTouchEnd) this.props.onTouchEnd(event);
		this._initialTouch = null;
		this._lastTouch = null;
		this.setState({
			isActive: false
		});
	},

	onMouseDown: function(event) {
		if (window._blockMouseEvents) {
			window._blockMouseEvents = false;
			return;
		}
		if (this.props.onMouseDown && this.props.onMouseDown(event) === false) return;
		this.processEvent(event);
		this.initPressDetection(this.endMouseEvent);
		this._mouseDown = true;
		this.setState({
			isActive: true
		});
	},

	onMouseMove: function(event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseMove && this.props.onMouseMove(event);
	},

	onMouseUp: function(event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseUp && this.props.onMouseUp(event);
		this.props.onTap && this.props.onTap(event);
		this.endMouseEvent();
	},

	onMouseOut: function(event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseOut && this.props.onMouseOut(event);
		this.endMouseEvent();
	},

	endMouseEvent: function() {
		this.cancelPressDetection();
		this._mouseDown = false;
		this.setState({
			isActive: false
		});
	},

	touchStyles: function() {
		return {
			WebkitTapHighlightColor: 'rgba(0,0,0,0)',
			WebkitTouchCallout: 'none',
			WebkitUserSelect: 'none',
			KhtmlUserSelect: 'none',
			MozUserSelect: 'none',
			msUserSelect: 'none',
			userSelect: 'none',
			cursor: 'pointer'
		};
	},

	handlers: function() {
		return {
			onTouchStart: this.onTouchStart,
			onTouchMove: this.onTouchMove,
			onTouchEnd: this.onTouchEnd,
			onMouseDown: this.onMouseDown,
			onMouseUp: this.onMouseUp,
			onMouseMove: this.onMouseMove,
			onMouseOut: this.onMouseOut
		};
	}
};

/**
 * Tappable Component
 * ==================
 */

var component = React.createClass({

	displayName: 'Tappable',

	mixins: [Mixin],

	propTypes: {
		component: React.PropTypes.any,           // component to create
		className: React.PropTypes.string,        // optional className
		classBase: React.PropTypes.string,        // base for generated classNames
		style: React.PropTypes.object,            // additional style properties for the component
		disabled: React.PropTypes.bool            // only applies to buttons
	},

	getDefaultProps: function() {
		return {
			component: 'span',
			classBase: 'Tappable'
		};
	},

	render: function() {
		var props = this.props;
		var className = props.classBase + (this.state.isActive ? '-active' : '-inactive');

		if (props.className) {
			className += ' ' + props.className;
		}

		var style = {};
		extend(style, this.touchStyles(), props.style);

		var newComponentProps = extend({}, props, {
			style: style,
			className: className,
			disabled: props.disabled,
			handlers: this.handlers
		}, this.handlers());

		delete newComponentProps.onTap;
		delete newComponentProps.onPress;
		delete newComponentProps.onPinchStart;
		delete newComponentProps.onPinchMove;
		delete newComponentProps.onPinchEnd;
		delete newComponentProps.moveThreshold;
		delete newComponentProps.pressDelay;
		delete newComponentProps.pressMoveThreshold;
		delete newComponentProps.preventDefault;
		delete newComponentProps.stopPropagation;
		delete newComponentProps.component;

		return React.createElement(props.component, newComponentProps, props.children);
	}
});

component.Mixin = Mixin;
module.exports = component;
<commit_msg>Padding event to onPress handler, fixes #25<commit_after>var React = require('react');

// Enable React Touch Events
React.initializeTouchEvents(true);

function getTouchProps(touch) {
	if (!touch) return {};
	return {
		pageX: touch.pageX,
		pageY: touch.pageY,
		clientX: touch.clientX,
		clientY: touch.clientY
	};
}

function isDataOrAriaProp(key) {
	return key.indexOf('data-') === 0 || key.indexOf('aria-') === 0;
}

function getPinchProps(touches) {
	return {
		touches: Array.prototype.map.call(touches, function copyTouch(touch) {
			return { identifier: touch.identifier, pageX: touch.pageX, pageY: touch.pageY };
		}),
		center: { x: (touches[0].pageX + touches[1].pageX) / 2, y: (touches[0].pageY + touches[1].pageY) / 2 },
		angle: Math.atan() * (touches[1].pageY - touches[0].pageY) / (touches[1].pageX - touches[0].pageX) * 180 / Math.PI,
		distance: Math.sqrt(Math.pow(Math.abs(touches[1].pageX - touches[0].pageX), 2) + Math.pow(Math.abs(touches[1].pageY - touches[0].pageY), 2))
	};
}

var extend = require('react/lib/Object.assign');

/**
 * Tappable Mixin
 * ==============
 */

var Mixin = {
	propTypes: {
		moveThreshold: React.PropTypes.number,       // pixels to move before cancelling tap
		pressDelay: React.PropTypes.number,          // ms to wait before detecting a press
		pressMoveThreshold: React.PropTypes.number,  // pixels to move before cancelling press
		preventDefault: React.PropTypes.bool,        // whether to preventDefault on all events
		stopPropagation: React.PropTypes.bool,       // whether to stopPropagation on all events

		onTap: React.PropTypes.func,                 // fires when a tap is detected
		onPress: React.PropTypes.func,               // fires when a press is detected
		onTouchStart: React.PropTypes.func,          // pass-through touch event
		onTouchMove: React.PropTypes.func,           // pass-through touch event
		onTouchEnd: React.PropTypes.func,            // pass-through touch event
		onMouseDown: React.PropTypes.func,           // pass-through mouse event
		onMouseUp: React.PropTypes.func,             // pass-through mouse event
		onMouseMove: React.PropTypes.func,           // pass-through mouse event
		onMouseOut: React.PropTypes.func,            // pass-through mouse event

		onPinchStart: React.PropTypes.func,          // fires when a pinch gesture is started
		onPinchMove: React.PropTypes.func,           // fires on every touch-move when a pinch action is active
		onPinchEnd: React.PropTypes.func             // fires when a pinch action ends
	},

	getDefaultProps: function() {
		return {
			moveThreshold: 100,
			pressDelay: 1000,
			pressMoveThreshold: 5
		};
	},

	getInitialState: function() {
		return {
			isActive: false,
			touchActive: false,
			pinchActive: false
		};
	},

	componentWillUnmount: function() {
		this.cleanupScrollDetection();
		this.cancelPressDetection();
	},

	processEvent: function(event) {
		if (this.props.preventDefault) event.preventDefault();
		if (this.props.stopPropagation) event.stopPropagation();
	},

	onTouchStart: function(event) {
		if (this.props.onTouchStart && this.props.onTouchStart(event) === false) return;
		this.processEvent(event);
		window._blockMouseEvents = true;

		if (event.touches.length === 1) {
			this._initialTouch = this._lastTouch = getTouchProps(event.touches[0]);
			this.initScrollDetection();
			this.initPressDetection(event, this.endTouch);
			this.setState({
				isActive: true
			});
		} else if ((this.props.onPinchStart || this.props.onPinchMove || this.props.onPinchEnd) && event.touches.length === 2) {
			this.onPinchStart(event);
		}
	},

	onPinchStart: function(event) {
		// in case the two touches didn't start exactly at the same time
		if (this._initialTouch) this.endTouch();

		var touches = event.touches;

		this._initialPinch = getPinchProps(touches);

		this._initialPinch = extend(this._initialPinch, {
			displacement: { x: 0, y: 0 },
			displacementVelocity: { x: 0, y: 0 },
			rotation: 0,
			rotationVelocity: 0,
			zoom: 1,
			zoomVelocity: 0,
			time: Date.now()
		});

		this._lastPinch = this._initialPinch;

		this.props.onPinchStart && this.props.onPinchStart(this._initialPinch, event);
	},

	onPinchMove: function(event) {
		if (this._initialTouch) this.endTouch();

		var touches = event.touches;

		if(touches.length !== 2){
			return this.onPinchEnd(event) // bail out before disaster
		}

		var currentPinch =
			touches[0].identifier === this._initialPinch.touches[0].identifier && touches[1].identifier === this._initialPinch.touches[1].identifier ?
				getPinchProps(touches) // the touches are in the correct order
			: touches[1].identifier === this._initialPinch.touches[0].identifier && touches[0].identifier === this._initialPinch.touches[1].identifier ?
				getPinchProps(touches.reverse()) // the touches have somehow changed order
			:
				getPinchProps(touches); // something is wrong, but we still have two touch-points, so we try not to fail

		currentPinch.displacement = {
			x: currentPinch.center.x - this._initialPinch.center.x,
			y: currentPinch.center.y - this._initialPinch.center.y
		};

		currentPinch.time = Date.now();
		var timeSinceLastPinch = currentPinch.time - this._lastPinch.time;

		currentPinch.displacementVelocity = {
			x: (currentPinch.displacement.x - this._lastPinch.displacement.x) / timeSinceLastPinch,
			y: (currentPinch.displacement.y - this._lastPinch.displacement.y) / timeSinceLastPinch
		};

		currentPinch.rotation = currentPinch.angle - this._initialPinch.angle;
		currentPinch.rotationVelocity = currentPinch.rotation - this._lastPinch.rotation / timeSinceLastPinch;

		currentPinch.zoom = currentPinch.distance / this._initialPinch.distance;
		currentPinch.zoomVelocity = (currentPinch.zoom - this._lastPinch.zoom) / timeSinceLastPinch;

		this.props.onPinchMove && this.props.onPinchMove(currentPinch, event);

		this._lastPinch = currentPinch;
	},

	onPinchEnd: function(event) {
		// TODO use helper to order touches by identifier and use actual values on touchEnd.
		var currentPinch = extend({}, this._lastPinch);
		currentPinch.time = Date.now();

		if (currentPinch.time - this._lastPinch.time > 16) {
			currentPinch.displacementVelocity = 0;
			currentPinch.rotationVelocity = 0;
			currentPinch.zoomVelocity = 0;
		}

		this.props.onPinchEnd && this.props.onPinchEnd(currentPinch, event);

		this._initialPinch = this._lastPinch = null;

		// If one finger is still on screen, it should start a new touch event for swiping etc
		// But it should never fire an onTap or onPress event.
		// Since there is no support swipes yet, this should be disregarded for now
		// if (event.touches.length === 1) {
		// 	this.onTouchStart(event);
		// }
	},

	initScrollDetection: function() {
		this._scrollParents = [];
		this._scrollPos = { top: 0, left: 0 };
		var node = this.getDOMNode();
		while (node) {
			if (node.scrollHeight > node.offsetHeight || node.scrollWidth > node.offsetWidth) {
				this._scrollParents.push(node);
				this._scrollPos.top += node.scrollTop;
				this._scrollPos.left += node.scrollLeft;
			}
			node = node.parentNode;
		}
	},

	calculateMovement: function(touch) {
		return {
			x: Math.abs(touch.clientX - this._initialTouch.clientX),
			y: Math.abs(touch.clientY - this._initialTouch.clientY)
		};
	},

	detectScroll: function() {
		var currentScrollPos = { top: 0, left: 0 };
		for (var i = 0; i < this._scrollParents.length; i++) {
			currentScrollPos.top += this._scrollParents[i].scrollTop;
			currentScrollPos.left += this._scrollParents[i].scrollLeft;
		}
		return !(currentScrollPos.top === this._scrollPos.top && currentScrollPos.left === this._scrollPos.left);
	},

	cleanupScrollDetection: function() {
		this._scrollParents = undefined;
		this._scrollPos = undefined;
	},

	initPressDetection: function(event, callback) {
		if (!this.props.onPress) return;
		this._pressTimeout = setTimeout(function() {
			this.props.onPress(event);
			callback();
		}.bind(this), this.props.pressDelay);
	},

	cancelPressDetection: function() {
		clearTimeout(this._pressTimeout);
	},

	onTouchMove: function(event) {
		if (this._initialTouch) {
			this.processEvent(event);

			if (this.detectScroll()) return this.endTouch(event);

			this.props.onTouchMove && this.props.onTouchMove(event);
			this._lastTouch = getTouchProps(event.touches[0]);
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x > this.props.pressMoveThreshold || movement.y > this.props.pressMoveThreshold) {
				this.cancelPressDetection();
			}
			if (movement.x > this.props.moveThreshold || movement.y > this.props.moveThreshold) {
				if (this.state.isActive) {
					this.setState({
						isActive: false
					});
				}
			} else {
				if (!this.state.isActive) {
					this.setState({
						isActive: true
					});
				}
			}
		} else if (this._initialPinch && event.touches.length === 2) {
			this.onPinchMove(event);
			event.preventDefault();
		}
	},

	onTouchEnd: function(event) {
		if (this._initialTouch) {
			this.processEvent(event);
			var movement = this.calculateMovement(this._lastTouch);
			if (movement.x <= this.props.moveThreshold && movement.y <= this.props.moveThreshold && this.props.onTap) {
				this.props.onTap(event);
			}
			this.endTouch(event);
		} else if (this._initialPinch && (event.touches.length + event.changedTouches.length) === 2) {
			this.onPinchEnd(event);
			event.preventDefault();
		}
	},

	endTouch: function(event) {
		this.cancelPressDetection();
		if (event && this.props.onTouchEnd) this.props.onTouchEnd(event);
		this._initialTouch = null;
		this._lastTouch = null;
		this.setState({
			isActive: false
		});
	},

	onMouseDown: function(event) {
		if (window._blockMouseEvents) {
			window._blockMouseEvents = false;
			return;
		}
		if (this.props.onMouseDown && this.props.onMouseDown(event) === false) return;
		this.processEvent(event);
		this.initPressDetection(event, this.endMouseEvent);
		this._mouseDown = true;
		this.setState({
			isActive: true
		});
	},

	onMouseMove: function(event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseMove && this.props.onMouseMove(event);
	},

	onMouseUp: function(event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseUp && this.props.onMouseUp(event);
		this.props.onTap && this.props.onTap(event);
		this.endMouseEvent();
	},

	onMouseOut: function(event) {
		if (window._blockMouseEvents || !this._mouseDown) return;
		this.processEvent(event);
		this.props.onMouseOut && this.props.onMouseOut(event);
		this.endMouseEvent();
	},

	endMouseEvent: function() {
		this.cancelPressDetection();
		this._mouseDown = false;
		this.setState({
			isActive: false
		});
	},

	touchStyles: function() {
		return {
			WebkitTapHighlightColor: 'rgba(0,0,0,0)',
			WebkitTouchCallout: 'none',
			WebkitUserSelect: 'none',
			KhtmlUserSelect: 'none',
			MozUserSelect: 'none',
			msUserSelect: 'none',
			userSelect: 'none',
			cursor: 'pointer'
		};
	},

	handlers: function() {
		return {
			onTouchStart: this.onTouchStart,
			onTouchMove: this.onTouchMove,
			onTouchEnd: this.onTouchEnd,
			onMouseDown: this.onMouseDown,
			onMouseUp: this.onMouseUp,
			onMouseMove: this.onMouseMove,
			onMouseOut: this.onMouseOut
		};
	}
};

/**
 * Tappable Component
 * ==================
 */

var component = React.createClass({

	displayName: 'Tappable',

	mixins: [Mixin],

	propTypes: {
		component: React.PropTypes.any,           // component to create
		className: React.PropTypes.string,        // optional className
		classBase: React.PropTypes.string,        // base for generated classNames
		style: React.PropTypes.object,            // additional style properties for the component
		disabled: React.PropTypes.bool            // only applies to buttons
	},

	getDefaultProps: function() {
		return {
			component: 'span',
			classBase: 'Tappable'
		};
	},

	render: function() {
		var props = this.props;
		var className = props.classBase + (this.state.isActive ? '-active' : '-inactive');

		if (props.className) {
			className += ' ' + props.className;
		}

		var style = {};
		extend(style, this.touchStyles(), props.style);

		var newComponentProps = extend({}, props, {
			style: style,
			className: className,
			disabled: props.disabled,
			handlers: this.handlers
		}, this.handlers());

		delete newComponentProps.onTap;
		delete newComponentProps.onPress;
		delete newComponentProps.onPinchStart;
		delete newComponentProps.onPinchMove;
		delete newComponentProps.onPinchEnd;
		delete newComponentProps.moveThreshold;
		delete newComponentProps.pressDelay;
		delete newComponentProps.pressMoveThreshold;
		delete newComponentProps.preventDefault;
		delete newComponentProps.stopPropagation;
		delete newComponentProps.component;

		return React.createElement(props.component, newComponentProps, props.children);
	}
});

component.Mixin = Mixin;
module.exports = component;
<|endoftext|>


<commit_before>(function($)
{
    $.fn.obslugaFormularzy = function()
    {
        var $collectionHolder;

        var $addLink = $('Dodaj');
        var $newLinkLi = $('

').append($addLink);

        var $this = $(this);

        $collectionHolder = $this.find('ul');

        $collectionHolder.find('li').each(function() {
            addFormDeleteLink($(this));
        });

        $collectionHolder.append($newLinkLi);

        $collectionHolder.data('index', $collectionHolder.find(':input').length);

        $addLink.on('click',function(e) {
            e.preventDefault();

            addForm($collectionHolder, $newLinkLi);
        });

        $this.on('focusin','input[type=datetime]', function()
        {
            $(this).datetimepicker({dateFormat: "yy-mm-dd"});
        });

        function addForm($collectionHolder, $newLinkLi)
        {
            var prototype = $collectionHolder.data('prototype');

            var index = $collectionHolder.data('index');

            var newForm = prototype.replace(/__name__/g, index);

            $collectionHolder.data('index', index + 1);

            var $newFormLi = $('

').append(newForm);
            $newLinkLi.before($newFormLi);

            addFormDeleteLink($newFormLi);
        }

        function addFormDeleteLink($FormLi)
        {
            var $removeForm = $('Usuń ');

            $FormLi.append($removeForm);

            $removeForm.on('click', function(e)
            {
                e.preventDefault();

                $FormLi.remove();
            })
        }

    }

    $.fn.qTipHelper = function(options)
    {
        var $this = $(this);

        var settings = $.extend({
            ajax: false,
            przypisz_do: '',
            url: ''
        },options);

        var qTipOptionsDefaults = {
            prerender: true,
            style: {
                widget: true,
                def: false
            },
            position: {
                my: 'bottom right',
                at: 'top center',
                adjust: {
                    y: -10
                },
                effect: false
            },
            show: {
                event: 'click mouseover',
                solo: true
            },
            hide: {
                event: 'unfocus'
            }
        };

        if(settings.ajax == false)
        {
            $this.qtip(qTipOptionsDefaults);
        }else{
            var qTipOptions = $.extend({
                overwrite: false, // Make sure the tooltip won't be overridden once created
                content: {
                    text: function(event, api)
                    {
                        return $.ajax({
                            url: settings.url,
                            type: 'GET',
                            dataType: 'json',
                            data: {
                                id: $(this).val()
                            }
                        })
                        .then(function(content)
                        {
                            return content.opis
                        },function(xhr, sttus, error){
                            api.set('content.text', status + ': ' + error)
                        })
                    }
                },
                show: false
/*                show: {
                    ready: true // Show the tooltip as soon as it's bound, vital so it shows up the first time you hover!
                }*/
            }, qTipOptionsDefaults);

            var $helperContainer = $this.find('.'+settings.przypisz_do);
/*            $helperContainer.on('mouseover','select', function(event){
//                $(this).qtip(qTipOptions, event);
            })*/
            var tooltips = $helperContainer.qtip(qTipOptions);

            $helperContainer.on('change','select',function(event){
                $(this).qtip('destroy',true);
                $(this).qtip(qTipOptions, event);
/*                var tooltips = $(this).qtip(qTipOptions);
                var api = tooltips.qtip('api');
                api.toggle(true);*/
            })
            .each(function(i) {
                $.attr(this, 'oldtitle', $.attr(this, 'title'));
                this.removeAttribute('title');
            });

        }

    }
})(jQuery);<commit_msg>Finalne opracowanie funkcji podpowiedzi pobieranych przy wykorzystaniu ajax.<commit_after>(function($)
{
    $.fn.obslugaFormularzy = function()
    {
        var $collectionHolder;

        var $addLink = $('Dodaj');
        var $newLinkLi = $('

').append($addLink);

        var $this = $(this);

        $collectionHolder = $this.find('ul');

        $collectionHolder.find('li').each(function() {
            addFormDeleteLink($(this));
        });

        $collectionHolder.append($newLinkLi);

        $collectionHolder.data('index', $collectionHolder.find(':input').length);

        $addLink.on('click',function(e) {
            e.preventDefault();

            addForm($collectionHolder, $newLinkLi);
        });

        $this.on('focusin','input[type=datetime]', function()
        {
            $(this).datetimepicker({dateFormat: "yy-mm-dd"});
        });

        function addForm($collectionHolder, $newLinkLi)
        {
            var prototype = $collectionHolder.data('prototype');

            var index = $collectionHolder.data('index');

            var newForm = prototype.replace(/__name__/g, index);

            $collectionHolder.data('index', index + 1);

            var $newFormLi = $('

').append(newForm);
            $newLinkLi.before($newFormLi);

            addFormDeleteLink($newFormLi);
        }

        function addFormDeleteLink($FormLi)
        {
            var $removeForm = $('Usuń ');

            $FormLi.append($removeForm);

            $removeForm.on('click', function(e)
            {
                e.preventDefault();

                $FormLi.remove();
            })
        }

    };

    $.fn.qTipHelper = function(options)
    {
        var $this = $(this);

        var settings = $.extend({
            ajax: false,
            przypisz_do: '',
            url: ''
        },options);

        var qTipOptionsDefaults = {
            prerender: true,
            style: {
                widget: true,
                def: false
            },
            position: {
                my: 'bottom right',
                at: 'top center',
                adjust: {
                    y: -10
                },
                effect: false
            },
            show: {
                event: 'click mouseover',
                solo: true
            },
            hide: {
                event: 'unfocus'
            }
        };

        if(settings.ajax == false)
        {
            $this.qtip(qTipOptionsDefaults);
        }else{
            var qTipOptions = $.extend( {},qTipOptionsDefaults,{
                overwrite: false,
                content: {
                    text: function(event, api)
                    {
                        return $.ajax({
                            url: settings.url,
                            type: 'GET',
                            dataType: 'json',
                            data: {
                                id: $(this).val()
                            }
                        })
                        .then(function(content)
                        {
                            return content.opis;
                        },function(xhr, status, error){
                            api.set('content.text', status + ': ' + error)
                        })
                    }
                },
                show: {
                    ready: true
                },
                position: {
                }
            });

            var $helperContainer = $this.find('.'+settings.przypisz_do);

            $helperContainer.on('mouseover','select', function(event){
                $(this).qtip(qTipOptions, event);
            });

            $helperContainer.on('change','select',function(event){
                $(this).qtip('destroy', true);
                var tooltip = $(this).qtip(qTipOptions, event);
                var api = tooltip.qtip('api');
                api.show();
            })
            .each(function() {
                $.attr(this, 'oldtitle', $.attr(this, 'title'));
                this.removeAttribute('title');
            });

        }

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


<commit_before>import React, { Component } from "react"
import IconButton from "material-ui/IconButton"
import NavigateBefore from "material-ui-icons/NavigateBefore"
import NavigateNext from "material-ui-icons/NavigateNext"
import MoreVert from "material-ui-icons/MoreVert"
import Menu, { MenuItem } from "material-ui/Menu"
import { withStyles, createStyleSheet } from "material-ui/styles"
import PropTypes from "prop-types"
import AppBar from "material-ui/AppBar"
import Toolbar from "material-ui/Toolbar"
import Typography from "material-ui/Typography"
import { monthNames } from "./utils/Strings"
import { getWeekDateRange, getWeekOfMonth, getWeeksOfMonth } from "./utils/DateHelper"

const styleSheet = createStyleSheet("SimpleAppBar", theme => ({
  root: {
    position: "relative",
    marginTop: 30,
    width: "100%"
  },
  appBar: {
    position: "relative"
  },
  toolbar: {
    display: "flex",
    justifyContent: "space-between"
  },
  paginator: {
    display: "flex",
    justifyContent: "center",
    alignItems: "center"
  },
  icons: {
    color: "white"
  },
  dateRange: {
    width: 120
  }
}))

class Titlebar extends Component {
  state = {
    anchorEl: undefined,
    open: false
  }

  handleClick = event => {
    this.setState({ open: true, anchorEl: event.currentTarget })
  }

  handleRequestClose = () => {
    this.setState({ open: false })
  }

  paginateForward = () => {
    //Remove the following once Kajuan helps me with stuff
    let termEnd = new Date(1498449600)
    console.log(termEnd)

    const endMonth = termEnd.getMonth()
    const endYear = termEnd.getFullYear()
    const endDay = termEnd.getDate()
    const endWeek = getWeekOfMonth(endYear, endMonth, endDay)
    let dateObj = this.props.currentDateRange

    switch (this.props.calendarType) {
      case "monthview":
        if( dateObj.month === endMonth){
          alert("end of term reached")
          return
        }
        if (dateObj.year === 11){
          console.log("It is December")
          dateObj.year++
          dateObj.month = 0
          this.props.changeDateRange(dateObj)
        }else{
          console.log("paginate normally")
          dateObj.month++
          this.props.changeDateRange(dateObj)
        }

        break;

      case "weekview":
      case "scheduleview":

        if( dateObj.month === endMonth && dateObj.week === endWeek){
          alert("end of term reached")
        }else{
          let dayOfMonth = new Date(dateObj.year, dateObj.month, dateObj.day)
          if (getWeeksOfMonth(dayOfMonth) === dateObj.week){
            dateObj.month++
            dateObj.week = 1
            this.props.changeDateRange(dateObj)
          }else{
            dateObj.week++
            this.props.changeDateRange(dateObj)
        }

        break;
    }

  }
  }

  getDateRange = () => {
    let text
    const classes = this.props.classes
    const dateObj = this.props.currentDateRange
    if (this.props.calendarType === "weekview") {
      text =
        monthNames[dateObj.month] +
        " " +
        getWeekDateRange(dateObj.month, dateObj.year, dateObj.week)
    } else if (this.props.calendarType === "monthview") {
      text = monthNames[dateObj.month]
    }

    return (
      <Typography type="title" className={classes.dateRange} colorInherit>
        {text}
      </Typography>
    )
  }

  render() {
    const classes = this.props.classes
    return (
      <AppBar className={classes.appBar}>
        <Toolbar className={classes.toolbar}>

            <IconButton aria-label="Paginate Backward">
              <NavigateBefore className={classes.icons} />
            </IconButton>
            {this.getDateRange()}
            <IconButton
              aria-label="Paginate Forward"
              onClick={this.paginateForward}
            >
              <NavigateNext className={classes.icons} />
            </IconButton>

          <IconButton
            aria-label="More options and views"
            onClick={this.handleClick}
          >
            <MoreVert style={{ color: "white" }} />
          </IconButton>

          <Menu
            anchorEl={this.state.anchorEl}
            open={this.state.open}
            onRequestClose={this.handleRequestClose}
          >
            <MenuItem onClick={this.handleRequestClose}>Month View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Week View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Day View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Schedule View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Download ICal</MenuItem>
          </Menu>
        </Toolbar>
      </AppBar>
    )
  }
}

Titlebar.propTypes = {
  classes: PropTypes.object.isRequired
}

export default withStyles(styleSheet)(Titlebar)
<commit_msg>Pagination backward seems to work #1<commit_after>import React, { Component } from "react"
import IconButton from "material-ui/IconButton"
import NavigateBefore from "material-ui-icons/NavigateBefore"
import NavigateNext from "material-ui-icons/NavigateNext"
import MoreVert from "material-ui-icons/MoreVert"
import Menu, { MenuItem } from "material-ui/Menu"
import { withStyles, createStyleSheet } from "material-ui/styles"
import PropTypes from "prop-types"
import AppBar from "material-ui/AppBar"
import Toolbar from "material-ui/Toolbar"
import Typography from "material-ui/Typography"
import { monthNames } from "./utils/Strings"
import { getWeekDateRange, getWeekOfMonth, getWeeksOfMonth } from "./utils/DateHelper"

const styleSheet = createStyleSheet("SimpleAppBar", theme => ({
  root: {
    position: "relative",
    marginTop: 30,
    width: "100%"
  },
  appBar: {
    position: "relative"
  },
  toolbar: {
    display: "flex",
    justifyContent: "space-between"
  },
  paginator: {
    display: "flex",
    justifyContent: "center",
    alignItems: "center"
  },
  icons: {
    color: "white"
  },
  dateRange: {
    width: 120
  }
}))

class Titlebar extends Component {
  state = {
    anchorEl: undefined,
    open: false
  }

  handleClick = event => {
    this.setState({ open: true, anchorEl: event.currentTarget })
  }

  handleRequestClose = () => {
    this.setState({ open: false })
  }

  paginateForward = () => {
    //Remove the following once Kajuan helps me with stuff
    let termEnd = new Date(1498449600)
    console.log(termEnd)

    const endMonth = termEnd.getMonth()
    const endYear = termEnd.getFullYear()
    const endDay = termEnd.getDate()
    const endWeek = getWeekOfMonth(endYear, endMonth, endDay)
    let dateObj = this.props.currentDateRange

    switch (this.props.calendarType) {
      case "monthview":
        if( dateObj.month === endMonth){
          alert("end of term reached")
          return
        }
        if (dateObj.month === 11){
          console.log("It is December")
          dateObj.year++
          dateObj.month = 0
          this.props.changeDateRange(dateObj)
        }else{
          console.log("paginate normally")
          dateObj.month++
          this.props.changeDateRange(dateObj)
        }

        break;

      case "weekview":
      case "scheduleview":

        if( dateObj.month === endMonth && dateObj.week === endWeek){
          alert("end of term reached")
        }else{
          let dayOfMonth = new Date(dateObj.year, dateObj.month, dateObj.day)
          if (getWeeksOfMonth(dayOfMonth) === dateObj.week){
            dateObj.month++
            dateObj.week = 1
            this.props.changeDateRange(dateObj)
          }else{
            dateObj.week++
            this.props.changeDateRange(dateObj)
        }

        break;
        }
    }
  }

  paginateBackward = () => {
    //Remove the following once Kajuan helps me with stuff
    let termStart = new Date(1433333600)
    console.log(termStart)

    const startMonth = termStart.getMonth()
    const startYear = termStart.getFullYear()
    const startDay = termStart.getDate()
    const startWeek = getWeekOfMonth(startYear, startMonth, startDay)
    let dateObj = this.props.currentDateRange

    switch (this.props.calendarType) {
      case "monthview":
        if( dateObj.month === startMonth){
          alert("start of term reached")
          return
        }
        if (dateObj.year === 0){
          console.log("It is January")
          dateObj.year--
          dateObj.month = 11
          this.props.changeDateRange(dateObj)
        }else{
          console.log("paginate normally")
          dateObj.month--
          this.props.changeDateRange(dateObj)
        }

        break;

      case "weekview":
      case "scheduleview":

        if( dateObj.month === startMonth && dateObj.week === startWeek){
          alert("start of term reached")
        }else{
          let dayOfMonth = new Date(dateObj.year, dateObj.month, dateObj.day)
          if (dateObj.week === 1){
            dateObj.month--
            dayOfMonth = new Date(dateObj.year, dateObj.month, 1)
            dateObj.week = getWeeksOfMonth(dayOfMonth)
            this.props.changeDateRange(dateObj)
          }else{
            dateObj.week--
            this.props.changeDateRange(dateObj)
        }

        break;
    }

    }
  }

  getDateRange = () => {
    let text
    const classes = this.props.classes
    const dateObj = this.props.currentDateRange
    if (this.props.calendarType === "weekview") {
      text =
        monthNames[dateObj.month] +
        " " +
        getWeekDateRange(dateObj.month, dateObj.year, dateObj.week)
    } else if (this.props.calendarType === "monthview") {
      text = monthNames[dateObj.month]
    }

    return (
      <Typography type="title" className={classes.dateRange} colorInherit>
        {text}
      </Typography>
    )
  }

  render() {
    const classes = this.props.classes
    return (
      <AppBar className={classes.appBar}>
        <Toolbar className={classes.toolbar}>

            <IconButton aria-label="Paginate Backward" onClick={this.paginateBackward}>
              <NavigateBefore className={classes.icons} />
            </IconButton>
            {this.getDateRange()}
            <IconButton
              aria-label="Paginate Forward"
              onClick={this.paginateForward}
            >
              <NavigateNext className={classes.icons} />
            </IconButton>

          <IconButton
            aria-label="More options and views"
            onClick={this.handleClick}
          >
            <MoreVert style={{ color: "white" }} />
          </IconButton>

          <Menu
            anchorEl={this.state.anchorEl}
            open={this.state.open}
            onRequestClose={this.handleRequestClose}
          >
            <MenuItem onClick={this.handleRequestClose}>Month View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Week View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Day View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Schedule View</MenuItem>
            <MenuItem onClick={this.handleRequestClose}>Download ICal</MenuItem>
          </Menu>
        </Toolbar>
      </AppBar>
    )
  }
}

Titlebar.propTypes = {
  classes: PropTypes.object.isRequired
}

export default withStyles(styleSheet)(Titlebar)
<|endoftext|>