<commit_before>var participants;		//people currently running an instance of the hangout
var queue;				//list of participant ids waiting to speak. 0 is the current speaker
var timeOut;			//unix time of when the current speaker's turn will end
var currentSpeakerId;	//id of the current speaker; on updates if it doesn't match queue, manager sets new time

var greenDot = gapi.hangout.av.effects.createImageResource('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB90BDwMNIxL4LdEAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAuNJREFUeNrtmy2M2mAYx3/tTsxchliWnDi1kAxBhsE0aTBkbkPg0Ljhlp1CYnF3Dj03wbBnSJOaMywTXLKcOkGyICBnJrhsog9Lj7Xlo3y078s/qSx9/z+e9/N5XoMdy3Z5BpwBOaAgTw44B14CM2AC3ANDYCDPEBg5Fo+7bJ+xI9MvgBJQB97H/Lke0AH6jsU0sQBsFwMoAs0tmI6C0QJuHIs/iQAgxsvAFwnpfWgM1IDruCCMmObfAl+B1xxGd0DVsfi+VwC2y3MJxU8kQ22g6Vj83jkA2+UN8AM4IVmaAXnH4nadl8w1zX+Q6Slp5pE2DaWN2wdgu3wEuiRfXWnr9gDYLp+BS9KjS2lz/DFAaKbJvF8Nx+JqYwDSn7qkWxXH4tvaAGS0H6KGcmGzgxExzz8kdLTfdIo8DVonhA2CLYXMz6fI1koRIMvbAWqqsLhsNgI2Nj8PuLbfx94h699ALXaBssLmEW/lwAiQf//XHre0h9IYeDWPAn8EFDUwj3gsBnWBJvqo+aQLyBneBL2UcSym8wgooZ9K/i5Q1xBAHcCQc/sZeurExEta6KozEy9Lo6tyJl6qSlcVjgCOXcDL0uqqcxPIaAwgY6K5TA33AH5NTLzKDF11b6LO0fcmGpqoewC6igZHAMcuACONAYxMqcPraWi+51g8zhdCHQ0BdOYLIYC+hgD6/wBIBWZPs/Cf+iMAQrKniqrl3wvMdYOXNlJdY/H6FIDkymoaAKhFZYev8VLIqupOPBIIQMhUFQZQXSyu/u9ARCoo2gqabwcVVYedCDVRK1s0IyT7HQhAqqnyCgHIh1WSh54JSl1dRQHzlagK8shDUamwbKTYfCOqSnQpAIFwBVyk0PzFsjphWOPCRMqKphurmF8LgEBIQ/F0ZVnYbwxAIOh7ZcY3O5wmbLHUxiuGvl33Re2vzcXKDcqHs8C7PW+lx/LNbBzzsSNgIRr0vDobAkO/y9MRMBJ9ff4vhV3btM/DqFkAAAAASUVORK5CYII=');
var greenDotOverlay = greenDot.createOverlay(
	{'scale':
		{'magnitude': 0.15, 'reference': gapi.hangout.av.effects.ScaleReference.WIDTH}});

var yellowDot = gapi.hangout.av.effects.createImageResource('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB90BDwMXCA5pLkoAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAuFJREFUeNrtmyts21AUhj97BiPVCiZLBUVzpAVUKykuqca2gLDgsoVNKwoMDWtZ8NhAFloSXJJpIJXmooJIVkCjkoFbbcAnk5vZzsN52Pfml8yS+P5fzn2ecy3WrMB3XgAHQBk4lqcMHAKvAQU8APfAAOjLMwCGrqee1tk+a02mXwGnwDnwIePPdYE20HM9Nc4tgMB3LOAEaKzAdBqMJnDjeupPLgCI8TPgq4T0JjQCasB1VhBWRvPvgG/AG7ajO6DqeurHRgEEvvNSQvEz+VALaLie+r12AIHvvAV+Ag75kgKOXE/dLvIle0HzH2V6ypt5pE0DaePqAQS+8wnokH91pK2rAxD4zhfgkuLoUtqcfQwQmkUyH1Xd9dTV0gCkP3Uotiqup74vDEBG+wF6qJw0O1gp8/xjTkf7ZafIvbh1QtIg2NTI/GSKbM4VAbK87aOnjqeXzVbMxubXFtf2m9g7lKIbqOkucKaxecTbWWwEyL8fbHBLuy2NAHcSBdEIODHAPOLxJK4LNDBHjWddQM7wHjBL+66nxpMIOMU8nUa7wLmBAM4BLDm3V5gpxyZMWpiqA5swS2OqyjZhqspUHe8A7LpAmKU1VYc2sG8wgH0bw2UbuAeI6sEmrMwwVfc2+hx9L6OBjb4HoPOovwOw6wIwNBjA0JY6vK6B5ruup54mC6G2gQDak4UQQM9AAL1/AKQCs2tY+I+jEQAJ2VNN1YzuBSa6IUwb6a6ReH0OQHJlNQMA1NKyw9eEKWRddSceiQUgZKoaA6hOF1f/dyAiFRQtDc234oqqd0VScZ+WDx5p9O8fJVWSJ54JSl1dRQPzlbQK8tRDUamwrBfYfD2tSnQmAIFwBVwU0PzFrDrhxEEwYWAsUtF0fR7zCwEQCEUonq7MCvulAQgEc6/MRGaHvZwtlloyz98u+kXjr81lyg3Ki0vA+w1vpUfyzlIW85kjYCoazLw6mwDDvMvTKTByfX3+L4KL/xorzXR/AAAAAElFTkSuQmCC');
	var yellowDotOverlay = yellowDot.createOverlay(
	{'scale':
		{'magnitude': 0.15, 'reference': gapi.hangout.av.effects.ScaleReference.WIDTH}});

var buttonDisabled = false;	//true when button is clicked to prevent joining the queue several times

gapi.hangout.onApiReady.add(function(eventObj){
	if (eventObj.isApiReady) {
		participants = gapi.hangout.getEnabledParticipants();
		console.log(participants);
		printParticipants();

		gapi.hangout.onParticipantsChanged.add(onParticipantsChange);
		gapi.hangout.data.onStateChanged.add(onDataChange);
	}
});

function onParticipantsChange(eventObj) {
	participants = eventObj.participants;
	printParticipants();
};

function onDataChange (eventObj){
	var state = gapi.hangout.data.getState();
	queue = JSON.parse(state.queue);
	timeOut = JSON.parse(state.timeOut);
}

function onServerUpdate(){
	printParticipants();
	clearOverlay();
	var queuePosition = currentQueuePosition(gapi.hangout.getParticipantId());
	if (queuePosition == 0){
		placeGreenDot();
	}
	else if (queuePosition != -1){
		placeYellowDot();
	}

	//lowest order participant manages time updates
	//and checks for disconnected queue memembers
	if (isManager()){
		console.log("managing update...");

	}
}

function printParticipants(){
	var members = "";
	for (var i = 0; i < participants.length; i++){
		members = members + participants[i].person.displayName;
	}
	document.getElementById('particpantsList').innerHTML = members;
}

function buttonClick(){
	if (!buttonDisabled){
		buttonDisabled = true;
		var queuePosition = currentQueuePosition(gapi.hangout.getParticipantId());
		if (queuePosition == 0){
			queue.shift();
			gapi.hangout.submitDelta({'queue':JSON.stringify(queue)});
		}
		else if (queuePosition == -1){
			queue.push(gapi.hangout.getParticipantId());
			gapi.hangout.submitDelta({'queue':JSON.stringify(queue)});
		}
	}
}

function placeGreenDot(){
	greenDotOverlay.setPosition(.4, -.35);
	greenDotOverlay.setVisible(true);
}

function placeYellowDot(){
	yellowDotOverlay.setPosition(.4, -.35);
	yellowDotOverlay.setVisible(true);
}

function clearOverlay(){
	greenDotOverlay.setVisible(false);
	yellowDotOverlay.setVisible(false);
}

//returns the passed id place in the queue
//-1 if they are not currently in the queue
function currentQueuePosition(id){
	var rv = -1;
	for (var i = 0; i < queue.length; i++){
		if (queue[i].id == id){
			rv = i;
		}
	}
	return rv;
}

function isManager(){
	return (participants[0].person.id == gapi.hangout.getParticipantId());
}<commit_msg>queue starts as an empty array<commit_after>var participants;		//people currently running an instance of the hangout
var queue = [];				//list of participant ids waiting to speak. 0 is the current speaker
var timeOut;			//unix time of when the current speaker's turn will end
var currentSpeakerId;	//id of the current speaker; on updates if it doesn't match queue, manager sets new time

var greenDot = gapi.hangout.av.effects.createImageResource('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB90BDwMNIxL4LdEAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAuNJREFUeNrtmy2M2mAYx3/tTsxchliWnDi1kAxBhsE0aTBkbkPg0Ljhlp1CYnF3Dj03wbBnSJOaMywTXLKcOkGyICBnJrhsog9Lj7Xlo3y078s/qSx9/z+e9/N5XoMdy3Z5BpwBOaAgTw44B14CM2AC3ANDYCDPEBg5Fo+7bJ+xI9MvgBJQB97H/Lke0AH6jsU0sQBsFwMoAs0tmI6C0QJuHIs/iQAgxsvAFwnpfWgM1IDruCCMmObfAl+B1xxGd0DVsfi+VwC2y3MJxU8kQ22g6Vj83jkA2+UN8AM4IVmaAXnH4nadl8w1zX+Q6Slp5pE2DaWN2wdgu3wEuiRfXWnr9gDYLp+BS9KjS2lz/DFAaKbJvF8Nx+JqYwDSn7qkWxXH4tvaAGS0H6KGcmGzgxExzz8kdLTfdIo8DVonhA2CLYXMz6fI1koRIMvbAWqqsLhsNgI2Nj8PuLbfx94h699ALXaBssLmEW/lwAiQf//XHre0h9IYeDWPAn8EFDUwj3gsBnWBJvqo+aQLyBneBL2UcSym8wgooZ9K/i5Q1xBAHcCQc/sZeurExEta6KozEy9Lo6tyJl6qSlcVjgCOXcDL0uqqcxPIaAwgY6K5TA33AH5NTLzKDF11b6LO0fcmGpqoewC6igZHAMcuACONAYxMqcPraWi+51g8zhdCHQ0BdOYLIYC+hgD6/wBIBWZPs/Cf+iMAQrKniqrl3wvMdYOXNlJdY/H6FIDkymoaAKhFZYev8VLIqupOPBIIQMhUFQZQXSyu/u9ARCoo2gqabwcVVYedCDVRK1s0IyT7HQhAqqnyCgHIh1WSh54JSl1dRQHzlagK8shDUamwbKTYfCOqSnQpAIFwBVyk0PzFsjphWOPCRMqKphurmF8LgEBIQ/F0ZVnYbwxAIOh7ZcY3O5wmbLHUxiuGvl33Re2vzcXKDcqHs8C7PW+lx/LNbBzzsSNgIRr0vDobAkO/y9MRMBJ9ff4vhV3btM/DqFkAAAAASUVORK5CYII=');
var greenDotOverlay = greenDot.createOverlay(
	{'scale':
		{'magnitude': 0.15, 'reference': gapi.hangout.av.effects.ScaleReference.WIDTH}});

