<commit_before>/**
* iFrame api mapping support
*
* Client side ( binds a given iFrames to expose the player api )
*/

( function( mw ) {

mw.IFramePlayerApiClient = function( iframe, playerProxy ){
	return this.init( iframe , playerProxy );
};
mw.IFramePlayerApiClient.prototype = {
	'exportedMethods': [
		'play',
		'pause',
		'stop',
		'resizePlayer',
		'proxyAcknowledgment'
	],
	// Local store of the previous sate of player proxy
	'_prevPlayerProxy': {},

	// Stores the current playerProxy ( can be updated by user js )
	'init': function( iframe , playerProxy, options ){
		this.iframe = iframe;
		this.playerProxy = playerProxy;

		// Set the iframe server
		var srcParts = mw.parseUri( mw.absoluteUrl( $j(this.iframe).attr('src') ) );
		this.iframeServer = srcParts.protocol + '://' + srcParts.authority;

		this.addPlayerSendApi();
		this.addPlayerReciveApi();

		this.addIframeFullscreenBinding();

	},
	'addPlayerSendApi': function(){
		var _this = this;

		// Allow modules to extend the list of iframeExported bindings
		$j( mw ).trigger( 'AddIframePlayerMethods', [ this.exportedMethods ]);

		$j.each( this.exportedMethods, function(na, method){
			_this.playerProxy[ method ] = function(){
				_this.postMessage( {
					'method' : method,
					'args' : $j.makeArray( arguments )
				} );
			};
		});
	},
	'addPlayerReciveApi': function(){
		var _this = this;

		$j.receiveMessage( function( event ){
			_this.hanldeReciveMsg( event );
		}, this.iframeServer);
	},
	'addIframeFullscreenBinding': function(){
		var _this = this;
		parentsAbsoluteList = [];
		var fullscreenMode = false;
		var orgSize  = {
			'width' : $j( _this.iframe ).width(),
			'height' : $j( _this.iframe ).height(),
			'position' : null
		};

		// Add a local scope variable to register
		// local scope fullscreen calls on orientation change
		// ( without this variable we would call fullscreen on all iframes on
		// orientation change )
		var localIframeInFullscreen = false;

		// Bind orientation change to resize player ( if fullscreen )
		$j(window).bind( 'orientationchange', function(e){
			if( localIframeInFullscreen ){
				doFullscreen();
			}
		});

		var doFullscreen = function(){
			mw.log("iframeClient:: doFullscreen()");
			localIframeInFullscreen = true;
			// Make the iframe fullscreen
			$j( _this.iframe )
				.css({
					'z-index': mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) + 1,
					'position': 'absolute',
					'top' : 0,
					'left' : 0,
					'width' : $j(window).width(),
					'height' : $j(window).height()
				})
				.data(
					'isFullscreen', true
				);

			// Remove absolute css of the interface parents
			$j( _this.iframe ).parents().each( function() {
				//mw.log(' parent : ' + $j( this ).attr('id' ) + ' class: ' + $j( this ).attr('class') + ' pos: ' + $j( this ).css( 'position' ) );
				if( $j( this ).css( 'position' ) == 'absolute' ) {
					parentsAbsoluteList.push( $j( this ) );
					$j( this ).css( 'position', null );
				}
			} );
		}
		var restoreWindowMode = function(){
			localIframeInFullscreen = false;
			$j( _this.iframe )
				.css( orgSize )
				.data(
					'isFullscreen', false
				)
			// restore any parent absolute pos:
			$j(parentsAbsoluteList).each( function() {
				$j( this ).css( 'position', 'absolute' );
			} );
		};

		$j( this.playerProxy ).bind( 'onOpenFullScreen', doFullscreen);
		$j( this.playerProxy ).bind( 'onCloseFullScreen', restoreWindowMode);

	},
	/**
	 * Handle received events
	 */
	'hanldeReciveMsg': function( event ){
		var _this = this;
		//mw.log('IFramePlayerApiClient::hanldeReciveMsg:' + event.data );

		// Decode the message
		var msgObject = JSON.parse( event.data );
		var playerAttributes = mw.getConfig( 'EmbedPlayer.Attributes' );

		// check if the message object is for "this" player
		if( msgObject.playerId !=  _this.playerProxy.id ){
			// mw.log(' hanldeReciveMsg (skiped ) ' + msgObject.playerId + ' != ' + _this.playerProxy.id );
			return ;
		}

		// Before we update local attributes check that the object has not been updated by user js
		for( var attrName in playerAttributes ){
			if( attrName != 'id' ){
				if( _this._prevPlayerProxy[ attrName ] != _this.playerProxy[ attrName ] ){
					//mw.log( "IFramePlayerApiClient:: User js update:" + attrName + ' set to: ' + this.playerProxy[ attrName ] + ' != old: ' + _this._prevPlayerProxy[ attrName ] );
					// Send the updated attribute back to the iframe:
					_this.postMessage({
						'attrName' : attrName,
						'attrValue' : _this.playerProxy[ attrName ]
	 				});
				}
			}
		}

		// Update any attributes
		if( msgObject.attributes ){
			for( var i in msgObject.attributes ){
				if( i != 'id' && i != 'class' && i != 'style' ){
					try{
						this.playerProxy[ i ] = msgObject.attributes[i];
						this._prevPlayerProxy[i] = msgObject.attributes[i];
					} catch( e ){
						mw.log("Error could not set:" + i );
					}
				}
			}
		}
		//mw.log("handle event method name: " + msgObject.triggerName );

		// Trigger any binding events
		if( typeof msgObject.triggerName != 'undefined' && msgObject.triggerArgs != 'undefined') {
			// mw.log('IFramePlayerApiClient::hanldeReciveMsgt: trigger: ' + msgObject.triggerName );
			$j( _this.playerProxy ).trigger( msgObject.triggerName, msgObject.triggerArgs );
		}
	},
	'postMessage': function( msgObject ){
		/*mw.log( "IFramePlayerApiClient:: postMessage(): " + JSON.stringify( msgObject ) +
				' iframe: ' +  this.iframe + ' cw:' + this.iframe.contentWindow +
				' src: ' + mw.absoluteUrl( $j( this.iframe ).attr('src')  ) );*/
		$j.postMessage(
			JSON.stringify( msgObject ),
			mw.absoluteUrl( $j( this.iframe ).attr('src') ),
			this.iframe.contentWindow
		);
	}
};

//Add the jQuery binding
jQuery.fn.iFramePlayer = function( readyCallback ){
	if( ! this.selector ){
		this.selector = $j( this );
	}
	// Handle each embed frame
	$j( this.selector ).each( function( inx, targetPlayer ){
		mw.log( "$.iFramePlayer::" + targetPlayer.id );
		// Append '_ifp' ( iframe player ) to id of real iframe so that 'id', and 'src' attributes don't conflict
		var playerProxyId = ( $j( targetPlayer ).attr( 'id' ) )? $j( targetPlayer ).attr( 'id' ) : Math.floor( 9999999 * Math.random() );
		var iframePlayerId = playerProxyId + '_ifp' ;

		// Update the id and append the div element proxy after the iframe
		$j( targetPlayer)
			.attr('id', iframePlayerId)
			.after(
				$j('<div />')
				.attr( 'id', playerProxyId )
			);

		var playerProxy = $j( '#' + playerProxyId ).get(0);

		// Allow modules to extend the 'iframe' based player
		$j( mw ).trigger( 'newIframePlayerClientSide', [ playerProxy ] );

		// Once the proxy ready event is received from the server complete the handshake
		// and send the proxyAcknowledgment back to the iframe server
		$j( playerProxy ).bind('proxyReady', function(){
			playerProxy.proxyAcknowledgment();
		});
		// Bind the iFrame player ready callback
		if( readyCallback ){
			$j( playerProxy ).bind( 'playerReady', readyCallback );
		};

		// Setup the iframe:
		var iframe = $j('#' + iframePlayerId).get(0);
		if( !iframe ){
			mw.log("$.iFramePlayer:: Error invalid iFramePlayer request");
			return false;
		}
		if( !iframe['playerApi'] ){
			iframe['playerApi'] = new mw.IFramePlayerApiClient( iframe, playerProxy );
		}
	});
	// Return this ( jQuery style )
	return this;
};

} )( window.mw );
<commit_msg>wrap instead of after for iframe proxy ( so that remove by id works )<commit_after>/**
* iFrame api mapping support
*
* Client side ( binds a given iFrames to expose the player api )
*/