var yellowDot = gapi.hangout.av.effects.createImageResource('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB90BDwMXCA5pLkoAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAuFJREFUeNrtmyts21AUhj97BiPVCiZLBUVzpAVUKykuqca2gLDgsoVNKwoMDWtZ8NhAFloSXJJpIJXmooJIVkCjkoFbbcAnk5vZzsN52Pfml8yS+P5fzn2ecy3WrMB3XgAHQBk4lqcMHAKvAQU8APfAAOjLMwCGrqee1tk+a02mXwGnwDnwIePPdYE20HM9Nc4tgMB3LOAEaKzAdBqMJnDjeupPLgCI8TPgq4T0JjQCasB1VhBWRvPvgG/AG7ajO6DqeurHRgEEvvNSQvEz+VALaLie+r12AIHvvAV+Ag75kgKOXE/dLvIle0HzH2V6ypt5pE0DaePqAQS+8wnokH91pK2rAxD4zhfgkuLoUtqcfQwQmkUyH1Xd9dTV0gCkP3Uotiqup74vDEBG+wF6qJw0O1gp8/xjTkf7ZafIvbh1QtIg2NTI/GSKbM4VAbK87aOnjqeXzVbMxubXFtf2m9g7lKIbqOkucKaxecTbWWwEyL8fbHBLuy2NAHcSBdEIODHAPOLxJK4LNDBHjWddQM7wHjBL+66nxpMIOMU8nUa7wLmBAM4BLDm3V5gpxyZMWpiqA5swS2OqyjZhqspUHe8A7LpAmKU1VYc2sG8wgH0bw2UbuAeI6sEmrMwwVfc2+hx9L6OBjb4HoPOovwOw6wIwNBjA0JY6vK6B5ruup54mC6G2gQDak4UQQM9AAL1/AKQCs2tY+I+jEQAJ2VNN1YzuBSa6IUwb6a6ReH0OQHJlNQMA1NKyw9eEKWRddSceiQUgZKoaA6hOF1f/dyAiFRQtDc234oqqd0VScZ+WDx5p9O8fJVWSJ54JSl1dRQPzlbQK8tRDUamwrBfYfD2tSnQmAIFwBVwU0PzFrDrhxEEwYWAsUtF0fR7zCwEQCEUonq7MCvulAQgEc6/MRGaHvZwtlloyz98u+kXjr81lyg3Ki0vA+w1vpUfyzlIW85kjYCoazLw6mwDDvMvTKTByfX3+L4KL/xorzXR/AAAAAElFTkSuQmCC');
	var yellowDotOverlay = yellowDot.createOverlay(
	{'scale':
		{'magnitude': 0.15, 'reference': gapi.hangout.av.effects.ScaleReference.WIDTH}});

var buttonDisabled = false;	//true when button is clicked to prevent joining the queue several times

gapi.hangout.onApiReady.add(function(eventObj){
	if (eventObj.isApiReady) {
		participants = gapi.hangout.getEnabledParticipants();
		console.log(participants);
		printParticipants();

		gapi.hangout.onParticipantsChanged.add(onParticipantsChange);
		gapi.hangout.data.onStateChanged.add(onDataChange);
	}
});

function onParticipantsChange(eventObj) {
	participants = eventObj.participants;
	printParticipants();
};

function onDataChange (eventObj){
	var state = gapi.hangout.data.getState();
	queue = JSON.parse(state.queue);
	timeOut = JSON.parse(state.timeOut);
}

function onServerUpdate(){
	printParticipants();
	clearOverlay();
	var queuePosition = currentQueuePosition(gapi.hangout.getParticipantId());
	if (queuePosition == 0){
		placeGreenDot();
	}
	else if (queuePosition != -1){
		placeYellowDot();
	}

	//lowest order participant manages time updates
	//and checks for disconnected queue memembers
	if (isManager()){
		console.log("managing update...");

	}
}

function printParticipants(){
	var members = "";
	for (var i = 0; i < participants.length; i++){
		members = members + participants[i].person.displayName;
	}
	document.getElementById('particpantsList').innerHTML = members;
}

function buttonClick(){
	if (!buttonDisabled){
		buttonDisabled = true;
		var queuePosition = currentQueuePosition(gapi.hangout.getParticipantId());
		if (queuePosition == 0){
			queue.shift();
			gapi.hangout.submitDelta({'queue':JSON.stringify(queue)});
		}
		else if (queuePosition == -1){
			queue.push(gapi.hangout.getParticipantId());
			gapi.hangout.submitDelta({'queue':JSON.stringify(queue)});
		}
	}
}

function placeGreenDot(){
	greenDotOverlay.setPosition(.4, -.35);
	greenDotOverlay.setVisible(true);
}

function placeYellowDot(){
	yellowDotOverlay.setPosition(.4, -.35);
	yellowDotOverlay.setVisible(true);
}

function clearOverlay(){
	greenDotOverlay.setVisible(false);
	yellowDotOverlay.setVisible(false);
}

//returns the passed id place in the queue
//-1 if they are not currently in the queue
function currentQueuePosition(id){
	var rv = -1;
	for (var i = 0; i < queue.length; i++){
		if (queue[i].id == id){
			rv = i;
		}
	}
	return rv;
}

function isManager(){
	return (participants[0].person.id == gapi.hangout.getParticipantId());
}<|endoftext|>


<commit_before>/**
 * WPDashboardPopularPages component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { MODULES_ANALYTICS, DATE_RANGE_OFFSET } from '../../modules/analytics/datastore/constants';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import PreviewBlock from '../PreviewBlock';
import ReportError from '../ReportError';
import { numFmt } from '../../util';
import TableOverflowContainer from '../../components/TableOverflowContainer';
import { getDataTableFromData } from '../../components/data-table';
const { useSelect } = Data;

const WPDashboardPopularPages = () => {
	const dateRangeDates = useSelect( ( select ) => select( CORE_USER ).getDateRangeDates( {
		compare: true,
		offsetDays: DATE_RANGE_OFFSET,
	} ) );

	const reportArgs = {
		...dateRangeDates,
		metrics: [
			{
				expression: 'ga:pageviews',
				alias: 'Pageviews',
			},
		],
		dimensions: [
			'ga:pageTitle',
			'ga:pagePath',
		],
		orderby: [
			{
				fieldName: 'ga:pageviews',
				sortOrder: 'DESCENDING',
			},
		],
		limit: 5,
	};

	const data = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( reportArgs ) );
	const error = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ reportArgs ] ) );
	const loading = useSelect( ( select ) => ! select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ reportArgs ] ) );

	if ( loading ) {
		return <PreviewBlock width="48%" height="92px" />;
	}

	if ( error ) {
		return <ReportError moduleSlug="analytics" error={ error } />;
	}

	const headers = [
		{
			title: __( 'Title', 'google-site-kit' ),
			tooltip: __( 'Page Title', 'google-site-kit' ),
			primary: true,
		},
		{
			title: __( 'Pageviews', 'google-site-kit' ),
			tooltip: __( 'Pageviews', 'google-site-kit' ),
		},
	];
	const links = [];
	const dataMapped = data[ 0 ].data.rows.map( ( row, i ) => {
		const [ title, url ] = row.dimensions;
		links[ i ] = url;

		return [
			title,
			numFmt( row.metrics[ 0 ].values[ 0 ], { style: 'decimal' } ),
		];
	} );
	const options = {
		hideHeader: false,
		chartsEnabled: false,
		links,
		hideColumns: {
			mobile: [ 2, 3 ],
		},
	};
	const dataTable = getDataTableFromData( dataMapped, headers, options );

	return (

				{ __( 'Top content over the last 28 days', 'google-site-kit' ) }

			<TableOverflowContainer>
				{ dataTable }
			</TableOverflowContainer>

	);
};

export default WPDashboardPopularPages;

<commit_msg>Add ZeroReport element.<commit_after>/**
 * WPDashboardPopularPages component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { MODULES_ANALYTICS, DATE_RANGE_OFFSET } from '../../modules/analytics/datastore/constants';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import PreviewBlock from '../PreviewBlock';
import ReportError from '../ReportError';
import { numFmt } from '../../util';
import TableOverflowContainer from '../../components/TableOverflowContainer';
import { getDataTableFromData } from '../../components/data-table';
import ReportZero from '../../components/ReportZero';
import { isZeroReport } from '../../modules/analytics/util/is-zero-report';
const { useSelect } = Data;

const WPDashboardPopularPages = () => {
	const dateRangeDates = useSelect( ( select ) => select( CORE_USER ).getDateRangeDates( {
		compare: true,
		offsetDays: DATE_RANGE_OFFSET,
	} ) );

	const reportArgs = {
		...dateRangeDates,
		metrics: [
			{
				expression: 'ga:pageviews',
				alias: 'Pageviews',
			},
		],
		dimensions: [
			'ga:pageTitle',
			'ga:pagePath',
		],
		orderby: [
			{
				fieldName: 'ga:pageviews',
				sortOrder: 'DESCENDING',
			},
		],
		limit: 5,
	};

	const data = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( reportArgs ) );
	const error = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ reportArgs ] ) );
	const loading = useSelect( ( select ) => ! select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ reportArgs ] ) );

	if ( loading ) {
		return <PreviewBlock width="48%" height="92px" />;
	}

	if ( error ) {
		return <ReportError moduleSlug="analytics" error={ error } />;
	}

	if ( isZeroReport( data ) ) {
		return <ReportZero moduleSlug="analytics" />;
	}

	const headers = [
		{
			title: __( 'Title', 'google-site-kit' ),
			tooltip: __( 'Page Title', 'google-site-kit' ),
			primary: true,
		},
		{
			title: __( 'Pageviews', 'google-site-kit' ),
			tooltip: __( 'Pageviews', 'google-site-kit' ),
		},
	];
	const links = [];
	const dataMapped = data[ 0 ].data.rows.map( ( row, i ) => {
		const [ title, url ] = row.dimensions;
		links[ i ] = url;

		return [
			title,
			numFmt( row.metrics[ 0 ].values[ 0 ], { style: 'decimal' } ),
		];
	} );
	const options = {
		hideHeader: false,
		chartsEnabled: false,
		links,
		hideColumns: {
			mobile: [ 2, 3 ],
		},
	};
	const dataTable = getDataTableFromData( dataMapped, headers, options );

	return (

				{ __( 'Top content over the last 28 days', 'google-site-kit' ) }

			<TableOverflowContainer>
				{ dataTable }
			</TableOverflowContainer>

	);
};

export default WPDashboardPopularPages;

<|endoftext|>


<commit_before>/* eslint-disable no-unused-vars */
class Service {
  constructor (options) {
    this.options = options || {};
    this.app = this.options['app'];
  }

  setup(app) {
    this.app = app;
  }

  async find (params) {
    return [];
  }

  async get (id, params) {
    let stageId = (new Buffer(id)).toString('base64');
    return {
      id, text: `A new message with ID: ${id}!`,base64:`${stageId}`
    };

  }