( function( mw ) {

mw.IFramePlayerApiClient = function( iframe, playerProxy ){
	return this.init( iframe , playerProxy );
};
mw.IFramePlayerApiClient.prototype = {
	'exportedMethods': [
		'play',
		'pause',
		'stop',
		'resizePlayer',
		'proxyAcknowledgment'
	],
	// Local store of the previous sate of player proxy
	'_prevPlayerProxy': {},

	// Stores the current playerProxy ( can be updated by user js )
	'init': function( iframe , playerProxy, options ){
		this.iframe = iframe;
		this.playerProxy = playerProxy;

		// Set the iframe server
		var srcParts = mw.parseUri( mw.absoluteUrl( $j(this.iframe).attr('src') ) );
		this.iframeServer = srcParts.protocol + '://' + srcParts.authority;

		this.addPlayerSendApi();
		this.addPlayerReciveApi();

		this.addIframeFullscreenBinding();

	},
	'addPlayerSendApi': function(){
		var _this = this;

		// Allow modules to extend the list of iframeExported bindings
		$j( mw ).trigger( 'AddIframePlayerMethods', [ this.exportedMethods ]);

		$j.each( this.exportedMethods, function(na, method){
			_this.playerProxy[ method ] = function(){
				_this.postMessage( {
					'method' : method,
					'args' : $j.makeArray( arguments )
				} );
			};
		});
	},
	'addPlayerReciveApi': function(){
		var _this = this;

		$j.receiveMessage( function( event ){
			_this.hanldeReciveMsg( event );
		}, this.iframeServer);
	},
	'addIframeFullscreenBinding': function(){
		var _this = this;
		parentsAbsoluteList = [];
		var fullscreenMode = false;
		var orgSize  = {
			'width' : $j( _this.iframe ).width(),
			'height' : $j( _this.iframe ).height(),
			'position' : null
		};

		// Add a local scope variable to register
		// local scope fullscreen calls on orientation change
		// ( without this variable we would call fullscreen on all iframes on
		// orientation change )
		var localIframeInFullscreen = false;

		// Bind orientation change to resize player ( if fullscreen )
		$j(window).bind( 'orientationchange', function(e){
			if( localIframeInFullscreen ){
				doFullscreen();
			}
		});

		var doFullscreen = function(){
			mw.log("iframeClient:: doFullscreen()");
			localIframeInFullscreen = true;
			// Make the iframe fullscreen
			$j( _this.iframe )
				.css({
					'z-index': mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) + 1,
					'position': 'absolute',
					'top' : 0,
					'left' : 0,
					'width' : $j(window).width(),
					'height' : $j(window).height()
				})
				.data(
					'isFullscreen', true
				);

			// Remove absolute css of the interface parents
			$j( _this.iframe ).parents().each( function() {
				//mw.log(' parent : ' + $j( this ).attr('id' ) + ' class: ' + $j( this ).attr('class') + ' pos: ' + $j( this ).css( 'position' ) );
				if( $j( this ).css( 'position' ) == 'absolute' ) {
					parentsAbsoluteList.push( $j( this ) );
					$j( this ).css( 'position', null );
				}
			} );
		}
		var restoreWindowMode = function(){
			localIframeInFullscreen = false;
			$j( _this.iframe )
				.css( orgSize )
				.data(
					'isFullscreen', false
				)
			// restore any parent absolute pos:
			$j(parentsAbsoluteList).each( function() {
				$j( this ).css( 'position', 'absolute' );
			} );
		};

		$j( this.playerProxy ).bind( 'onOpenFullScreen', doFullscreen);
		$j( this.playerProxy ).bind( 'onCloseFullScreen', restoreWindowMode);

	},
	/**
	 * Handle received events
	 */
	'hanldeReciveMsg': function( event ){
		var _this = this;
		//mw.log('IFramePlayerApiClient::hanldeReciveMsg:' + event.data );

		// Decode the message
		var msgObject = JSON.parse( event.data );
		var playerAttributes = mw.getConfig( 'EmbedPlayer.Attributes' );

		// check if the message object is for "this" player
		if( msgObject.playerId !=  _this.playerProxy.id ){
			// mw.log(' hanldeReciveMsg (skiped ) ' + msgObject.playerId + ' != ' + _this.playerProxy.id );
			return ;
		}

		// Before we update local attributes check that the object has not been updated by user js
		for( var attrName in playerAttributes ){
			if( attrName != 'id' ){
				if( _this._prevPlayerProxy[ attrName ] != _this.playerProxy[ attrName ] ){
					//mw.log( "IFramePlayerApiClient:: User js update:" + attrName + ' set to: ' + this.playerProxy[ attrName ] + ' != old: ' + _this._prevPlayerProxy[ attrName ] );
					// Send the updated attribute back to the iframe:
					_this.postMessage({
						'attrName' : attrName,
						'attrValue' : _this.playerProxy[ attrName ]
	 				});
				}
			}
		}

		// Update any attributes
		if( msgObject.attributes ){
			for( var i in msgObject.attributes ){
				if( i != 'id' && i != 'class' && i != 'style' ){
					try{
						this.playerProxy[ i ] = msgObject.attributes[i];
						this._prevPlayerProxy[i] = msgObject.attributes[i];
					} catch( e ){
						mw.log("Error could not set:" + i );
					}
				}
			}
		}
		//mw.log("handle event method name: " + msgObject.triggerName );

		// Trigger any binding events
		if( typeof msgObject.triggerName != 'undefined' && msgObject.triggerArgs != 'undefined') {
			// mw.log('IFramePlayerApiClient::hanldeReciveMsgt: trigger: ' + msgObject.triggerName );
			$j( _this.playerProxy ).trigger( msgObject.triggerName, msgObject.triggerArgs );
		}
	},
	'postMessage': function( msgObject ){
		/*mw.log( "IFramePlayerApiClient:: postMessage(): " + JSON.stringify( msgObject ) +
				' iframe: ' +  this.iframe + ' cw:' + this.iframe.contentWindow +
				' src: ' + mw.absoluteUrl( $j( this.iframe ).attr('src')  ) );*/
		$j.postMessage(
			JSON.stringify( msgObject ),
			mw.absoluteUrl( $j( this.iframe ).attr('src') ),
			this.iframe.contentWindow
		);
	}
};

//Add the jQuery binding
jQuery.fn.iFramePlayer = function( readyCallback ){
	if( ! this.selector ){
		this.selector = $j( this );
	}
	// Handle each embed frame
	$j( this.selector ).each( function( inx, targetPlayer ){
		mw.log( "$.iFramePlayer::" + targetPlayer.id );
		// Append '_ifp' ( iframe player ) to id of real iframe so that 'id', and 'src' attributes don't conflict
		var playerProxyId = ( $j( targetPlayer ).attr( 'id' ) )? $j( targetPlayer ).attr( 'id' ) : Math.floor( 9999999 * Math.random() );
		var iframePlayerId = playerProxyId + '_ifp' ;

		// Update the id and wrap with the proxy
		$j( targetPlayer)
			.attr('id', iframePlayerId)
			.wrap(
				$j('<div />')
				.attr( 'id', playerProxyId )
			);

		var playerProxy = $j( '#' + playerProxyId ).get(0);

		// Allow modules to extend the 'iframe' based player
		$j( mw ).trigger( 'newIframePlayerClientSide', [ playerProxy ] );

		// Once the proxy ready event is received from the server complete the handshake
		// and send the proxyAcknowledgment back to the iframe server
		$j( playerProxy ).bind('proxyReady', function(){
			playerProxy.proxyAcknowledgment();
		});
		// Bind the iFrame player ready callback
		if( readyCallback ){
			$j( playerProxy ).bind( 'playerReady', readyCallback );
		};

		// Setup the iframe:
		var iframe = $j('#' + iframePlayerId).get(0);
		if( !iframe ){
			mw.log("$.iFramePlayer:: Error invalid iFramePlayer request");
			return false;
		}
		if( !iframe['playerApi'] ){
			iframe['playerApi'] = new mw.IFramePlayerApiClient( iframe, playerProxy );
		}
	});
	// Return this ( jQuery style )
	return this;
};

} )( window.mw );
<|endoftext|>


<commit_before>/**
 * Handlers for various widget types. The method signatures are always the same,
 * but each handler can handle them differently.
 */

var WIDGET_MARGIN_X = 20;
var WIDGET_MARGIN_Y = 60;

function _handleYoutube(container, config) {
    // Clean up all previous.
    container.selectAll('iframe').remove();
    var iframe = container.append('iframe');
    iframe
        .attr('width', config.width)
        .attr('height', config.height)
        .attr('src', config.dataSource)
        .attr('allowfullscreen')
        .attr('frameborder', 0)
}

function _handleC3(container, config) {
    var init_config = {
        bindto: '#' + normalizeName(config.name),
        legend: {
            show: true
        },
        size: {
            height: config.height - WIDGET_MARGIN_Y,
            width: config.width - WIDGET_MARGIN_X
        },
        data: {
            type: config.type,
            url: config.dataSource,
            mimeType: 'json'
        },
        onrendered: function(){
            unload(container);
        }
    };
    if(isOverride(config)) {
        // Just use the raw payload for this widgets' options.
        $.getJSON(config.dataSource, function(res){
            // Keep existing options if not specified.
            var config = $.extend(init_config, res);
            c3.generate(init_config);
        });
        return;
    }
    if(config.type === 'timeseries') {
        init_config['axis'] = {
            x: {type: 'timeseries'},
        };
        // Map the corresponding data key and list of dates
        // to the `x` property.
        init_config['data']['x'] = 'dates';
    }
    c3.generate(init_config);
}

function _handleD3(container, config) {
    // Clean up all D3 charts in one step.
    container.selectAll('svg').remove();
    // Handle specific types.
    if(config.type === 'radial-dendrogram') return _handleRadialDendrogram(container, config);
    if(config.type === 'dendrogram') return _handleDendrogram(container, config);
    if(config.type === 'voronoi') return _handleVoronoi(container, config);
    if(config.type === 'treemap') return _handleTreemap(container, config);
    if(config.type === 'circlepack') return _handleCirclePack(container, config);
    throw new Error('Unknown type: ' + config.type);
}

function _handleCirclePack(container, config) {
    // Adapted from https://bl.ocks.org/mbostock/4063530
    var margin = WIDGET_MARGIN_Y;
    var diameter = d3.max([config.width, config.height]) - margin;
    var format = d3.format(',d');

    var pack = d3.layout.pack()
        .size([diameter, diameter])
        .value(function(d) { return d.size; });

    var svg = container
        .append('svg')
        .attr('width', diameter)
        .attr('height', diameter)
        .append('g');

    d3.json(config.dataSource, function(error, data) {
        if(error) throw new Error("Could not load url: " + config.dataSource);

        var node = svg.datum(data).selectAll('.node')
        .data(pack.nodes)
        .enter().append('g')
        .attr('class', function(d) { return d.children ? 'node' : 'leaf node'; })
        .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });

        node.append('title')
        .text(function(d) { return d.name + (d.children ? '' : ': ' + format(d.size)); });

        node.append('circle')
        .attr('r', function(d) { return d.r; });

        node.filter(function(d) { return !d.children; }).append('text')
        .attr('dy', '.3em')
        .style('text-anchor', 'middle')
        .text(function(d) { return d.name.substring(0, d.r / 3); });
        unload(container);
    });

    d3.select(self.frameElement).style("height", diameter + "px");
}

function _handleTreemap(container, config) {
    // Adapted from http://bl.ocks.org/mbostock/4063582
    var margin = {
        top: WIDGET_MARGIN_Y / 2,
        bottom: WIDGET_MARGIN_Y / 2,
        left: WIDGET_MARGIN_X / 2,
        right: WIDGET_MARGIN_X / 2
    };
    var width = config.width - WIDGET_MARGIN_X;
    var height = config.height - WIDGET_MARGIN_Y;
    var color = d3.scale.category20c();
    var treemap = d3.layout.treemap()
        .size([width, height])
        .sticky(true)
        .value(function(d) { return d.size; });
    // Cleanup
    container.selectAll('.treemap').remove();
    var div = container
        .append('div')
        .classed({'treemap': true, 'chart-centered': true})
        .style('position', 'relative')
        .style('width', width + 'px')
        .style('height', height + 'px');

    d3.json(config.dataSource, function(error, root) {
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var node = div.datum(root).selectAll('.node')
            .data(treemap.nodes)
            .enter().append('div')
            .attr('class', 'node')
            .call(position)
            .style('border', '1px solid white')
            .style('font', '10px sans-serif')
            .style('line-height', '12px')
            .style('overflow', 'hidden')
            .style('position', 'absolute')
            .style('text-indent', '2px')
            .style('background', function(d) {
                return d.children ? color(d.name) : null;
            })
            .text(function(d) {
                return d.children ? null : d.name;
            });
        d3.selectAll('input').on('change', function change() {
            var value = this.value === 'count'
            ? function() { return 1; }
            : function(d) { return d.size;};
            node
            .data(treemap.value(value).nodes)
            .transition()
            .duration(1500)
            .call(position);
        });
    });

    function position() {
        this.style('left', function(d) { return d.x + 'px'; })
            .style('top', function(d) { return d.y + 'px'; })
            .style('width', function(d) { return Math.max(0, d.dx - 1) + 'px'; })
            .style('height', function(d) { return Math.max(0, d.dy - 1) + 'px'; });
    }
}