  async updateStatus (data, params) {
    let stageId = (new Buffer(data.taskid,'base64')).toString('ascii');
    data.taskid = stageId
    // get Flowz data
    let fInstance = await this.app.service('finstance').get(data.finstanceId);
    // get last Stage submitted data
    let lastIndex = fInstance.stageReference.length - 1
    // get Flowz data
    let flowzData = await this.app.service('flowzdata').get(fInstance.stageReference[lastIndex].stageRecordId);

    let flowzDataRecord = await this.app.service('flowzdata').create({
      data: flowzData.data,
      fid: fInstance.fid,
      iid: data.finstanceId,
      state: fInstance.currentStatus,
      nextTarget: stageId
    }).catch((err)=> {
      throw new Error(err.message)
    });
    return flowzDataRecord
  }

  async create (data, params) {
    console.log(data, params);
    if (Array.isArray(data)) {
      return Promise.all(data.map(current => this.create(current, params)));
    }

    return {msg:"your response saved"};
  }

  async update (id, data, params) {
    return data;
  }

  async patch (id, data, params) {
    return data;
  }

  async remove (id, params) {
    return { id };
  }
}

module.exports = function (options) {
  return new Service(options);
};

module.exports.Service = Service;
<commit_msg>set email response message<commit_after>/* eslint-disable no-unused-vars */
class Service {
  constructor (options) {
    this.options = options || {};
    this.app = this.options['app'];
  }

  setup(app) {
    this.app = app;
  }

  async find (params) {
    return [];
  }

  async get (id, params) {
    let stageId = (new Buffer(id)).toString('base64');
    return {
      id, text: `A new message with ID: ${id}!`,base64:`${stageId}`
    };

  }

  async updateStatus (data, params) {
    let stageId = (new Buffer(data.taskid,'base64')).toString('ascii');
    data.taskid = stageId
    // get Flowz data
    let fInstance = await this.app.service('finstance').get(data.finstanceId);
    // get last Stage submitted data
    let lastIndex = fInstance.stageReference.length - 1
    // get Flowz data
    let flowzData = await this.app.service('flowzdata').get(fInstance.stageReference[lastIndex].stageRecordId);

    let flowzDataRecord = await this.app.service('flowzdata').create({
      data: flowzData.data,
      fid: fInstance.fid,
      iid: data.finstanceId,
      state: fInstance.currentStatus,
      nextTarget: stageId
    }).catch((err)=> {
      throw new Error(err.message)
    });
    return "Your response saved successfully"
  }

  async create (data, params) {
    console.log(data, params);
    if (Array.isArray(data)) {
      return Promise.all(data.map(current => this.create(current, params)));
    }

    return {msg:"your response saved"};
  }

  async update (id, data, params) {
    return data;
  }

  async patch (id, data, params) {
    return data;
  }

  async remove (id, params) {
    return { id };
  }
}

module.exports = function (options) {
  return new Service(options);
};

module.exports.Service = Service;
<|endoftext|>


<commit_before>var iTunes = require('../');

iTunes.createConnection(function(err, itunes) {
  var i = itunes.getVolumeSync();
  var inc = 1;
  setInterval(function() {
    if (i == 100) inc *= -1;
    else if (i == 0) inc *= -1;
    itunes.setVolumeSync(i+=inc);
  }, 50);
});
<commit_msg>Update the 'fluctuate volume' example for the async API<commit_after>var iTunes = require('../')
  , speed  = Number(process.argv[2] || 50)
  , inc    = 1
  , i      = 0
  , conn   = null

iTunes.createConnection(function (err, c) {
  if (err) throw err;
  conn = c;
  conn.volume( initVolume );
});

function initVolume (err, v) {
  if (err) throw err;
  i = v;
  console.log('Toggling Volume at Speed: %d', speed);
  step();
}

function step () {
  if (i === 0 || i === 100) inc *= -1;
  conn.volume(i += inc, afterSet);
}

function afterSet (err, v) {
  if (err) throw err;
  setTimeout(step, speed);
}
<|endoftext|>


<commit_before>// backbone.structured.events.js v0.1.1

(function () {

   var root = this;

   // Create a local reference to array methods.
   var array = [];
   var slice = array.slice;

   // Backbone.Events
   // ---------------
   // Regular expression used to split event strings.
   var eventSplitter = /\s+/;

   // Implement fancy features of the Events API such as multiple event
   // names `"change blur"` and jQuery-style event maps `{change: action}`
   // in terms of the existing API.
   var eventsApi = function (obj, action, name, rest) {

      if (!name) return true;
      if (typeof name === 'object') {
         for (var key in name) {
            if (name.hasOwnProperty(key)) {
               obj[action].apply(obj, [key, name[key]].concat(rest));
            }
         }
      } else if (eventSplitter.test(name)) {
         var names = name.split(eventSplitter);
         for (var i = 0, l = names.length; i < l; i++) {
            obj[action].apply(obj, [names[i]].concat(rest));
         }
      } else {
         return true;
      }
   };

   // Optimized internal dispatch function for triggering events. Tries to
   // keep the usual cases speedy (most Backbone events have 3 arguments).
   var triggerEvents = function (events, args) {

      var ev, i = -1,
         l = events.length;
      switch (args.length) {
      case 0:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx);
         return;
      case 1:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0]);
         return;
      case 2:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
         return;
      case 3:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
         return;
      default:
         while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
      }
   };

   // A module that can be mixed in to *any object* in order to provide it with
   // custom events. You may bind with `on` or remove with `off` callback
   // functions to an event; `trigger`-ing an event fires all callbacks in
   // succession.
   //
   //     var object = {};
   //     _.extend(object, Backbone.Events);
   //     object.on('expand', function(){ alert('expanded'); });
   //     object.trigger('expand');
   //
   var Events = (function () {

      var seperator = '.';
      var toString = Object.prototype.toString;

      // Utility for getting the name of an object type
      var getType = function (obj) {
         return toString.call(obj).slice(8, -1);
      };

      // Create an object from a delimited string and bind to
      // an optional context.
      var setObj = function (str, ctx, sep) {

         ctx = ctx || window;
         str = str.split(sep || seperator);

         var obj, _i, _len;
         for (_i = 0, _len = str.length; _i < _len; _i++) {
            obj = str[_i];
            ctx = (ctx[obj] = ctx[obj] || {});
         }
         return ctx;
      };

      // Retrieve an object using a delimited string from an optional
      // context.
      var getObj = function (str, ctx, sep) {

         ctx = ctx || window;
         str = str.split(sep || seperator);

         var arr = _.filter(str, function (num) {
            return num.length;
         }),
            obj = null;

         obj = _.reduce(arr, function (prev, curr, index, list) {
            if (prev) {
               return prev[list[index]];
            }
         }, ctx);
         return obj;
      };

      // Reconstruct an object against true/false rules defined
      // by an iterator
      var remap = function (obj, iterator, parentkey) {

         var key, _obj = {};

         if (getType(iterator) !== 'Function') return obj;
         if (getType(obj) === 'Object') {

            for (key in obj) {
               if (obj.hasOwnProperty(key)
                  && iterator(key, obj[key], obj, parentkey)) {
                  _obj[key] = (getType(obj[key]) === 'Object')
               ? remap(obj[key], iterator, key)
               : obj[key];
               }
            }
         }
         return _obj;
      };

      // Scrub any matching context objects or callbacks from the list of events
      var scrubList = function (list, callback, context) {
         var events, j, k, ev;
         events = [];
         for (j = 0, k = list.length; j < k; j++) {
            ev = list[j];
            if ((callback && callback !== ev.callback
               && callback !== ev.callback._callback)
               || (context && context !== ev.context)) {
               events.push(ev);
            }
         }
         return events;
      };

      return {

         // Bind one or more space separated events, or an events map,
         // to a `callback` function. Passing `"all"` will bind the callback to
         // all events fired.
         on: function (name, callback, context) {
            if (!(eventsApi(this, 'on', name, [callback, context]) && callback)) return this;

            this._events || (this._events = {});
            var obj = getObj(name, this._events);
            var list = (obj && obj._events) || (setObj(name, this._events)._events = []);

            list.push({
               callback: callback,
               context: context,
               ctx: context || this
            });

            return this;
         },

         // Bind events to only be triggered a single time. After the first time
         // the callback is invoked, it will be removed.
         once: function (name, callback, context) {
            if (!(eventsApi(this, 'once', name, [callback, context]) && callback)) return this;
            var self = this;
            var once = _.once(function () {
               self.off(name, once);
               callback.apply(this, arguments);
            });
            once._callback = callback;
            this.on(name, once, context);
            return this;
         },

         // Remove one or many callbacks. If `context` is null, removes all
         // callbacks with that function. If `callback` is null, removes all
         // callbacks for the event. If `name` is null, removes all bound
         // callbacks for all events.
         off: function (name, callback, context) {

            if (!this._events
               || !eventsApi(this, 'off', name, [callback, context])) return this;

            if (!name && !callback && !context) {
               this._events = {};
               return this;
            }

            // To remove named (or unamed) objects with optional contexts and callbacks we
            // must recursively remap the "_events" object.
            //
            // Remapping (which may be side effectful) allows us to reconstruct everything
            // within the "_events" hierarchy against a ruleset defined by an iterator. If
            // the iterator returns "true", the key is included in the remap, othewrwise it
            // is excluded.
            this._events = remap(this._events, function (key, value, parent, parentkey) {

               if (name) {
                  if (callback || context) {
                     if ((key === '_events')
                        && ((name.split(seperator).pop()) === parentkey)
                        && (getType(value) === 'Array')) {
                        parent[key] = scrubList(value, callback, context);
                     }
                     return true;
                  } else {
                     return (key === '_events')
                     && ((name.split(seperator).pop()) === parentkey) ? false : true;
                  }
               } else if (callback || context) {
                  if ((key === '_events') && (getType(value) === 'Array')) {
                     parent[key] = scrubList(value, callback, context);
                  }
                  return true;
               } else return false;

            });

            // Remove any empty objects
            this._events = remap(this._events, function (key, value) {
               return _.isEmpty(value) ? false : true;
            });

            return this;
         },

         // Trigger one or many events, firing all bound callbacks. Callbacks are
         // passed the same arguments as `trigger` is, apart from the event name
         // (unless you're listening on `"all"`, which will cause your callback to
         // receive the true name of the event as the first argument).
         trigger: function (name) {
            if (!this._events) return this;
            var args = slice.call(arguments, 1);
            if (!eventsApi(this, 'trigger', name, args)) return this;

            //var events = this._events[name];
            var allEvents = this._events.all && this._events.all._events;
            var obj = getObj(name, this._events);
            var events = obj ? obj._events : false;

            // Pass the events object to allow access to the sibling context
            args.push(obj);

            if (events) triggerEvents(events, args);
            if (allEvents) triggerEvents(allEvents, arguments);
            return this;
         },

         // Change the seperator character(s) used to delimit event names
         setSeperator: function (sep) {
            seperator = (sep && sep.toString()) || seperator;
            return this;
         },

         // Deep removal of a namespace and all of its child objects (not just the
         // the events local to the namesapce)
         destroy: function (name) {

            if (!this._events
               || !eventsApi(this, 'destroy', name)) return this;

            if (!name) {
               this._events = {};
               return this;
            }

            var names = name.split(seperator), wildcard = false;

            name = ("*" !== names[names.length - 1]) ? names.pop()
            : (wildcard = !0) && names[names.length - 2];

            if (wildcard) {
               this._events = remap(this._events, function (key, value, parent, parentkey) {
                  return (name === parentkey && key !== '_events') ? false : true;
               });
            }
            else {
               this._events = remap(this._events, function (key) {
                  return (name === key) ? false : true;
               });
            }

            return this;
         },

         // Deep triggering of all events in a hierarchy, including or excluding any
         // present on the parent object itself
         deepTrigger: function (name) {

            if (!this._events) return this;
            var args = slice.call(arguments, 1);
            if (!eventsApi(this, 'deepTrigger', name, args)) return this;

            var names = name.split(seperator), wildcard = false;
            var arr = [];
            var trigger = false;

            name = ("*" !== names[names.length - 1]) ? names.pop()
            : (wildcard = !0) && names[names.length - 2];

            remap(this._events, function (key, value, parent, parentkey) {
               if (key !== '_events') {
                  if (wildcard && ((name === parentkey) || trigger)) {
                     trigger = true;
                     arr.push(value._events);
                  }
                  else if (!wildcard && ((name === key) || trigger)) {
                     trigger = true;
                     arr.push(value._events);
                  }
               }
               return true;

            });

            _.each(arr, function (events) {
               triggerEvents(events, args);
            });
         },

         // An inversion-of-control version of `on`. Tell *this* object to listen to
         // an event in another object ... keeping track of what it's listening to.
         listenTo: function (obj, name, callback) {
            var listeners = this._listeners || (this._listeners = {});
            var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
            listeners[id] = obj;
            obj.on(name, typeof name === 'object' ? this : callback, this);
            return this;
         },

         // Tell this object to stop listening to either specific events ... or
         // to every object it's currently listening to.
         stopListening: function (obj, name, callback) {

            var listeners = this._listeners;
            if (!listeners) return this;
            if (obj) {
               obj.off(name, typeof name === 'object' ? this : callback, this);
               if (!name && !callback) delete listeners[obj._listenerId];
            } else {
               if (typeof name === 'object') callback = this;
               for (var id in listeners) {
                  if (listeners.hasOwnProperty(id)) {
                     listeners[id].off(name, callback, this);
                  }
               }
               this._listeners = {};
            }
            return this;
         }

      };

   }());

   root.Events = Events;

}.call(Backbone));<commit_msg>Small bug fixes to deepTrigger<commit_after>// backbone.structured.events.js v0.1.2