function _handleRadialDendrogram(container, config) {
    container.selectAll('svg').remove();
    // Code taken (and refactored for use here) from:
    // https://bl.ocks.org/mbostock/4339607
    var radius = (config.width > config.height ? config.width : config.height) / 2;
    var cluster = d3.layout.cluster()
        .size([360, radius * 0.65]); // reduce size relative to `radius`
    var diagonal = d3.svg.diagonal.radial()
        .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
    var svg = container.append('svg')
        .attr('width', radius * 2)
        .attr('height', radius * 2)
        .append('g')
        .attr('transform', 'translate(' + radius + ',' + radius + ')');
    d3.json(config.dataSource, function(error, root) {
        if (error) throw error;
        var nodes = cluster.nodes(root);
        var link = svg.selectAll('path.link')
            .data(cluster.links(nodes))
            .enter().append('path')
            .attr('class', 'link')
            .attr('d', diagonal);
        var node = svg.selectAll('g.node')
            .data(nodes)
            .enter().append('g')
            .attr('class', 'node')
            .attr('transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; })
        node.append('circle')
            .attr('r', 4.5);
        node.append('text')
            .attr('dy', '.31em')
            .attr('text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; })
            .attr('transform', function(d) { return d.x < 180 ? 'translate(8)' : 'rotate(180)translate(-8)'; })
            .text(function(d) { return d.name; });
        unload(container);
    });
    d3.select(self.frameElement).style('height', radius * 2 + 'px');
}

function _handleDendrogram(container, config) {
    container.selectAll('svg').remove();
    var PADDING = 100;
    var width = config.width - WIDGET_MARGIN_X;
    var height = config.height - WIDGET_MARGIN_Y;
    var cluster = d3.layout.cluster()
        .size([height, width - PADDING]);
    var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });
    var svg = container
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', 'translate(40,0)');

    d3.json(config.dataSource, function(error, root) {
        if(error) throw new Error('Could not load url: ' + config.dataSource);

        var nodes = cluster.nodes(root),
        links = cluster.links(nodes);

        var link = svg.selectAll('.link')
        .data(links)
        .enter().append('path')
        .attr('class', 'link')
        .attr('d', diagonal);

        var node = svg.selectAll('.node')
        .data(nodes)
        .enter().append('g')
        .attr('class', 'node')
        .attr('transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; })

        node.append('circle').attr('r', 4.5);
        node.append('text')
        .attr('dx', function(d) { return d.children ? -8 : 8; })
        .attr('dy', 3)
        .style('text-anchor', function(d) { return d.children ? 'end' : 'start'; })
        .text(function(d) { return d.name; });

        unload(container);
    });
}

function _handleVoronoi(container, config) {
    d3.json(config.dataSource, function(error, data){
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var width = config.width - WIDGET_MARGIN_X;
        var height = config.height - WIDGET_MARGIN_Y;
        var vertices = data;
        var voronoi = d3.geom.voronoi().clipExtent([[0, 0], [width, height]]);
        // Cleanup
        var svg = container
        .append('svg')
        .attr('width', width)
        .attr('height', height);
        var path = svg.append('g').selectAll('path');
        svg.selectAll('circle')
        .data(vertices.slice(1))
        .enter().append('circle')
        .attr('transform', function(d) { return 'translate(' + d + ')'; })
        .attr('r', 1.5);
        redraw();

        function redraw() {
            path = path.data(voronoi(vertices), polygon);
            path.exit().remove();
            path.enter().append('path')
            .attr('class', function(d, i) { return 'q' + (i % 9) + '-9'; })
            .attr('d', polygon);
            path.order();
        }
        unload(container);
    });
}

function _handleSparkline(container, config) {
    // Clean up old canvas elements
    container.selectAll('.sparkline-container').remove();
    var sparkline_type = config.type.split('-')[1];
    var spark = container
        .append('div')
        .classed({
            'sparkline-container': true,
            'text-center': true
        });
    spark = $(spark[0]);
    $.getJSON(config.dataSource, function(data){
        var opts = {
            type: sparkline_type,
            width: config.width - WIDGET_MARGIN_X,
            height: config.height - WIDGET_MARGIN_Y,
        };
        spark.sparkline(data, opts);
        unload(container);
    });
}

function _handleDataTable(container, config) {
    // Clean up old tables if they exist, during reloading.
    container.selectAll('div').remove();
    d3.json(config.dataSource, function(error, res) {
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var keys = d3.keys(res[0]).map(function(d){
            return {'data': d};
        });
        container
            .append('table')
            .classed({
                'table': true,
                'table-striped': true,
                'table-bordered': true
            })
            .attr('id', config.name);
        $('#' + config.name).dataTable({
            data: res,
            columns: keys
        }).css({width: 'auto'});
        unload(container);
    });
}

function _handleSingleNum(container, config) {
    container.selectAll('.singlenum').remove();
    d3.json(config.dataSource, function(data){
        var num = container.append('div')
            .classed({'singlenum': true})
            .text(data);
        data = String(data);
        // Add red or green, depending on if the number appears to be pos/neg.
        num.classed({
            'text-danger': data.startsWith('-'),
            'text-success': !data.startsWith('-')
        });
        // Get title height to offset box.
        var title_h = container
            .select('.widget-title')
            .node()
            .getBoundingClientRect()
            .height;
        var inner_box_height = config.height - title_h; // factor in rough height of title.
        container.style({
            'line-height': inner_box_height + 'px',
            'height': inner_box_height + 'px'
        });
        var digits = String(data).length;
        var size = getDigitSize()(digits);
        num.style('font-size', size + 'px');
        unload(container);
    });
}

function _handleTimeline(container, config) {
    $.getJSON(config.dataSource, function(data){
        container.append('div').attr('id', 'widget-' + config.guid);
        var timeline = new TL.Timeline('widget-' + config.guid, data);
        unload(container);
    });
}

function _handleIframe(container, config) {
    container.selectAll('iframe').remove();
    var iframe = container.append('iframe');
    iframe.attr({
        border: 0,
        src: config.dataSource,
        height: '100%',
        width: '100%'
    });
    unload(container);
}

function _handleCustom(container, config) {
    container.selectAll('.custom-container').remove();
    $.get(config.dataSource, function(html){
        container.append('div').classed({'custom-container': true}).html(html);
        unload(container);
    });
}

function _handleVenn(container, config) {
    container.selectAll('.venn').remove();
    d3.json(config.dataSource, function(error, data){
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var chart = venn.VennDiagram();
        var cont = container
            .append('div')
            .classed({'venn': true})
        cont.datum(data).call(chart);
        cont.select('svg')
            .attr('width', config.width - WIDGET_MARGIN_X)
            .attr('height', config.height - WIDGET_MARGIN_Y)
        unload(container);
    });
}
<commit_msg>Convert more requests to use d3.<commit_after>/**
 * Handlers for various widget types. The method signatures are always the same,
 * but each handler can handle them differently.
 */

var WIDGET_MARGIN_X = 20;
var WIDGET_MARGIN_Y = 60;

function _handleYoutube(container, config) {
    // Clean up all previous.
    container.selectAll('iframe').remove();
    var iframe = container.append('iframe');
    iframe
        .attr('width', config.width)
        .attr('height', config.height)
        .attr('src', config.dataSource)
        .attr('allowfullscreen')
        .attr('frameborder', 0)
}

function _handleC3(container, config) {
    var init_config = {
        bindto: '#' + normalizeName(config.name),
        legend: {
            show: true
        },
        size: {
            height: config.height - WIDGET_MARGIN_Y,
            width: config.width - WIDGET_MARGIN_X
        },
        data: {
            type: config.type,
            url: config.dataSource,
            mimeType: 'json'
        },
        onrendered: function(){
            unload(container);
        }
    };
    if(isOverride(config)) {
        // Just use the raw payload for this widgets' options.
        d3.json(config.dataSource, function(res){
            // Keep existing options if not specified.
            var config = $.extend(init_config, res);
            c3.generate(init_config);
        });
        return;
    }
    if(config.type === 'timeseries') {
        init_config['axis'] = {
            x: {type: 'timeseries'},
        };
        // Map the corresponding data key and list of dates
        // to the `x` property.
        init_config['data']['x'] = 'dates';
    }
    c3.generate(init_config);
}

function _handleD3(container, config) {
    // Clean up all D3 charts in one step.
    container.selectAll('svg').remove();
    // Handle specific types.
    if(config.type === 'radial-dendrogram') return _handleRadialDendrogram(container, config);
    if(config.type === 'dendrogram') return _handleDendrogram(container, config);
    if(config.type === 'voronoi') return _handleVoronoi(container, config);
    if(config.type === 'treemap') return _handleTreemap(container, config);
    if(config.type === 'circlepack') return _handleCirclePack(container, config);
    throw new Error('Unknown type: ' + config.type);
}

function _handleCirclePack(container, config) {
    // Adapted from https://bl.ocks.org/mbostock/4063530
    var margin = WIDGET_MARGIN_Y;
    var diameter = d3.max([config.width, config.height]) - margin;
    var format = d3.format(',d');

    var pack = d3.layout.pack()
        .size([diameter, diameter])
        .value(function(d) { return d.size; });

    var svg = container
        .append('svg')
        .attr('width', diameter)
        .attr('height', diameter)
        .append('g');

    d3.json(config.dataSource, function(error, data) {
        if(error) throw new Error("Could not load url: " + config.dataSource);

        var node = svg.datum(data).selectAll('.node')
        .data(pack.nodes)
        .enter().append('g')
        .attr('class', function(d) { return d.children ? 'node' : 'leaf node'; })
        .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });

        node.append('title')
        .text(function(d) { return d.name + (d.children ? '' : ': ' + format(d.size)); });

        node.append('circle')
        .attr('r', function(d) { return d.r; });

        node.filter(function(d) { return !d.children; }).append('text')
        .attr('dy', '.3em')
        .style('text-anchor', 'middle')
        .text(function(d) { return d.name.substring(0, d.r / 3); });
        unload(container);
    });

    d3.select(self.frameElement).style("height", diameter + "px");
}

function _handleTreemap(container, config) {
    // Adapted from http://bl.ocks.org/mbostock/4063582
    var margin = {
        top: WIDGET_MARGIN_Y / 2,
        bottom: WIDGET_MARGIN_Y / 2,
        left: WIDGET_MARGIN_X / 2,
        right: WIDGET_MARGIN_X / 2
    };
    var width = config.width - WIDGET_MARGIN_X;
    var height = config.height - WIDGET_MARGIN_Y;
    var color = d3.scale.category20c();
    var treemap = d3.layout.treemap()
        .size([width, height])
        .sticky(true)
        .value(function(d) { return d.size; });
    // Cleanup
    container.selectAll('.treemap').remove();
    var div = container
        .append('div')
        .classed({'treemap': true, 'chart-centered': true})
        .style('position', 'relative')
        .style('width', width + 'px')
        .style('height', height + 'px');

    d3.json(config.dataSource, function(error, root) {
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var node = div.datum(root).selectAll('.node')
            .data(treemap.nodes)
            .enter().append('div')
            .attr('class', 'node')
            .call(position)
            .style('border', '1px solid white')
            .style('font', '10px sans-serif')
            .style('line-height', '12px')
            .style('overflow', 'hidden')
            .style('position', 'absolute')
            .style('text-indent', '2px')
            .style('background', function(d) {
                return d.children ? color(d.name) : null;
            })
            .text(function(d) {
                return d.children ? null : d.name;
            });
        d3.selectAll('input').on('change', function change() {
            var value = this.value === 'count'
            ? function() { return 1; }
            : function(d) { return d.size;};
            node
            .data(treemap.value(value).nodes)
            .transition()
            .duration(1500)
            .call(position);
        });
    });

    function position() {
        this.style('left', function(d) { return d.x + 'px'; })
            .style('top', function(d) { return d.y + 'px'; })
            .style('width', function(d) { return Math.max(0, d.dx - 1) + 'px'; })
            .style('height', function(d) { return Math.max(0, d.dy - 1) + 'px'; });
    }
}

function _handleRadialDendrogram(container, config) {
    container.selectAll('svg').remove();
    // Code taken (and refactored for use here) from:
    // https://bl.ocks.org/mbostock/4339607
    var radius = (config.width > config.height ? config.width : config.height) / 2;
    var cluster = d3.layout.cluster()
        .size([360, radius * 0.65]); // reduce size relative to `radius`
    var diagonal = d3.svg.diagonal.radial()
        .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
    var svg = container.append('svg')
        .attr('width', radius * 2)
        .attr('height', radius * 2)
        .append('g')
        .attr('transform', 'translate(' + radius + ',' + radius + ')');
    d3.json(config.dataSource, function(error, root) {
        if (error) throw error;
        var nodes = cluster.nodes(root);
        var link = svg.selectAll('path.link')
            .data(cluster.links(nodes))
            .enter().append('path')
            .attr('class', 'link')
            .attr('d', diagonal);
        var node = svg.selectAll('g.node')
            .data(nodes)
            .enter().append('g')
            .attr('class', 'node')
            .attr('transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; })
        node.append('circle')
            .attr('r', 4.5);
        node.append('text')
            .attr('dy', '.31em')
            .attr('text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; })
            .attr('transform', function(d) { return d.x < 180 ? 'translate(8)' : 'rotate(180)translate(-8)'; })
            .text(function(d) { return d.name; });
        unload(container);
    });
    d3.select(self.frameElement).style('height', radius * 2 + 'px');
}

function _handleDendrogram(container, config) {
    container.selectAll('svg').remove();
    var PADDING = 100;
    var width = config.width - WIDGET_MARGIN_X;
    var height = config.height - WIDGET_MARGIN_Y;
    var cluster = d3.layout.cluster()
        .size([height, width - PADDING]);
    var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });
    var svg = container
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .append('g')
        .attr('transform', 'translate(40,0)');

    d3.json(config.dataSource, function(error, root) {
        if(error) throw new Error('Could not load url: ' + config.dataSource);

        var nodes = cluster.nodes(root),
        links = cluster.links(nodes);

        var link = svg.selectAll('.link')
        .data(links)
        .enter().append('path')
        .attr('class', 'link')
        .attr('d', diagonal);

        var node = svg.selectAll('.node')
        .data(nodes)
        .enter().append('g')
        .attr('class', 'node')
        .attr('transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; })

        node.append('circle').attr('r', 4.5);
        node.append('text')
        .attr('dx', function(d) { return d.children ? -8 : 8; })
        .attr('dy', 3)
        .style('text-anchor', function(d) { return d.children ? 'end' : 'start'; })
        .text(function(d) { return d.name; });

        unload(container);
    });
}

function _handleVoronoi(container, config) {
    d3.json(config.dataSource, function(error, data){
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var width = config.width - WIDGET_MARGIN_X;
        var height = config.height - WIDGET_MARGIN_Y;
        var vertices = data;
        var voronoi = d3.geom.voronoi().clipExtent([[0, 0], [width, height]]);
        // Cleanup
        var svg = container
        .append('svg')
        .attr('width', width)
        .attr('height', height);
        var path = svg.append('g').selectAll('path');
        svg.selectAll('circle')
        .data(vertices.slice(1))
        .enter().append('circle')
        .attr('transform', function(d) { return 'translate(' + d + ')'; })
        .attr('r', 1.5);
        redraw();

        function redraw() {
            path = path.data(voronoi(vertices), polygon);
            path.exit().remove();
            path.enter().append('path')
            .attr('class', function(d, i) { return 'q' + (i % 9) + '-9'; })
            .attr('d', polygon);
            path.order();
        }
        unload(container);
    });
}

function _handleSparkline(container, config) {
    // Clean up old canvas elements
    container.selectAll('.sparkline-container').remove();
    var sparkline_type = config.type.split('-')[1];
    var spark = container
        .append('div')
        .classed({
            'sparkline-container': true,
            'text-center': true
        });
    spark = $(spark[0]);
    d3.json(config.dataSource, function(data){
        var opts = {
            type: sparkline_type,
            width: config.width - WIDGET_MARGIN_X,
            height: config.height - WIDGET_MARGIN_Y,
        };
        spark.sparkline(data, opts);
        unload(container);
    });
}

function _handleDataTable(container, config) {
    // Clean up old tables if they exist, during reloading.
    container.selectAll('div').remove();
    d3.json(config.dataSource, function(error, res) {
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var keys = d3.keys(res[0]).map(function(d){
            return {'data': d};
        });
        container
            .append('table')
            .classed({
                'table': true,
                'table-striped': true,
                'table-bordered': true
            })
            .attr('id', config.name);
        $('#' + config.name).dataTable({
            data: res,
            columns: keys
        }).css({width: 'auto'});
        unload(container);
    });
}

function _handleSingleNum(container, config) {
    container.selectAll('.singlenum').remove();
    d3.json(config.dataSource, function(data){
        var num = container.append('div')
            .classed({'singlenum': true})
            .text(data);
        data = String(data);
        // Add red or green, depending on if the number appears to be pos/neg.
        num.classed({
            'text-danger': data.startsWith('-'),
            'text-success': !data.startsWith('-')
        });
        // Get title height to offset box.
        var title_h = container
            .select('.widget-title')
            .node()
            .getBoundingClientRect()
            .height;
        var inner_box_height = config.height - title_h; // factor in rough height of title.
        container.style({
            'line-height': inner_box_height + 'px',
            'height': inner_box_height + 'px'
        });
        var digits = String(data).length;
        var size = getDigitSize()(digits);
        num.style('font-size', size + 'px');
        unload(container);
    });
}

function _handleTimeline(container, config) {
    d3.json(config.dataSource, function(data){
        container.append('div').attr('id', 'widget-' + config.guid);
        var timeline = new TL.Timeline('widget-' + config.guid, data);
        unload(container);
    });
}

function _handleIframe(container, config) {
    container.selectAll('iframe').remove();
    var iframe = container.append('iframe');
    iframe.attr({
        border: 0,
        src: config.dataSource,
        height: '100%',
        width: '100%'
    });
    unload(container);
}

function _handleCustom(container, config) {
    container.selectAll('.custom-container').remove();
    $.get(config.dataSource, function(html){
        container.append('div').classed({'custom-container': true}).html(html);
        unload(container);
    });
}

function _handleVenn(container, config) {
    container.selectAll('.venn').remove();
    d3.json(config.dataSource, function(error, data){
        if(error) throw new Error('Could not load url: ' + config.dataSource);
        var chart = venn.VennDiagram();
        var cont = container
            .append('div')
            .classed({'venn': true})
        cont.datum(data).call(chart);
        cont.select('svg')
            .attr('width', config.width - WIDGET_MARGIN_X)
            .attr('height', config.height - WIDGET_MARGIN_Y)
        unload(container);
    });
}
<|endoftext|>


<commit_before>import {Button} from 'widget/button'
import {isMobile} from './userAgent'
import {msg} from 'translate'
import Confirm from 'widget/confirm'
import PropTypes from 'prop-types'
import React from 'react'

export class ModalConfirmationButton extends React.Component {
    state = {
        askConfirmation: false
    }

    askConfirmation(askConfirmation) {
        this.setState({askConfirmation})
    }

    renderConfirm() {
        const {title, message, confirmLabel, onConfirm, children} = this.props
        return (
            <Confirm
                title={title}
                message={message}
                label={confirmLabel || msg('widget.safetyButton.label')}
                onConfirm={() => {
                    onConfirm()
                    this.askConfirmation(false)
                }}
                onCancel={() => this.askConfirmation(false)}>
                {children}
            </Confirm>
        )
    }

    render() {
        const {busy, chromeless, disabled, icon, iconType, label, shape, size, skipConfirmation, tooltip, tooltipPlacement, width, onConfirm} = this.props
        const {askConfirmation} = this.state
        return (
            <React.Fragment>
                <Button
                    busy={busy}
                    chromeless={chromeless}
                    icon={icon}
                    iconType={iconType}
                    label={label}
                    shape={shape}
                    size={size}
                    width={width}
                    disabled={disabled}
                    tooltip={tooltip}
                    tooltipPlacement={tooltipPlacement}
                    tooltipDelay={500}
                    onClick={() => skipConfirmation ? onConfirm() : this.askConfirmation(true)}
                    onClickHold={() => onConfirm()}
                />
                {askConfirmation ? this.renderConfirm() : null}
            </React.Fragment>
        )
    }
}

ModalConfirmationButton.defaultProps = {
    tooltipPlacement: 'top'
}

ModalConfirmationButton.propTypes = {
    message: PropTypes.string.isRequired,
    onConfirm: PropTypes.func.isRequired,
    busy: PropTypes.any,
    chromeless: PropTypes.any,
    confirmLabel: PropTypes.string,
    disabled: PropTypes.any,
    icon: PropTypes.any,
    iconType: PropTypes.any,
    label: PropTypes.any,
    shape: PropTypes.any,
    size: PropTypes.any,
    skipConfirmation: PropTypes.any,
    title: PropTypes.any,
    tooltip: PropTypes.any,
    tooltipPlacement: PropTypes.any,
    width: PropTypes.any
}

export class TooltipConfirmationButton extends React.Component {
    state = {
        askConfirmation: false
    }

    askConfirmation(askConfirmation) {
        this.setState({askConfirmation})
    }

    renderTooltipConfirmation() {
        const {onConfirm} = this.props
        return (
            <Button
                look='cancel'
                icon='exclamation-triangle'
                label={msg('button.confirm')}
                onClick={() => onConfirm && onConfirm()}/>
        )
    }

    renderTooltip() {
        const {tooltip} = this.props
        const {askConfirmation} = this.state
        return askConfirmation
            ? this.renderTooltipConfirmation()
            : tooltip
    }

    render() {
        const {busy, chromeless, disabled, icon, iconType, label, shape, size, skipConfirmation, tooltipPlacement, width, onConfirm} = this.props
        const {askConfirmation} = this.state
        return (
            <Button
                busy={busy}
                chromeless={chromeless}
                icon={icon}
                iconType={iconType}
                label={label}
                shape={shape}
                size={size}
                width={width}
                disabled={disabled}
                tooltip={this.renderTooltip()}
                tooltipPlacement={tooltipPlacement}
                tooltipClickTrigger={isMobile()}
                tooltipDelay={500}
                tooltipOnVisible={visible => !visible && this.askConfirmation(false)}
                onClick={() => skipConfirmation ? onConfirm() : this.askConfirmation(!askConfirmation)}
                onClickHold={() => onConfirm && onConfirm()}
            />
        )
    }
}

TooltipConfirmationButton.defaultProps = {
    tooltipPlacement: 'top'
}

TooltipConfirmationButton.propTypes = {
    onConfirm: PropTypes.func.isRequired,
    busy: PropTypes.any,
    chromeless: PropTypes.any,
    disabled: PropTypes.any,
    icon: PropTypes.any,
    iconType: PropTypes.any,
    label: PropTypes.any,
    shape: PropTypes.any,
    size: PropTypes.any,
    skipConfirmation: PropTypes.any,
    tooltip: PropTypes.any,
    tooltipPlacement: PropTypes.any,
    width: PropTypes.any
}
<commit_msg>Improved TooltipConfirmationButton on mobile.<commit_after>import {Button} from 'widget/button'
import {isMobile} from './userAgent'
import {msg} from 'translate'
import Confirm from 'widget/confirm'
import PropTypes from 'prop-types'
import React from 'react'

export class ModalConfirmationButton extends React.Component {
    state = {
        askConfirmation: false
    }

    askConfirmation(askConfirmation) {
        this.setState({askConfirmation})
    }

    renderConfirm() {
        const {title, message, confirmLabel, onConfirm, children} = this.props
        return (
            <Confirm
                title={title}
                message={message}
                label={confirmLabel || msg('widget.safetyButton.label')}
                onConfirm={() => {
                    onConfirm()
                    this.askConfirmation(false)
                }}
                onCancel={() => this.askConfirmation(false)}>
                {children}
            </Confirm>
        )
    }

    render() {
        const {busy, chromeless, disabled, icon, iconType, label, shape, size, skipConfirmation, tooltip, tooltipPlacement, width, onConfirm} = this.props
        const {askConfirmation} = this.state
        return (
            <React.Fragment>
                <Button
                    busy={busy}
                    chromeless={chromeless}
                    icon={icon}
                    iconType={iconType}
                    label={label}
                    shape={shape}
                    size={size}
                    width={width}
                    disabled={disabled}
                    tooltip={tooltip}
                    tooltipPlacement={tooltipPlacement}
                    tooltipDelay={500}
                    onClick={() => skipConfirmation ? onConfirm() : this.askConfirmation(true)}
                    onClickHold={() => onConfirm()}
                />
                {askConfirmation ? this.renderConfirm() : null}
            </React.Fragment>
        )
    }
}

ModalConfirmationButton.defaultProps = {
    tooltipPlacement: 'top'
}

ModalConfirmationButton.propTypes = {
    message: PropTypes.string.isRequired,
    onConfirm: PropTypes.func.isRequired,
    busy: PropTypes.any,
    chromeless: PropTypes.any,
    confirmLabel: PropTypes.string,
    disabled: PropTypes.any,
    icon: PropTypes.any,
    iconType: PropTypes.any,
    label: PropTypes.any,
    shape: PropTypes.any,
    size: PropTypes.any,
    skipConfirmation: PropTypes.any,
    title: PropTypes.any,
    tooltip: PropTypes.any,
    tooltipPlacement: PropTypes.any,
    width: PropTypes.any
}

export class TooltipConfirmationButton extends React.Component {
    state = {
        askConfirmation: false
    }

    askConfirmation(askConfirmation) {
        this.setState({askConfirmation})
    }

    renderTooltipConfirmation() {
        const {onConfirm} = this.props
        return (
            <Button
                look='cancel'
                icon='exclamation-triangle'
                label={msg('button.confirm')}
                onClick={() => onConfirm && onConfirm()}/>
        )
    }

    renderTooltip() {
        const {tooltip} = this.props
        const {askConfirmation} = this.state
        return askConfirmation || isMobile()
            ? this.renderTooltipConfirmation()
            : tooltip
    }

    render() {
        const {busy, chromeless, disabled, icon, iconType, label, shape, size, skipConfirmation, tooltipPlacement, width, onConfirm} = this.props
        const {askConfirmation} = this.state
        return (
            <Button
                busy={busy}
                chromeless={chromeless}
                icon={icon}
                iconType={iconType}
                label={label}
                shape={shape}
                size={size}
                width={width}
                disabled={disabled}
                tooltip={this.renderTooltip()}
                tooltipPlacement={tooltipPlacement}
                tooltipClickTrigger={isMobile()}
                tooltipDelay={500}
                tooltipOnVisible={visible => !visible && this.askConfirmation(false)}
                onClick={() => skipConfirmation ? onConfirm() : this.askConfirmation(!askConfirmation)}
                onClickHold={() => onConfirm && onConfirm()}
            />
        )
    }
}

TooltipConfirmationButton.defaultProps = {
    tooltipPlacement: 'top'
}

TooltipConfirmationButton.propTypes = {
    onConfirm: PropTypes.func.isRequired,
    busy: PropTypes.any,
    chromeless: PropTypes.any,
    disabled: PropTypes.any,
    icon: PropTypes.any,
    iconType: PropTypes.any,
    label: PropTypes.any,
    shape: PropTypes.any,
    size: PropTypes.any,
    skipConfirmation: PropTypes.any,
    tooltip: PropTypes.any,
    tooltipPlacement: PropTypes.any,
    width: PropTypes.any
}
<|endoftext|>


<commit_before>/*
* Run the global `beforeRequest` method, and then the local method.
*/
const when = require('when');
const _    = require('lodash');

const localOnly = require('./localOnly');

const REFERENCE_MODIFICATION_ERROR_MESSAGE = 'Modification by reference is deprecated. `beforeRequest` must return the modified object.';

function validateForObject (referencedRequest, originalRequestCopy) {
    /*
        If function returns undefined, then assume no modification to
        original params, and so set as default argument
    */
    return (returnedRequest) => {
        if (_.isUndefined(returnedRequest)) {
            if (!_.isEqual(referencedRequest, originalRequestCopy)) {
                if (process.env.NODE_ENV === 'development') {
                    throw new Error(REFERENCE_MODIFICATION_ERROR_MESSAGE);
                } else {
                    console.warn(REFERENCE_MODIFICATION_ERROR_MESSAGE);
                }
            }
        } else if (!_.isPlainObject(returnedRequest)) {
            throw new Error('`beforeRequest` must return an object');
        }
        return returnedRequest || originalRequestCopy;
    };
}

module.exports = function (config, request = {}) {

    const { _globalOptions } = this;

    const originalRequest = _.cloneDeep(request);

    //Start by executing globalBefore if provided and globals true
    const globalRequestExec = (
    	_.isFunction(_globalOptions.beforeRequest) && !localOnly(config, 'beforeRequest') ?
    	_globalOptions.beforeRequest(request) :
    	request
    );

    return when(globalRequestExec)

    .then(validateForObject(request, originalRequest))

    .then((globalRequestResult = request) => {
        return when(( config.before ? config.before(globalRequestResult) : globalRequestResult ));
    })

    .then(validateForObject(request, originalRequest));

};

// var when = require('when');
// var _    = require('lodash');
//
// var localOnly = require('./localOnly');
//
// module.exports = function (config, request, params) {
//   var threadneedle = this;
//   return when.promise(function (resolve, reject) {
//
//     when()
//
//     // Run global promise first
//     .then(function () {
//       if (_.isFunction(threadneedle._globalOptions.beforeRequest) && !localOnly(config, 'beforeRequest')) {
//         return when(threadneedle._globalOptions.beforeRequest(request, params));
//       }
//     })
//
//     // Then run the local prmoise
//     .then(function () {
//       if (_.isFunction(config.beforeRequest)) {
//         return when(config.beforeRequest(request, params));
//       }
//     })
//
//     .then(function () {
//       return request;
//     })
//
//     .done(resolve, reject);
//
//   });
// };
<commit_msg>deleted old code<commit_after>/*
* Run the global `beforeRequest` method, and then the local method.
*/
const when = require('when');
const _    = require('lodash');

const localOnly = require('./localOnly');

const REFERENCE_MODIFICATION_ERROR_MESSAGE = 'Modification by reference is deprecated. `beforeRequest` must return the modified object.';

function validateForObject (referencedRequest, originalRequestCopy) {
    /*
        If function returns undefined, then assume no modification to
        original params, and so set as default argument
    */
    return (returnedRequest) => {
        if (_.isUndefined(returnedRequest)) {
            if (!_.isEqual(referencedRequest, originalRequestCopy)) {
                if (process.env.NODE_ENV === 'development') {
                    throw new Error(REFERENCE_MODIFICATION_ERROR_MESSAGE);
                } else {
                    console.warn(REFERENCE_MODIFICATION_ERROR_MESSAGE);
                }
            }
        } else if (!_.isPlainObject(returnedRequest)) {
            throw new Error('`beforeRequest` must return an object');
        }
        return returnedRequest || originalRequestCopy;
    };
}

module.exports = function (config, request = {}) {

    const { _globalOptions } = this;

    const originalRequest = _.cloneDeep(request);

    //Start by executing globalBefore if provided and globals true
    const globalRequestExec = (
    	_.isFunction(_globalOptions.beforeRequest) && !localOnly(config, 'beforeRequest') ?
    	_globalOptions.beforeRequest(request) :
    	request
    );

    return when(globalRequestExec)

    .then(validateForObject(request, originalRequest))

    .then((globalRequestResult = request) => {
        return when(( config.before ? config.before(globalRequestResult) : globalRequestResult ));
    })

    .then(validateForObject(request, originalRequest));

};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint nomen:true, node:true*/

/**
@module moijto-parser-body
**/

'use strict';

/**
Export a function which can create a body parser.
@return {Object} The newly constructed body parser.
**/
module.exports = require('express').bodyParser;

var express = require('express'),
    json = express.json,
    urlencoded = express.urlencoded;

module.exports = function bodyParser(options) {
    var _json = json(options),
        _urlencoded = urlencoded(options);

    return function (req, res, next) {
        _json(req, res, function (err) {
            if (err) {
                return next(err);
            }
            _urlencoded(req, res, function (err) {
                if (err) {
                    return next(err);
                }
                next();
            });
        });
    };
};<commit_msg>Breakline.<commit_after>/*
 * Copyright (c) 2011-2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint nomen:true, node:true*/

/**
@module moijto-parser-body
**/

'use strict';

/**
Export a function which can create a body parser.
@return {Object} The newly constructed body parser.
**/
module.exports = require('express').bodyParser;

var express = require('express'),
    json = express.json,
    urlencoded = express.urlencoded;

module.exports = function bodyParser(options) {
    var _json = json(options),
        _urlencoded = urlencoded(options);

    return function (req, res, next) {
        _json(req, res, function (err) {
            if (err) {
                return next(err);
            }
            _urlencoded(req, res, function (err) {
                if (err) {
                    return next(err);
                }
                next();
            });
        });
    };
};<|endoftext|>


<commit_before>// Not a unique entry file, but dependencies required for old table.js bundle, to retrofit newer browserify files to be
// usable in a non-browserified bundle
//
// Expected to be loaded after cdb.js but before table.js
var cdb = require('cartodb.js');
cdb.editor = {
  ImportsCollection: require('./new_common/background_importer/imports_collection'),
  BackgroundImporterModel: require('./editor/background_importer_model'),
  BackgroundImporterView: require('./new_common/background_importer/background_importer_view'),
  AddLayerView: require('./new_common/dialogs/map/add_layer_view'),
  AddLayerModel: require('./new_common/dialogs/map/add_layer_model'),

  ChangePrivacyView: require('./new_common/dialogs/change_privacy/change_privacy_view'),
  ChangePrivacyModel: require('./new_common/dialogs/change_privacy/view_model'),

  DeleteItemsView: require('./new_common/dialogs/delete_items_view'),
  DeleteItemsViewModel: require('./new_common/dialogs/delete_items_view_model')

  DialogFactory: require('./new_common/dialog_factory'),
};
<commit_msg>Fix post-merge<commit_after>// Not a unique entry file, but dependencies required for old table.js bundle, to retrofit newer browserify files to be
// usable in a non-browserified bundle
//
// Expected to be loaded after cdb.js but before table.js
var cdb = require('cartodb.js');
cdb.editor = {
  ImportsCollection: require('./new_common/background_importer/imports_collection'),
  BackgroundImporterModel: require('./editor/background_importer_model'),
  BackgroundImporterView: require('./new_common/background_importer/background_importer_view'),
  AddLayerView: require('./new_common/dialogs/map/add_layer_view'),
  AddLayerModel: require('./new_common/dialogs/map/add_layer_model'),

  ChangePrivacyView: require('./new_common/dialogs/change_privacy/change_privacy_view'),
  ChangePrivacyModel: require('./new_common/dialogs/change_privacy/view_model'),

  DeleteItemsView: require('./new_common/dialogs/delete_items_view'),
  DeleteItemsViewModel: require('./new_common/dialogs/delete_items_view_model'),

  DialogFactory: require('./new_common/dialog_factory')
};
<|endoftext|>


<commit_before>// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import AxiomError from 'axiom/core/error';

/**
 * Registry of views that can be placed in windows.
 */
export var ViewManager = function(moduleManager) {
  this.moduleManager_ = moduleManager;
  this.views_ = {};
  this.extensionBindings_ = [];
};

export default ViewManager;

ViewManager.prototype.bind = function(serviceBinding) {
  serviceBinding.bind(this, {
    'onExtend': this.onExtend,
    'register': this.register,
    'unregister': this.unregister,
    'show': this.show,
    'hide': this.hide,
  });

  serviceBinding.ready();
};

/**
 * Extending the View Manager adds new view types.
 *
 * The extension descriptor should provide a unique id for each view.  The
 * binding should provide 'show' and 'hide' callbacks.
 */
ViewManager.prototype.onExtend = function(extensionBinding) {
  this.extensionBindings_.push(extensionBinding);
  var defineViews = extensionBinding.descriptor['define-views'];
  for (var id in defineViews) {
    this.views_[id] = {
      descriptor: defineViews[id],
      extensionBinding: extensionBinding
    };
  }
};

/**
 * Register a view given a unique id and a custom element.
 */
ViewManager.prototype.register = function(id, tagName) {
  var view = this.views_[id];
  if (view)
    return Promise.reject(AxiomError.Duplicate('view', id));

  this.views_[id] = {
    tagName: tagName,
  };
};

/**
 * Unregister a view given its id.
 */
ViewManager.prototype.unregister = function(viewId) {
  var view = this.views_[viewId];
  if (!view)
    return Promise.reject(AxiomError.NotFound('view', viewId));

  delete this.views_[viewId];
};

/**
 * Display a view given it id and location information.
 */
ViewManager.prototype.show = function(viewId, args) {
  var view = this.views_[viewId];
  if (!view)
    return Promise.reject(AxiomError.NotFound('view', viewId));

  var windowsService = this.moduleManager_.getServiceBinding('windows@axiom');
  return windowsService
    .whenLoadedAndReady()
    .then(function() {
      // TODO(rpaquay): 'main-window' should not be hard coded.
      return windowsService.openWindow('main-window').then(function(window) {
        var document = window.document;
        var frame = document.getElementsByTagName('axiom-frame');
        if (frame.length !== 1) {
          return Promise.reject(AxiomError.Runtime('Document body should contain a single axiom-frame element'));
        }

        // TODO(rpaquay): Add support for adding more than a single view.
        var axiomView = document.createElement('axiom-view');
        axiomView.setAttribute('fit', '');
        frame[0].appendChild(axiomView);

        var element = document.createElement(view.tagName);
        axiomView.appendChild(element);

        view.element = element;
        // TODO(rpaquay): Call "onShow" on extension binding
        //view.element.onShow();
      });
    });
};

ViewManager.prototype.hide = function(viewId, args) {
  var view = this.views_[viewId];
  if (!view)
    return Promise.reject(AxiomError.NotFound('view', viewId));
};
<commit_msg>Code review feedback.<commit_after>// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import AxiomError from 'axiom/core/error';

/**
 * Registry of views that can be placed in windows.
 */
export var ViewManager = function(moduleManager) {
  this.moduleManager_ = moduleManager;
  this.views_ = new Map();
  this.extensionBindings_ = new Set();
};

export default ViewManager;

ViewManager.prototype.bind = function(serviceBinding) {
  serviceBinding.bind(this, {
    'onExtend': 'onExtend',
    'register': 'register',
    'unregister': 'unregister',
    'show': 'show',
    'hide': 'hide',
  });

  serviceBinding.ready();
};

/**
 * Extending the View Manager adds new view types.
 *
 * The extension descriptor should provide a unique id for each view.  The
 * binding should provide 'show' and 'hide' callbacks.
 */
ViewManager.prototype.onExtend = function(extensionBinding) {
  this.extensionBindings_.add(extensionBinding);
  var defineViews = extensionBinding.descriptor['define-views'];
  for (var id in defineViews) {
    this.views_.set(id, {
      descriptor: defineViews[id],
      extensionBinding: extensionBinding
    });
  }
};

/**
 * Register a view given a unique id and a custom element.
 */
ViewManager.prototype.register = function(id, tagName) {
  if (this.views_.has(id))
    return Promise.reject(AxiomError.Duplicate('view', id));

  this.views_.set(id, {
    tagName: tagName,
  });
};

/**
 * Unregister a view given its id.
 */
ViewManager.prototype.unregister = function(viewId) {
  if (!this.views_.has(viewId))
    return Promise.reject(AxiomError.NotFound('view', viewId));

  this.views_.delete(viewId);
};

/**
 * Display a view given it id and location information.
 */
ViewManager.prototype.show = function(viewId, args) {
  var view = this.views_.get(viewId);
  if (!view)
    return Promise.reject(AxiomError.NotFound('view', viewId));

  var windowsService = this.moduleManager_.getServiceBinding('windows@axiom');
  return windowsService
    .whenLoadedAndReady()
    .then(function() {
      // TODO(rpaquay): 'main-window' should not be hard coded.
      return windowsService.openWindow('main-window').then(function(window) {
        var document = window.document;
        var frame = document.getElementsByTagName('axiom-frame');
        if (frame.length !== 1) {
          return Promise.reject(AxiomError.Runtime('Document body should contain a single axiom-frame element'));
        }

        // TODO(rpaquay): Add support for adding more than a single view.
        var axiomView = document.createElement('axiom-view');
        axiomView.setAttribute('fit', '');
        frame[0].appendChild(axiomView);

        var element = document.createElement(view.tagName);
        axiomView.appendChild(element);

        view.element = element;
        // TODO(rpaquay): Call "onShow" on extension binding
        //view.element.onShow();
      });
    });
};

ViewManager.prototype.hide = function(viewId, args) {
  var view = this.views_.get(viewId);
  if (!view)
    return Promise.reject(AxiomError.NotFound('view', viewId));
};
<|endoftext|>


<commit_before>"use strict";

const Constants = require("../Constants");
const Events = Constants.Events;
const Utils = require("../core/Utils");
const BaseCollection = require("./BaseCollection");

const GuildMember = require("../models/GuildMember");

function createGuildMember(member) {
  if (member.user) member.id = member.user.id;

  return new GuildMember({
    id: member.id,
    guild_id: member.guild_id,
    roles: member.roles,
    mute: member.mute || false,
    deaf: member.deaf || false,
    joined_at: member.joined_at // todo: convert strings into Date?
  });
}

function handleConnectionOpen(data) {
  this.clear();
  data.guilds.forEach(guild => handleCreateGuild.call(this, guild));
  return true;
}

function handleGuildMemberUpdate(member) {
  const memberCollection = this.get(member.guild_id);
  if (!memberCollection) return true;
  memberCollection.mergeOrSet(member.user.id, createGuildMember(member));
  return true;
}

function handleGuildMemberRemove(member) {
  const memberCollection = this.get(member.guild_id);
  if (!memberCollection) return true;
  memberCollection.delete(member.user.id);
  return true;
}

function handleCreateGuild(guild) {
  if (guild.unavailable) return true;

  const memberCollection = new BaseCollection();
  this.set(guild.id, memberCollection);

  guild.members.forEach(member => {
    member.guild_id = guild.id;
    memberCollection.set(member.user.id, createGuildMember(member));
  });
  return true;
}

function handleDeleteGuild(guild) {
  this.delete(guild.id);
  return true;
}

function handleVoiceStateUpdate(data) {
  const memberCollection = this.get(data.guild_id);
  if (!memberCollection) return true;
  const member = memberCollection.get(data.user_id);
  memberCollection.set(data.user_id,
    member.merge({
      mute: data.mute,
      dead: data.deaf
    })
  );
  return true;
}

function handlePresenceUpdate(presence) {
  if (!presence.user || !presence.user.id) return true;

  const memberCollection = this.get(presence.guild_id);
  if (!memberCollection) return true;

  const cachedMember = memberCollection.get(presence.user.id);
  if (!cachedMember) {
    // note: presences only contain roles
    memberCollection.set(presence.user.id, createGuildMember(presence));
  }

  return true;
}

class GuildMemberCollection extends BaseCollection {
  constructor(discordie, gateway) {
    super();

    if (typeof gateway !== "function")
      throw new Error("Gateway parameter must be a function");

    discordie.Dispatcher.on(Events.GATEWAY_READY, e => {
      if (e.socket != gateway()) return;
      (handleConnectionOpen.bind(this))(e.data);
    });
    discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
      if (e.socket != gateway()) return;

      Utils.bindGatewayEventHandlers(this, e, {
        GUILD_CREATE: handleCreateGuild,
        GUILD_DELETE: handleDeleteGuild,
        GUILD_MEMBER_ADD: handleGuildMemberUpdate,
        GUILD_MEMBER_UPDATE: handleGuildMemberUpdate,
        GUILD_MEMBER_REMOVE: handleGuildMemberRemove,
        VOICE_STATE_UPDATE: handleVoiceStateUpdate,
        PRESENCE_UPDATE: handlePresenceUpdate,
      });
    });

    this._discordie = discordie;
    Utils.privatify(this);
  }
  getMember(guildId, userId) {
    const memberCollection = this.get(guildId);
    if (!memberCollection) return true;
    return memberCollection.get(userId);
  }
}