(function () {

   var root = this;

   // Create a local reference to array methods.
   var array = [];
   var slice = array.slice;

   // Backbone.Events
   // ---------------
   // Regular expression used to split event strings.
   var eventSplitter = /\s+/;

   // Implement fancy features of the Events API such as multiple event
   // names `"change blur"` and jQuery-style event maps `{change: action}`
   // in terms of the existing API.
   var eventsApi = function (obj, action, name, rest) {

      if (!name) return true;
      if (typeof name === 'object') {
         for (var key in name) {
            if (name.hasOwnProperty(key)) {
               obj[action].apply(obj, [key, name[key]].concat(rest));
            }
         }
      } else if (eventSplitter.test(name)) {
         var names = name.split(eventSplitter);
         for (var i = 0, l = names.length; i < l; i++) {
            obj[action].apply(obj, [names[i]].concat(rest));
         }
      } else {
         return true;
      }
   };

   // Optimized internal dispatch function for triggering events. Tries to
   // keep the usual cases speedy (most Backbone events have 3 arguments).
   var triggerEvents = function (events, args) {

      var ev, i = -1,
         l = events.length;
      switch (args.length) {
      case 0:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx);
         return;
      case 1:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0]);
         return;
      case 2:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
         return;
      case 3:
         while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
         return;
      default:
         while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
      }
   };

   // A module that can be mixed in to *any object* in order to provide it with
   // custom events. You may bind with `on` or remove with `off` callback
   // functions to an event; `trigger`-ing an event fires all callbacks in
   // succession.
   //
   //     var object = {};
   //     _.extend(object, Backbone.Events);
   //     object.on('expand', function(){ alert('expanded'); });
   //     object.trigger('expand');
   //
   var Events = (function () {

      var seperator = '.';
      var toString = Object.prototype.toString;

      // Utility for getting the name of an object type
      var getType = function (obj) {
         return toString.call(obj).slice(8, -1);
      };

      // Create an object from a delimited string and bind to
      // an optional context.
      var setObj = function (str, ctx, sep) {

         ctx = ctx || window;
         str = str.split(sep || seperator);

         var obj, _i, _len;
         for (_i = 0, _len = str.length; _i < _len; _i++) {
            obj = str[_i];
            ctx = (ctx[obj] = ctx[obj] || {});
         }
         return ctx;
      };

      // Retrieve an object using a delimited string from an optional
      // context.
      var getObj = function (str, ctx, sep) {

         ctx = ctx || window;
         str = str.split(sep || seperator);

         var arr = _.filter(str, function (num) {
            return num.length;
         }),
            obj = null;

         obj = _.reduce(arr, function (prev, curr, index, list) {
            if (prev) {
               return prev[list[index]];
            }
         }, ctx);
         return obj;
      };

      // Reconstruct an object against true/false rules defined
      // by an iterator
      var remap = function (obj, iterator, parentkey) {

         var key, _obj = {};

         if (getType(iterator) !== 'Function') return obj;
         if (getType(obj) === 'Object') {

            for (key in obj) {
               if (obj.hasOwnProperty(key)
                  && iterator(key, obj[key], obj, parentkey)) {
                  _obj[key] = (getType(obj[key]) === 'Object')
               ? remap(obj[key], iterator, key)
               : obj[key];
               }
            }
         }
         return _obj;
      };

      // Scrub any matching context objects or callbacks from the list of events
      var scrubList = function (list, callback, context) {
         var events, j, k, ev;
         events = [];
         for (j = 0, k = list.length; j < k; j++) {
            ev = list[j];
            if ((callback && callback !== ev.callback
               && callback !== ev.callback._callback)
               || (context && context !== ev.context)) {
               events.push(ev);
            }
         }
         return events;
      };

      return {

         // Bind one or more space separated events, or an events map,
         // to a `callback` function. Passing `"all"` will bind the callback to
         // all events fired.
         on: function (name, callback, context) {
            if (!(eventsApi(this, 'on', name, [callback, context]) && callback)) return this;

            this._events || (this._events = {});
            var obj = getObj(name, this._events);
            var list = (obj && obj._events) || (setObj(name, this._events)._events = []);

            list.push({
               callback: callback,
               context: context,
               ctx: context || this
            });

            return this;
         },

         // Bind events to only be triggered a single time. After the first time
         // the callback is invoked, it will be removed.
         once: function (name, callback, context) {
            if (!(eventsApi(this, 'once', name, [callback, context]) && callback)) return this;
            var self = this;
            var once = _.once(function () {
               self.off(name, once);
               callback.apply(this, arguments);
            });
            once._callback = callback;
            this.on(name, once, context);
            return this;
         },

         // Remove one or many callbacks. If `context` is null, removes all
         // callbacks with that function. If `callback` is null, removes all
         // callbacks for the event. If `name` is null, removes all bound
         // callbacks for all events.
         off: function (name, callback, context) {

            if (!this._events
               || !eventsApi(this, 'off', name, [callback, context])) return this;

            if (!name && !callback && !context) {
               this._events = {};
               return this;
            }

            // To remove named (or unamed) objects with optional contexts and callbacks we
            // must recursively remap the "_events" object.
            //
            // Remapping (which may be side effectful) allows us to reconstruct everything
            // within the "_events" hierarchy against a ruleset defined by an iterator. If
            // the iterator returns "true", the key is included in the remap, othewrwise it
            // is excluded.
            this._events = remap(this._events, function (key, value, parent, parentkey) {

               if (name) {
                  if (callback || context) {
                     if ((key === '_events')
                        && ((name.split(seperator).pop()) === parentkey)
                        && (getType(value) === 'Array')) {
                        parent[key] = scrubList(value, callback, context);
                     }
                     return true;
                  } else {
                     return (key === '_events')
                     && ((name.split(seperator).pop()) === parentkey) ? false : true;
                  }
               } else if (callback || context) {
                  if ((key === '_events') && (getType(value) === 'Array')) {
                     parent[key] = scrubList(value, callback, context);
                  }
                  return true;
               } else return false;

            });

            // Remove any empty objects
            this._events = remap(this._events, function (key, value) {
               return _.isEmpty(value) ? false : true;
            });

            return this;
         },

         // Trigger one or many events, firing all bound callbacks. Callbacks are
         // passed the same arguments as `trigger` is, apart from the event name
         // (unless you're listening on `"all"`, which will cause your callback to
         // receive the true name of the event as the first argument).
         trigger: function (name) {
            if (!this._events) return this;
            var args = slice.call(arguments, 1);
            if (!eventsApi(this, 'trigger', name, args)) return this;

            //var events = this._events[name];
            var allEvents = this._events.all && this._events.all._events;
            var obj = getObj(name, this._events);
            var events = obj ? obj._events : false;

            // Pass the events object to allow access to the sibling context
            args.push(obj);

            if (events) triggerEvents(events, args);
            if (allEvents) triggerEvents(allEvents, arguments);
            return this;
         },

         // Change the seperator character(s) used to delimit event names
         setSeperator: function (sep) {
            seperator = (sep && sep.toString()) || seperator;
            return this;
         },

         // Deep removal of a namespace and all of its child objects (not just the
         // the events local to the namesapce)
         destroy: function (name) {

            if (!this._events
               || !eventsApi(this, 'destroy', name)) return this;

            if (!name) {
               this._events = {};
               return this;
            }

            var names = name.split(seperator), wildcard = false;

            name = ("*" !== names[names.length - 1]) ? names.pop()
            : (wildcard = !0) && names[names.length - 2];

            if (wildcard) {
               this._events = remap(this._events, function (key, value, parent, parentkey) {
                  return (name === parentkey && key !== '_events') ? false : true;
               });
            }
            else {
               this._events = remap(this._events, function (key) {
                  return (name === key) ? false : true;
               });
            }

            return this;
         },

         // Deep triggering of all events in a hierarchy, including or excluding any
         // present on the parent object itself
         deepTrigger: function (name) {

            if (!this._events) return this;
            var args = slice.call(arguments, 1);
            if (!eventsApi(this, 'deepTrigger', name, args)) return this;

            var names = name.split(seperator), wildcard = false;
            var arr = [];
            var trigger = false;

            name = ("*" !== names[names.length - 1]) ? names.pop()
            : (wildcard = !0) && names[names.length - 2];

            remap(this._events, function (key, value, parent, parentkey) {

               if (key !== '_events') {

                  if (wildcard && ((name === parentkey) || trigger)) {
                     trigger = true;
                     value._events && arr.push(value._events);
                  }
                  else if (!wildcard) {
                     if ((name === key) || trigger) {
                        value._events && arr.push(value._events);
                     }
                     else if (name === parentkey) {
                        value._events && arr.push(value._events);
                        trigger = true;
                     }
                  }
               }

               return true;

            });

            _.each(arr, function (events) {
               triggerEvents(events, args);
            });

            return this;
         },

         // An inversion-of-control version of `on`. Tell *this* object to listen to
         // an event in another object ... keeping track of what it's listening to.
         listenTo: function (obj, name, callback) {
            var listeners = this._listeners || (this._listeners = {});
            var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
            listeners[id] = obj;
            obj.on(name, typeof name === 'object' ? this : callback, this);
            return this;
         },

         // Tell this object to stop listening to either specific events ... or
         // to every object it's currently listening to.
         stopListening: function (obj, name, callback) {

            var listeners = this._listeners;
            if (!listeners) return this;
            if (obj) {
               obj.off(name, typeof name === 'object' ? this : callback, this);
               if (!name && !callback) delete listeners[obj._listenerId];
            } else {
               if (typeof name === 'object') callback = this;
               for (var id in listeners) {
                  if (listeners.hasOwnProperty(id)) {
                     listeners[id].off(name, callback, this);
                  }
               }
               this._listeners = {};
            }
            return this;
         }

      };

   }());

   root.Events = Events;

}.call(Backbone));<|endoftext|>