module.exports = GuildMemberCollection;
<commit_msg>Don't update voice state of non-existent members<commit_after>"use strict";

const Constants = require("../Constants");
const Events = Constants.Events;
const Utils = require("../core/Utils");
const BaseCollection = require("./BaseCollection");

const GuildMember = require("../models/GuildMember");

function createGuildMember(member) {
  if (member.user) member.id = member.user.id;

  return new GuildMember({
    id: member.id,
    guild_id: member.guild_id,
    roles: member.roles,
    mute: member.mute || false,
    deaf: member.deaf || false,
    joined_at: member.joined_at // todo: convert strings into Date?
  });
}

function handleConnectionOpen(data) {
  this.clear();
  data.guilds.forEach(guild => handleCreateGuild.call(this, guild));
  return true;
}

function handleGuildMemberUpdate(member) {
  const memberCollection = this.get(member.guild_id);
  if (!memberCollection) return true;
  memberCollection.mergeOrSet(member.user.id, createGuildMember(member));
  return true;
}

function handleGuildMemberRemove(member) {
  const memberCollection = this.get(member.guild_id);
  if (!memberCollection) return true;
  memberCollection.delete(member.user.id);
  return true;
}

function handleCreateGuild(guild) {
  if (guild.unavailable) return true;

  const memberCollection = new BaseCollection();
  this.set(guild.id, memberCollection);

  guild.members.forEach(member => {
    member.guild_id = guild.id;
    memberCollection.set(member.user.id, createGuildMember(member));
  });
  return true;
}

function handleDeleteGuild(guild) {
  this.delete(guild.id);
  return true;
}

function handleVoiceStateUpdate(data) {
  const memberCollection = this.get(data.guild_id);
  if (!memberCollection) return true;
  const member = memberCollection.get(data.user_id);
  if (!member) return true;
  memberCollection.set(data.user_id,
    member.merge({
      mute: data.mute,
      dead: data.deaf
    })
  );
  return true;
}

function handlePresenceUpdate(presence) {
  if (!presence.user || !presence.user.id) return true;

  const memberCollection = this.get(presence.guild_id);
  if (!memberCollection) return true;

  const cachedMember = memberCollection.get(presence.user.id);
  if (!cachedMember) {
    // note: presences only contain roles
    memberCollection.set(presence.user.id, createGuildMember(presence));
  }

  return true;
}

class GuildMemberCollection extends BaseCollection {
  constructor(discordie, gateway) {
    super();

    if (typeof gateway !== "function")
      throw new Error("Gateway parameter must be a function");

    discordie.Dispatcher.on(Events.GATEWAY_READY, e => {
      if (e.socket != gateway()) return;
      (handleConnectionOpen.bind(this))(e.data);
    });
    discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
      if (e.socket != gateway()) return;

      Utils.bindGatewayEventHandlers(this, e, {
        GUILD_CREATE: handleCreateGuild,
        GUILD_DELETE: handleDeleteGuild,
        GUILD_MEMBER_ADD: handleGuildMemberUpdate,
        GUILD_MEMBER_UPDATE: handleGuildMemberUpdate,
        GUILD_MEMBER_REMOVE: handleGuildMemberRemove,
        VOICE_STATE_UPDATE: handleVoiceStateUpdate,
        PRESENCE_UPDATE: handlePresenceUpdate,
      });
    });

    this._discordie = discordie;
    Utils.privatify(this);
  }
  getMember(guildId, userId) {
    const memberCollection = this.get(guildId);
    if (!memberCollection) return true;
    return memberCollection.get(userId);
  }
}

module.exports = GuildMemberCollection;
<|endoftext|>