<commit_before>/*jshint node:true, laxcomma:true, expr:true, newcap:false*/
"use strict";

var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});

requirejs(['http', 'path', 'express', './routes', 'socket.io', 'underscore', './functions.json'], function (http, path, express, routes, socketio, _, fns) {
  var app = express()
    , server = http.createServer(app)
    , logging = true
    , io = socketio.listen(server, {origins: '*:*', log: false});

  app.configure(function() {
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    //app.use(express.logger('dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(path.join(__dirname, '../client')));
  });

  // Routing table
  app.get('/', routes.index);

  // App-specific logging function. Logs messages only if 'logging' var is set to true.
  var log = function(message) {
    if (logging) { console.log(message); }
  };

  // ID generator utility function
  var makeID = function(len) {
      var CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      var id = "";

      for (var i = 0, idLen = len || 10; i < idLen; i++) {
        id += CHARSET.charAt(Math.floor(Math.random() * CHARSET.length));
      }

      return id;
  };

  // Room constructor function
  var Room = function(){
    var roomID = makeID(10);
    var users = [];
    var currentFn = null;
    return _.extend(Object.create(Room), {

      initGame: function(){
        log('starting game id ' + roomID);
        currentFn = this.genRandomFn();
        io.sockets.in(roomID).emit('beginGame', currentFn);
      },

     genRandomFn: function(){
        var randProp,
            randIndex,
            keys = [];

        _.each(fns, function(val, prop){
          keys.push(prop);
        });

        randIndex = Math.floor(Math.random() * _.size(keys));
        randProp = keys[randIndex];

        return fns[randProp];
      },

      // Checks if the room is full. Returns true if yes, false if no.
      isFull: function(){
        return users.length >= 2;
      },

      // Adds a user to the room's users array and subscribes them to this
      // room's broadcasts.
      addUser: function(user){
        // TODO: Fix this security hole--isFull could be redefined by user
        if ( this.isFull() ) { throw new Error("Cannot add users to a full room."); }

        // Subscribe a user to this room's socket broadcasts
        user.getSocket().join(roomID);
        return users.push(user);
      },

      // Remove a user from the current room.
      removeUser: function(user){
        //TODO: Implement garbage collection on rooms
      },

      // Return an array containing all users in the room.
      getUsers: function(){
        return users;
      },

      getID: function(){
        return roomID;
      },

      // Broadcast the contents of a user's editor to that user's room.
      updateEditor: function(data, socket){
        socket.broadcast.to(roomID).emit('updateEditor', data);
      },

      sweetVictory: function(data, socket){
        socket.broadcast.to(roomID).emit('sweetVictory', data);
      }

    });
  };

  var User = function(socket){
    // TODO: More robust checking here
    if (!socket) {
      throw new Error("Cannot create a user without linking it to a socket.");
    }

    var userSocket = socket;
    var currentRoom = null;
    var uid = socket.id;
    return {

      setCurrentRoom: function(room){
        return currentRoom = room;
      },

      getCurrentRoom: function(){
        return currentRoom;
      },

      getSocket: function(){
        return userSocket;
      },

      getID: function(){
        return uid;
      }

    };
  };

  // Hash to store our users in
  var Users = {};

  // Create a room when we initialize the server
  var currentRoom = Room();

  io.sockets.on('connection', function (socket) {
    // Check to see if the current room is full and create a new one if it is
    if( currentRoom.isFull() ){
      currentRoom = Room();
    }

    // Create a user and link it to its corresponding socket connection
    var user = User(socket);

    // Add this user to the current room
    currentRoom.addUser(user);

    // Store the room's ID on the user object
    user.setCurrentRoom(currentRoom);

    // Check again if the room is now full, and start a game if it is
    if( currentRoom.isFull() ) {
      currentRoom.initGame();
    }

    // Broadcast changes to a room's users
    socket.on('editorChange', function(data) {
      user.getCurrentRoom().updateEditor(data, socket);
    });

    socket.on('sweetVictory', function(data) {
      user.getCurrentRoom().sweetVictory(data, socket);
    });

    socket.on('disconnect',function(){
      log('lol bai');
    });
  });

  server.listen(app.get('port'), function() {
    log("Underscoreboard server listening on port " + app.get('port'));
  });

});
<commit_msg>Moved logging out into development block<commit_after>/*jshint node:true, laxcomma:true, expr:true, newcap:false*/
"use strict";

var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});

requirejs(['http', 'path', 'express', './routes', 'socket.io', 'underscore', './functions.json'], function (http, path, express, routes, socketio, _, fns) {
  var app = express()
    , server = http.createServer(app)
    , logging = false
    , io = socketio.listen(server, {origins: '*:*', log: false});

  app.configure('development', function() {
    app.use(express.logger('dev'));
    logging = true;
  });

  app.configure(function() {
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(path.join(__dirname, '../client')));
  });

  // Routing table
  app.get('/', routes.index);

  // Logging function. Only logs when server is in development mode.
  var log = function(message) {
    if (logging) { console.log(message); }
  };

  // ID generator utility function
  var makeID = function(len) {
      var CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      var id = "";

      for (var i = 0, idLen = len || 10; i < idLen; i++) {
        id += CHARSET.charAt(Math.floor(Math.random() * CHARSET.length));
      }

      return id;
  };

  // Room constructor function
  var Room = function(){
    var roomID = makeID(10);
    var users = [];
    var currentFn = null;
    return _.extend(Object.create(Room), {

      initGame: function(){
        log('starting game id ' + roomID);
        currentFn = this.genRandomFn();
        io.sockets.in(roomID).emit('beginGame', currentFn);
      },

     genRandomFn: function(){
        var randProp,
            randIndex,
            keys = [];

        _.each(fns, function(val, prop){
          keys.push(prop);
        });

        randIndex = Math.floor(Math.random() * _.size(keys));
        randProp = keys[randIndex];

        return fns[randProp];
      },

      // Checks if the room is full. Returns true if yes, false if no.
      isFull: function(){
        return users.length >= 2;
      },

      // Adds a user to the room's users array and subscribes them to this
      // room's broadcasts.
      addUser: function(user){
        // TODO: Fix this security hole--isFull could be redefined by user
        if ( this.isFull() ) { throw new Error("Cannot add users to a full room."); }

        // Subscribe a user to this room's socket broadcasts
        user.getSocket().join(roomID);
        return users.push(user);
      },

      // Remove a user from the current room.
      removeUser: function(user){
        //TODO: Implement garbage collection on rooms
      },

      // Return an array containing all users in the room.
      getUsers: function(){
        return users;
      },

      getID: function(){
        return roomID;
      },

      // Broadcast the contents of a user's editor to that user's room.
      updateEditor: function(data, socket){
        socket.broadcast.to(roomID).emit('updateEditor', data);
      },

      sweetVictory: function(data, socket){
        socket.broadcast.to(roomID).emit('sweetVictory', data);
      }

    });
  };

  var User = function(socket){
    // TODO: More robust checking here
    if (!socket) {
      throw new Error("Cannot create a user without linking it to a socket.");
    }

    var userSocket = socket;
    var currentRoom = null;
    var uid = socket.id;
    return {

      setCurrentRoom: function(room){
        return currentRoom = room;
      },

      getCurrentRoom: function(){
        return currentRoom;
      },

      getSocket: function(){
        return userSocket;
      },

      getID: function(){
        return uid;
      }

    };
  };

  // Hash to store our users in
  var Users = {};

  // Create a room when we initialize the server
  var currentRoom = Room();

  io.sockets.on('connection', function (socket) {
    // Check to see if the current room is full and create a new one if it is
    if( currentRoom.isFull() ){
      currentRoom = Room();
    }

    // Create a user and link it to its corresponding socket connection
    var user = User(socket);

    // Add this user to the current room
    currentRoom.addUser(user);

    // Store the room's ID on the user object
    user.setCurrentRoom(currentRoom);

    // Check again if the room is now full, and start a game if it is
    if( currentRoom.isFull() ) {
      currentRoom.initGame();
    }

    // Broadcast changes to a room's users
    socket.on('editorChange', function(data) {
      user.getCurrentRoom().updateEditor(data, socket);
    });

    socket.on('sweetVictory', function(data) {
      user.getCurrentRoom().sweetVictory(data, socket);
    });

    socket.on('disconnect',function(){
      log('lol bai');
    });
  });

  server.listen(app.get('port'), function() {
    log("Underscoreboard server listening on port " + app.get('port'));
  });

});
<|endoftext|>


<commit_before>// Controller
// ==========
// Base controller class. Extend with an initialize method
// and actions (methods) to handle requests.

module.exports = Controller

var _ = require('underscore')
var extendable = require('extendable')
var Plugin = require('./plugin')

function Controller(options) {
  this.res = options.res
  this.req = options.req
  this.config = options.config
  this.route = options.route

  // run plugin setup for this controller instance
  this.runPlugins()

  // setup request timeout handler
  this.req.on('timeout', this.timeout.bind(this))

  this.model = {}

  this._done = this._done.bind(this)
  options.done = this._done

  this._defaultMediaType = this.config.defaultMediaType || 'text/html'

  this.initialize.apply(this, arguments)

  // Call the `action` if one was matched in the route
  if (options.route.action) {
    var action = this[options.route.action]
    if (action) action.call(this, this._done)
  }
}

_.extend(Controller.prototype, {

  // Called when the action method is done populating the
  // this.model object with data.
  _done: function() {
    this._render()
  },

  // Determines the best response type based on what the
  // client can accept and what the controller can output.
  _render: function(mediaType) {
    var self = this
    var preferredType = mediaType || this.preferredMediaType(this.availableMediaTypes)

    if (/html$/.test(preferredType)) {
      return this.render(function(err, html){
        if (err) self.error(err)
        if (self.html) return self.html(html)
        throw 'No `html` method implemented'
      })
    }

    if (/json$/.test(preferredType)) {
      if (this.json) return this.json(this.model)
      throw 'No `json` method implemented'
    }

    if (/xml$/.test(preferredType)) {
      if (this.xml) return this.xml(this.model)
      throw 'No `xml` method implemented'
    }

    // no match, try with the default media type
    if (!mediaType) return this._render(this._defaultMediaType)

    return this.res.end('No media type matched')
  },

  // Initialize is an empty method by default. Override
  // it with your own initialization logic.
  initialize: function(){},

  // Handles a timed out request. Override with your
  // own logic and error handling.
  timeout: function() {
    this.error(504, 'Server timeout')
  },

  // content types that can be output from this controller
  availableMediaTypes: [
    'text/html',
    'application/json'
  ],

  // template settings
  template: null,
  templateOptions: {
    layout: 'layout'
  },

  // Call this in your initialize function to enforce
  // a maximum request size. Useful for file uploads.
  enforceMaxLength: function(maxLen) {
    // respond with errors if max length is exceeded
    if (typeof maxLen === 'number') {
      var cl = req.headers['content-length']
      res.setHeader('max-length', ''+maxLen)
      if (!cl) {
        res.error(411)  // length required
        return false
      }
      if (cl > req.maxLen) {
        res.error(413) // too long
        return false
      }
    }
    return true
  }

})

Controller.extend = extendable
Plugin.makePluggable(Controller)
<commit_msg>made the controller an event emitter<commit_after>// Controller
// ==========
// Base controller class. Extend with an initialize method
// and actions (methods) to handle requests.

module.exports = Controller

var EventEmitter = require('events').EventEmitter
var _ = require('underscore')
var extendable = require('extendable')
var Plugin = require('./plugin')

function Controller(options) {
  this.res = options.res
  this.req = options.req
  this.config = options.config
  this.route = options.route

  // setup as an event emitter
  EventEmitter.call(this)

  // run plugin setup for this controller instance
  this.runPlugins()

  // setup request timeout handler
  this.req.on('timeout', this.timeout.bind(this))

  this.model = {}

  this._done = this._done.bind(this)
  options.done = this._done

  this._defaultMediaType = this.config.defaultMediaType || 'text/html'

  this.initialize.apply(this, arguments)

  // Call the `action` if one was matched in the route
  if (options.route.action) {
    var action = this[options.route.action]
    if (action) action.call(this, this._done)
  }
}

_.extend(Controller.prototype, EventEmitter.prototype, {

  // Called when the action method is done populating the
  // this.model object with data.
  _done: function() {
    this._render()
  },

  // Determines the best response type based on what the
  // client can accept and what the controller can output.
  _render: function(mediaType) {
    var self = this
    var preferredType = mediaType || this.preferredMediaType(this.availableMediaTypes)

    if (/html$/.test(preferredType)) {
      return this.render(function(err, html){
        if (err) self.error(err)
        if (self.html) return self.html(html)
        throw 'No `html` method implemented'
      })
    }

    if (/json$/.test(preferredType)) {
      if (this.json) return this.json(this.model)
      throw 'No `json` method implemented'
    }

    if (/xml$/.test(preferredType)) {
      if (this.xml) return this.xml(this.model)
      throw 'No `xml` method implemented'
    }

    // no match, try with the default media type
    if (!mediaType) return this._render(this._defaultMediaType)

    return this.res.end('No media type matched')
  },

  // Initialize is an empty method by default. Override
  // it with your own initialization logic.
  initialize: function(){},

  // Handles a timed out request. Override with your
  // own logic and error handling.
  timeout: function() {
    this.error(504, 'Server timeout')
  },

  // content types that can be output from this controller
  availableMediaTypes: [
    'text/html',
    'application/json'
  ],

  // template settings
  template: null,
  templateOptions: {
    layout: 'layout'
  },

  // Call this in your initialize function to enforce
  // a maximum request size. Useful for file uploads.
  enforceMaxLength: function(maxLen) {
    // respond with errors if max length is exceeded
    if (typeof maxLen === 'number') {
      var cl = req.headers['content-length']
      res.setHeader('max-length', ''+maxLen)
      if (!cl) {
        res.error(411)  // length required
        return false
      }
      if (cl > req.maxLen) {
        res.error(413) // too long
        return false
      }
    }
    return true
  }

})

Controller.extend = extendable
Plugin.makePluggable(Controller)
<|endoftext|>


<commit_before>/**
 * @author zhixin wen <wenzhixin2010@gmail.com>
 */

const Utils = $.fn.bootstrapTable.utils

// Reasonable defaults
const PIXEL_STEP = 10
const LINE_HEIGHT = 40
const PAGE_HEIGHT = 800

function normalizeWheel (event) {
  let sX = 0 // spinX
  let sY = 0 // spinY
  let pX = 0 // pixelX
  let pY = 0 // pixelY

  // Legacy
  if ('detail' in event) { sY = event.detail }
  if ('wheelDelta' in event) { sY = -event.wheelDelta / 120 }
  if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120 }
  if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120 }

  // side scrolling on FF with DOMMouseScroll
  if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
    sX = sY
    sY = 0
  }

  pX = sX * PIXEL_STEP
  pY = sY * PIXEL_STEP

  if ('deltaY' in event) { pY = event.deltaY }
  if ('deltaX' in event) { pX = event.deltaX }

  if ((pX || pY) && event.deltaMode) {
    if (event.deltaMode === 1) { // delta in LINE units
      pX *= LINE_HEIGHT
      pY *= LINE_HEIGHT
    } else { // delta in PAGE units
      pX *= PAGE_HEIGHT
      pY *= PAGE_HEIGHT
    }
  }

  // Fall-back if spin cannot be determined
  if (pX && !sX) { sX = (pX < 1) ? -1 : 1 }
  if (pY && !sY) { sY = (pY < 1) ? -1 : 1 }

  return {
    spinX: sX,
    spinY: sY,
    pixelX: pX,
    pixelY: pY
  }
}

$.extend($.fn.bootstrapTable.defaults, {
  fixedColumns: false,
  fixedNumber: 0,
  fixedRightNumber: 0
})

$.BootstrapTable = class extends $.BootstrapTable {

  fixedColumnsSupported () {
    return this.options.fixedColumns &&
      !this.options.detailView &&
      !this.options.cardView
  }

  initContainer () {
    super.initContainer()

    if (!this.fixedColumnsSupported()) {
      return
    }

    if (this.options.fixedNumber) {
      this.$tableContainer.append('

')
      this.$fixedColumns = this.$tableContainer.find('.fixed-columns')
    }

    if (this.options.fixedRightNumber) {
      this.$tableContainer.append('

')
      this.$fixedColumnsRight = this.$tableContainer.find('.fixed-columns-right')
    }
  }

  initBody (...args) {
    super.initBody(...args)

    if (!this.fixedColumnsSupported()) {
      return
    }

    if (this.options.showHeader && this.options.height) {
      return
    }

    this.initFixedColumnsBody()
    this.initFixedColumnsEvents()
  }

  trigger (...args) {
    super.trigger(...args)

    if (!this.fixedColumnsSupported()) {
      return
    }

    if (args[0] === 'post-header') {
      this.initFixedColumnsHeader()
    } else if (args[0] === 'scroll-body') {
      if (this.needFixedColumns && this.options.fixedNumber) {
        this.$fixedBody.scrollTop(this.$tableBody.scrollTop())
      }

      if (this.needFixedColumns && this.options.fixedRightNumber) {
        this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop())
      }
    }
  }

  updateSelected () {
    super.updateSelected()

    if (!this.fixedColumnsSupported()) {
      return
    }

    this.$tableBody.find('tr').each((i, el) => {
      const $el = $(el)
      const index = $el.data('index')
      const classes = $el.attr('class')

      const inputSelector = `[name="${this.options.selectItemName}"]`
      const $input = $el.find(inputSelector)

      if (typeof index === undefined) {
        return
      }

      const updateFixedBody = ($fixedHeader, $fixedBody) => {
        const $tr = $fixedBody.find(`tr[data-index="${index}"]`)

        $tr.attr('class', classes)

        if ($input.length) {
          $tr.find(inputSelector).prop('checked', $input.prop('checked'))
        }

        if (this.$selectAll.length) {
          $fixedHeader.add($fixedBody)
            .find('[name="btSelectAll"]')
            .prop('checked', this.$selectAll.prop('checked'))
        }
      }

      if (this.$fixedBody && this.options.fixedNumber) {
        updateFixedBody(this.$fixedHeader, this.$fixedBody)
      }

      if (this.$fixedBodyRight && this.options.fixedRightNumber) {
        updateFixedBody(this.$fixedHeaderRight, this.$fixedBodyRight)
      }
    })
  }

  hideLoading () {
    super.hideLoading()

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedColumns.find('.fixed-table-loading').hide()
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedColumnsRight.find('.fixed-table-loading').hide()
    }
  }

  initFixedColumnsHeader () {
    if (this.options.height) {
      this.needFixedColumns = this.$tableHeader.outerWidth(true) < this.$tableHeader.find('table').outerWidth(true)
    } else {
      this.needFixedColumns = this.$tableBody.outerWidth(true) < this.$tableBody.find('table').outerWidth(true)
    }

    const initFixedHeader = ($fixedColumns, isRight) => {
      $fixedColumns.find('.fixed-table-header').remove()
      $fixedColumns.append(this.$tableHeader.clone(true))

      $fixedColumns.css({
        width: this.getFixedColumnsWidth(isRight)
      })
      return $fixedColumns.find('.fixed-table-header')
    }

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedHeader = initFixedHeader(this.$fixedColumns)
      this.$fixedHeader.css('margin-right', '')
    } else if (this.$fixedColumns) {
      this.$fixedColumns.html('').css('width', '')
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedHeaderRight = initFixedHeader(this.$fixedColumnsRight, true)
      this.$fixedHeaderRight.scrollLeft(this.$fixedHeaderRight.find('table').width())
    } else if (this.$fixedColumnsRight) {
      this.$fixedColumnsRight.html('').css('width', '')
    }

    this.initFixedColumnsBody()
    this.initFixedColumnsEvents()
  }

  initFixedColumnsBody () {
    const initFixedBody = ($fixedColumns, $fixedHeader) => {
      $fixedColumns.find('.fixed-table-body').remove()
      $fixedColumns.append(this.$tableBody.clone(true))

      const $fixedBody = $fixedColumns.find('.fixed-table-body')

      const tableBody = this.$tableBody.get(0)
      const scrollHeight = tableBody.scrollWidth > tableBody.clientWidth ?
        Utils.getScrollBarWidth() : 0
      const height = this.$tableContainer.outerHeight(true) - scrollHeight - 1

      $fixedColumns.css({
        height
      })

      $fixedBody.css({
        height: height - $fixedHeader.height()
      })

      return $fixedBody
    }

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedBody = initFixedBody(this.$fixedColumns, this.$fixedHeader)
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedBodyRight = initFixedBody(this.$fixedColumnsRight, this.$fixedHeaderRight)
      this.$fixedBodyRight.scrollLeft(this.$fixedBodyRight.find('table').width())
      this.$fixedBodyRight.css('overflow-y', this.options.height ? 'auto' : 'hidden')
    }
  }

  getFixedColumnsWidth (isRight) {
    let visibleFields = this.getVisibleFields()
    let width = 0
    let fixedNumber = this.options.fixedNumber
    let marginRight = 0

    if (isRight) {
      visibleFields = visibleFields.reverse()
      fixedNumber = this.options.fixedRightNumber
      marginRight = parseInt(this.$tableHeader.css('margin-right'), 10)
    }

    for (let i = 0; i < fixedNumber; i++) {
      width += this.$header.find(`th[data-field="${visibleFields[i]}"]`).outerWidth(true)
    }

    return width + marginRight + 1
  }

  initFixedColumnsEvents () {
    const toggleHover = (e, toggle) => {
      const tr = `tr[data-index="${$(e.currentTarget).data('index')}"]`
      let $trs = this.$tableBody.find(tr)

      if (this.$fixedBody) {
        $trs = $trs.add(this.$fixedBody.find(tr))
      }
      if (this.$fixedBodyRight) {
        $trs = $trs.add(this.$fixedBodyRight.find(tr))
      }

      $trs.css('background-color', toggle ? $(e.currentTarget).css('background-color') : '')
    }

    this.$tableBody.find('tr').hover(e => {
      toggleHover(e, true)
    }, e => {
      toggleHover(e, false)
    })

    const isFirefox = typeof navigator !== 'undefined' &&
      navigator.userAgent.toLowerCase().indexOf('firefox') > -1
    const mousewheel = isFirefox ? 'DOMMouseScroll' : 'mousewheel'
    const updateScroll = (e, fixedBody) => {
      const normalized = normalizeWheel(e)
      const deltaY = Math.ceil(normalized.pixelY)
      const top = this.$tableBody.scrollTop() + deltaY

      if (
        deltaY < 0 && top > 0 ||
        deltaY > 0 && top < fixedBody.scrollHeight - fixedBody.clientHeight
      ) {
        e.preventDefault()
      }

      this.$tableBody.scrollTop(top)
      if (this.$fixedBody) {
        this.$fixedBody.scrollTop(top)
      }
      if (this.$fixedBodyRight) {
        this.$fixedBodyRight.scrollTop(top)
      }
    }

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedBody.find('tr').hover(e => {
        toggleHover(e, true)
      }, e => {
        toggleHover(e, false)
      })

      this.$fixedBody[0].addEventListener(mousewheel, e => {
        updateScroll(e, this.$fixedBody[0])
      })
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedBodyRight.find('tr').hover(e => {
        toggleHover(e, true)
      }, e => {
        toggleHover(e, false)
      })

      this.$fixedBodyRight.off('scroll').on('scroll', () => {
        const top = this.$fixedBodyRight.scrollTop()

        this.$tableBody.scrollTop(top)
        if (this.$fixedBody) {
          this.$fixedBody.scrollTop(top)
        }
      })
    }

    if (this.options.filterControl) {
      $(this.$fixedColumns).off('keyup change').on('keyup change', e => {
        const $target = $(e.target)
        const value = $target.val()
        const field = $target.parents('th').data('field')
        const $coreTh = this.$header.find(`th[data-field="${field}"]`)

        if ($target.is('input')) {
          $coreTh.find('input').val(value)
        } else if ($target.is('select')) {
          const $select = $coreTh.find('select')

          $select.find('option[selected]').removeAttr('selected')
          $select.find(`option[value="${value}"]`).attr('selected', true)
        }

        this.triggerSearch()
      })
    }
  }

  renderStickyHeader () {
    if (!this.options.stickyHeader) {
      return
    }

    this.$stickyContainer = this.$container.find('.sticky-header-container')
    super.renderStickyHeader()

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedColumns.css('z-index', 101)
        .find('.sticky-header-container')
        .css('right', '')
        .width(this.$fixedColumns.outerWidth())
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      const $stickyHeaderContainerRight = this.$fixedColumnsRight.find('.sticky-header-container')

      this.$fixedColumnsRight.css('z-index', 101)
      $stickyHeaderContainerRight.css('left', '')
        .scrollLeft($stickyHeaderContainerRight.find('.table').outerWidth())
        .width(this.$fixedColumnsRight.outerWidth())
    }
  }

  matchPositionX () {
    if (!this.options.stickyHeader) {
      return
    }

    this.$stickyContainer.eq(0).scrollLeft(this.$tableBody.scrollLeft())
  }
}
<commit_msg>Fixed fixedColumns toogleView display bug (#5413)<commit_after>/**
 * @author zhixin wen <wenzhixin2010@gmail.com>
 */

const Utils = $.fn.bootstrapTable.utils

// Reasonable defaults
const PIXEL_STEP = 10
const LINE_HEIGHT = 40
const PAGE_HEIGHT = 800

function normalizeWheel (event) {
  let sX = 0 // spinX
  let sY = 0 // spinY
  let pX = 0 // pixelX
  let pY = 0 // pixelY

  // Legacy
  if ('detail' in event) { sY = event.detail }
  if ('wheelDelta' in event) { sY = -event.wheelDelta / 120 }
  if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120 }
  if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120 }

  // side scrolling on FF with DOMMouseScroll
  if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
    sX = sY
    sY = 0
  }

  pX = sX * PIXEL_STEP
  pY = sY * PIXEL_STEP

  if ('deltaY' in event) { pY = event.deltaY }
  if ('deltaX' in event) { pX = event.deltaX }

  if ((pX || pY) && event.deltaMode) {
    if (event.deltaMode === 1) { // delta in LINE units
      pX *= LINE_HEIGHT
      pY *= LINE_HEIGHT
    } else { // delta in PAGE units
      pX *= PAGE_HEIGHT
      pY *= PAGE_HEIGHT
    }
  }

  // Fall-back if spin cannot be determined
  if (pX && !sX) { sX = (pX < 1) ? -1 : 1 }
  if (pY && !sY) { sY = (pY < 1) ? -1 : 1 }

  return {
    spinX: sX,
    spinY: sY,
    pixelX: pX,
    pixelY: pY
  }
}

$.extend($.fn.bootstrapTable.defaults, {
  fixedColumns: false,
  fixedNumber: 0,
  fixedRightNumber: 0
})

$.BootstrapTable = class extends $.BootstrapTable {

  fixedColumnsSupported () {
    return this.options.fixedColumns &&
      !this.options.detailView &&
      !this.options.cardView
  }

  initContainer () {
    super.initContainer()

    if (!this.fixedColumnsSupported()) {
      return
    }

    if (this.options.fixedNumber) {
      this.$tableContainer.append('

')
      this.$fixedColumns = this.$tableContainer.find('.fixed-columns')
    }

    if (this.options.fixedRightNumber) {
      this.$tableContainer.append('

')
      this.$fixedColumnsRight = this.$tableContainer.find('.fixed-columns-right')
    }
  }

  initBody (...args) {
    super.initBody(...args)

    if (this.$fixedColumns && this.$fixedColumns.length) {
      this.$fixedColumns.toggle(this.fixedColumnsSupported())
    }
    if (this.$fixedColumnsRight && this.$fixedColumnsRight.length) {
      this.$fixedColumnsRight.toggle(this.fixedColumnsSupported())
    }

    if (!this.fixedColumnsSupported()) {
      return
    }

    if (this.options.showHeader && this.options.height) {
      return
    }

    this.initFixedColumnsBody()
    this.initFixedColumnsEvents()
  }

  trigger (...args) {
    super.trigger(...args)

    if (!this.fixedColumnsSupported()) {
      return
    }

    if (args[0] === 'post-header') {
      this.initFixedColumnsHeader()
    } else if (args[0] === 'scroll-body') {
      if (this.needFixedColumns && this.options.fixedNumber) {
        this.$fixedBody.scrollTop(this.$tableBody.scrollTop())
      }

      if (this.needFixedColumns && this.options.fixedRightNumber) {
        this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop())
      }
    }
  }

  updateSelected () {
    super.updateSelected()

    if (!this.fixedColumnsSupported()) {
      return
    }

    this.$tableBody.find('tr').each((i, el) => {
      const $el = $(el)
      const index = $el.data('index')
      const classes = $el.attr('class')

      const inputSelector = `[name="${this.options.selectItemName}"]`
      const $input = $el.find(inputSelector)

      if (typeof index === undefined) {
        return
      }

      const updateFixedBody = ($fixedHeader, $fixedBody) => {
        const $tr = $fixedBody.find(`tr[data-index="${index}"]`)

        $tr.attr('class', classes)

        if ($input.length) {
          $tr.find(inputSelector).prop('checked', $input.prop('checked'))
        }

        if (this.$selectAll.length) {
          $fixedHeader.add($fixedBody)
            .find('[name="btSelectAll"]')
            .prop('checked', this.$selectAll.prop('checked'))
        }
      }

      if (this.$fixedBody && this.options.fixedNumber) {
        updateFixedBody(this.$fixedHeader, this.$fixedBody)
      }

      if (this.$fixedBodyRight && this.options.fixedRightNumber) {
        updateFixedBody(this.$fixedHeaderRight, this.$fixedBodyRight)
      }
    })
  }

  hideLoading () {
    super.hideLoading()

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedColumns.find('.fixed-table-loading').hide()
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedColumnsRight.find('.fixed-table-loading').hide()
    }
  }

  initFixedColumnsHeader () {
    if (this.options.height) {
      this.needFixedColumns = this.$tableHeader.outerWidth(true) < this.$tableHeader.find('table').outerWidth(true)
    } else {
      this.needFixedColumns = this.$tableBody.outerWidth(true) < this.$tableBody.find('table').outerWidth(true)
    }

    const initFixedHeader = ($fixedColumns, isRight) => {
      $fixedColumns.find('.fixed-table-header').remove()
      $fixedColumns.append(this.$tableHeader.clone(true))

      $fixedColumns.css({
        width: this.getFixedColumnsWidth(isRight)
      })
      return $fixedColumns.find('.fixed-table-header')
    }

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedHeader = initFixedHeader(this.$fixedColumns)
      this.$fixedHeader.css('margin-right', '')
    } else if (this.$fixedColumns) {
      this.$fixedColumns.html('').css('width', '')
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedHeaderRight = initFixedHeader(this.$fixedColumnsRight, true)
      this.$fixedHeaderRight.scrollLeft(this.$fixedHeaderRight.find('table').width())
    } else if (this.$fixedColumnsRight) {
      this.$fixedColumnsRight.html('').css('width', '')
    }

    this.initFixedColumnsBody()
    this.initFixedColumnsEvents()
  }

  initFixedColumnsBody () {
    const initFixedBody = ($fixedColumns, $fixedHeader) => {
      $fixedColumns.find('.fixed-table-body').remove()
      $fixedColumns.append(this.$tableBody.clone(true))

      const $fixedBody = $fixedColumns.find('.fixed-table-body')

      const tableBody = this.$tableBody.get(0)
      const scrollHeight = tableBody.scrollWidth > tableBody.clientWidth ?
        Utils.getScrollBarWidth() : 0
      const height = this.$tableContainer.outerHeight(true) - scrollHeight - 1

      $fixedColumns.css({
        height
      })

      $fixedBody.css({
        height: height - $fixedHeader.height()
      })

      return $fixedBody
    }

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedBody = initFixedBody(this.$fixedColumns, this.$fixedHeader)
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedBodyRight = initFixedBody(this.$fixedColumnsRight, this.$fixedHeaderRight)
      this.$fixedBodyRight.scrollLeft(this.$fixedBodyRight.find('table').width())
      this.$fixedBodyRight.css('overflow-y', this.options.height ? 'auto' : 'hidden')
    }
  }

  getFixedColumnsWidth (isRight) {
    let visibleFields = this.getVisibleFields()
    let width = 0
    let fixedNumber = this.options.fixedNumber
    let marginRight = 0

    if (isRight) {
      visibleFields = visibleFields.reverse()
      fixedNumber = this.options.fixedRightNumber
      marginRight = parseInt(this.$tableHeader.css('margin-right'), 10)
    }

    for (let i = 0; i < fixedNumber; i++) {
      width += this.$header.find(`th[data-field="${visibleFields[i]}"]`).outerWidth(true)
    }

    return width + marginRight + 1
  }

  initFixedColumnsEvents () {
    const toggleHover = (e, toggle) => {
      const tr = `tr[data-index="${$(e.currentTarget).data('index')}"]`
      let $trs = this.$tableBody.find(tr)

      if (this.$fixedBody) {
        $trs = $trs.add(this.$fixedBody.find(tr))
      }
      if (this.$fixedBodyRight) {
        $trs = $trs.add(this.$fixedBodyRight.find(tr))
      }

      $trs.css('background-color', toggle ? $(e.currentTarget).css('background-color') : '')
    }

    this.$tableBody.find('tr').hover(e => {
      toggleHover(e, true)
    }, e => {
      toggleHover(e, false)
    })

    const isFirefox = typeof navigator !== 'undefined' &&
      navigator.userAgent.toLowerCase().indexOf('firefox') > -1
    const mousewheel = isFirefox ? 'DOMMouseScroll' : 'mousewheel'
    const updateScroll = (e, fixedBody) => {
      const normalized = normalizeWheel(e)
      const deltaY = Math.ceil(normalized.pixelY)
      const top = this.$tableBody.scrollTop() + deltaY

      if (
        deltaY < 0 && top > 0 ||
        deltaY > 0 && top < fixedBody.scrollHeight - fixedBody.clientHeight
      ) {
        e.preventDefault()
      }

      this.$tableBody.scrollTop(top)
      if (this.$fixedBody) {
        this.$fixedBody.scrollTop(top)
      }
      if (this.$fixedBodyRight) {
        this.$fixedBodyRight.scrollTop(top)
      }
    }

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedBody.find('tr').hover(e => {
        toggleHover(e, true)
      }, e => {
        toggleHover(e, false)
      })

      this.$fixedBody[0].addEventListener(mousewheel, e => {
        updateScroll(e, this.$fixedBody[0])
      })
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      this.$fixedBodyRight.find('tr').hover(e => {
        toggleHover(e, true)
      }, e => {
        toggleHover(e, false)
      })

      this.$fixedBodyRight.off('scroll').on('scroll', () => {
        const top = this.$fixedBodyRight.scrollTop()

        this.$tableBody.scrollTop(top)
        if (this.$fixedBody) {
          this.$fixedBody.scrollTop(top)
        }
      })
    }

    if (this.options.filterControl) {
      $(this.$fixedColumns).off('keyup change').on('keyup change', e => {
        const $target = $(e.target)
        const value = $target.val()
        const field = $target.parents('th').data('field')
        const $coreTh = this.$header.find(`th[data-field="${field}"]`)

        if ($target.is('input')) {
          $coreTh.find('input').val(value)
        } else if ($target.is('select')) {
          const $select = $coreTh.find('select')

          $select.find('option[selected]').removeAttr('selected')
          $select.find(`option[value="${value}"]`).attr('selected', true)
        }

        this.triggerSearch()
      })
    }
  }

  renderStickyHeader () {
    if (!this.options.stickyHeader) {
      return
    }

    this.$stickyContainer = this.$container.find('.sticky-header-container')
    super.renderStickyHeader()

    if (this.needFixedColumns && this.options.fixedNumber) {
      this.$fixedColumns.css('z-index', 101)
        .find('.sticky-header-container')
        .css('right', '')
        .width(this.$fixedColumns.outerWidth())
    }

    if (this.needFixedColumns && this.options.fixedRightNumber) {
      const $stickyHeaderContainerRight = this.$fixedColumnsRight.find('.sticky-header-container')

      this.$fixedColumnsRight.css('z-index', 101)
      $stickyHeaderContainerRight.css('left', '')
        .scrollLeft($stickyHeaderContainerRight.find('.table').outerWidth())
        .width(this.$fixedColumnsRight.outerWidth())
    }
  }

  matchPositionX () {
    if (!this.options.stickyHeader) {
      return
    }

    this.$stickyContainer.eq(0).scrollLeft(this.$tableBody.scrollLeft())
  }
}
<|endoftext|>


<commit_before>import path from 'path';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import fs from 'fs';

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const dirBuild = path.resolve(__dirname, './build');
const dirSrc = path.resolve(__dirname, './src');

if (!fs.existsSync(dirBuild)) {
    fs.mkdirSync(dirBuild);
}

export default {
    entry: {
        app: [path.join(dirSrc, 'app.js')],
        fireworks: [path.join(dirSrc, './js/helpers/fireworks.js')],
    },
    output: {
        path: dirBuild,
        filename: './js/[name].bundle.js',
    },
    module: {
        rules: [
            // JavaScript
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: [
                    'babel-loader?presets[]=es2015,presets[]=react,presets[]=stage-2,plugins[]=transform-runtime,plugins[]=transform-class-properties,plugins[]=transform-export-extensions', // eslint-disable-line
                    'eslint-loader',
                ],
            },
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        {
                            loader: 'css-loader',
                            query: {
                                sourceMap: true,
                                minimize: true,
                                modules: true,
                                importLoaders: 1,
                                localIdentName: '[name]__[local]___[hash:base64:5]',
                            },
                        },
                        { loader: 'postcss-loader' },
                    ],
                }),
            },
            // Fonts
            /* eslint-disable max-len */
            {
                test: /\.woff(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/font-woff',
            },
            {
                test: /\.woff2(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/font-woff2',
            },
            {
                test: /\.ttf(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/octet-stream',
            },
            {
                test: /\.eot(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/font-otf',
            }, /* eslint-enable */
            {
                test: /\.svg([?#].*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=image/svg+xml',
            },
        ],
    },
    plugins: [
        new CopyWebpackPlugin([
            { from: path.join(dirSrc, 'index.html'), to: dirBuild },
        ]),
        new ExtractTextPlugin({
            filename: './styles/styles.css',
            allChunks: false,
            ignoreOrder: true,
        }),
        new BundleAnalyzerPlugin({
            // Can be `server`, `static` or `disabled`.
            // In `server` mode analyzer will start HTTP server to show bundle report.
            // In `static` mode single HTML file with bundle report will be generated.
            // In `disabled` mode you can use this plugin to just generate Webpack Stats JSON file by setting `generateStatsFile` to `true`.
            analyzerMode: 'server',
            // Host that will be used in `server` mode to start HTTP server.
            analyzerHost: '127.0.0.1',
            // Port that will be used in `server` mode to start HTTP server.
            analyzerPort: 8888,
            // Path to bundle report file that will be generated in `static` mode.
            // Relative to bundles output directory.
            reportFilename: 'report.html',
            // Module sizes to show in report by default.
            // Should be one of `stat`, `parsed` or `gzip`.
            // See "Definitions" section for more information.
            defaultSizes: 'parsed',
            // Automatically open report in default browser
            openAnalyzer: true,
            // If `true`, Webpack Stats JSON file will be generated in bundles output directory
            generateStatsFile: false,
            // Name of Webpack Stats JSON file that will be generated if `generateStatsFile` is `true`.
            // Relative to bundles output directory.
            statsFilename: 'stats.json',
            // Options for `stats.toJson()` method.
            // For example you can exclude sources of your modules from stats file with `source: false` option.
            // See more options here: https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
            statsOptions: null,
            // Log level. Can be 'info', 'warn', 'error' or 'silent'.
            logLevel: 'info',
        }),
    ],
    devtool: 'source-map',
    context: __dirname,
    devServer: {
        stats: {
            colors: true,
            version: false,
            hash: true,
            timings: true,
            chunks: false,
            chunkModules: false,
            children: false,
        },
    },
    // Ignore these as required by Enzyme http://airbnb.io/enzyme/docs/guides/webpack.html
    externals: {
        cheerio: 'window',
        'react/addons': true,
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': true,
    },
};
<commit_msg>Disables analyze server<commit_after>import path from 'path';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import fs from 'fs';

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const dirBuild = path.resolve(__dirname, './build');
const dirSrc = path.resolve(__dirname, './src');

if (!fs.existsSync(dirBuild)) {
    fs.mkdirSync(dirBuild);
}

export default {
    entry: {
        app: [path.join(dirSrc, 'app.js')],
        fireworks: [path.join(dirSrc, './js/helpers/fireworks.js')],
    },
    output: {
        path: dirBuild,
        filename: './js/[name].bundle.js',
    },
    module: {
        rules: [
            // JavaScript
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: [
                    'babel-loader?presets[]=es2015,presets[]=react,presets[]=stage-2,plugins[]=transform-runtime,plugins[]=transform-class-properties,plugins[]=transform-export-extensions', // eslint-disable-line
                    'eslint-loader',
                ],
            },
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        {
                            loader: 'css-loader',
                            query: {
                                sourceMap: true,
                                minimize: true,
                                modules: true,
                                importLoaders: 1,
                                localIdentName: '[name]__[local]___[hash:base64:5]',
                            },
                        },
                        { loader: 'postcss-loader' },
                    ],
                }),
            },
            // Fonts
            /* eslint-disable max-len */
            {
                test: /\.woff(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/font-woff',
            },
            {
                test: /\.woff2(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/font-woff2',
            },
            {
                test: /\.ttf(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/octet-stream',
            },
            {
                test: /\.eot(\?.*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=application/font-otf',
            }, /* eslint-enable */
            {
                test: /\.svg([?#].*)?$/,
                loader: 'url-loader?name=/fonts/[name].[ext]&limit=10000&mimetype=image/svg+xml',
            },
        ],
    },
    plugins: [
        new CopyWebpackPlugin([
            { from: path.join(dirSrc, 'index.html'), to: dirBuild },
        ]),
        new ExtractTextPlugin({
            filename: './styles/styles.css',
            allChunks: false,
            ignoreOrder: true,
        }),
        new BundleAnalyzerPlugin({
            // Can be `server`, `static` or `disabled`.
            analyzerMode: 'static',
            analyzerHost: 'localhost',
            analyzerPort: 8888,
            reportFilename: 'report.html',
            defaultSizes: 'parsed',
            openAnalyzer: false,
            generateStatsFile: false,
            statsOptions: null,
            logLevel: 'info',
        }),
    ],
    devtool: 'source-map',
    context: __dirname,
    devServer: {
        stats: {
            colors: true,
            version: false,
            hash: true,
            timings: true,
            chunks: false,
            chunkModules: false,
            children: false,
        },
    },
    // Ignore these as required by Enzyme http://airbnb.io/enzyme/docs/guides/webpack.html
    externals: {
        cheerio: 'window',
        'react/addons': true,
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': true,
    },
};
<|endoftext|>