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

// Require main module
module.exports = function(RED) {
  "use strict";

  var rtcommRtcConnector = require('rtcomm').RtcConnector;

   // The rtcomm RtcConnector node definition
  function RtcommRtcConnectorNode(n) {
      RED.nodes.createNode(this,n);
      this.topic = (n.topic || '/rtcomm/')+'event';
      this.broker = n.broker;
      this.brokerConfig = RED.nodes.getNode(this.broker);
      this.rtcConnector = null;

  //	This defines the event filter

      this.started = n.started || false;
      this.failed = n.failed || false;
      this.modified = n.modified || false;
      this.stopped = n.stopped || false;
      this.fromEndpoint = n.fromendpoint;
      this.toEndpoint = n.toendpoint;
      var unique = n.unique || false;

      var node = this;
      if (this.brokerConfig) {
         this.status({fill:"red",shape:"ring",text:"disconnected"});
        //this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
        var config = {
          'server': this.brokerConfig.broker,
          'port': this.brokerConfig.port,
           'eventPath': this.topic,
           'unique': unique};
        var rtcConnector = this.rtcConnector = rtcommRtcConnector.get(config);
        rtcConnector.on('connected',function(){
            node.log('connected');
            node.status({fill:"green",shape:"dot",text:"connected"});
        });
        rtcConnector.on('disconnected',function(){
            node.log('disconnected');
            node.status({fill:"red",shape:"ring",text:"disconnected"});
        });
        rtcConnector.on('error',function(){
            node.log('error');
            node.status({fill:"red",shape:"ring",text:"error"});
        });

        // Start the monitor
        rtcConnector.start();

        // Filter Callback
        var processMessage = function processMessage(topic, message) {
          var msg = {};
          //node.log('.processMessage('+topic+')+ '+message);
          try {
            msg.payload = JSON.parse(message);
          } catch(e) {
            node.error("Message cannot be parsed as an Object: "+message);
          }
          var match = /\/(session)\/(started|stopped|modified|failed)\/(.+$)/.exec(topic);
          if (match &&
              typeof msg.payload === 'object' &&
              msg.payload.method === 'RTCOMM_EVENT_FIRED' ) {
            //console.log('MATCH ARRAY'+match);
            msg.topic = topic;
            msg.payload.category = match[1] || 'unknown';
            msg.payload.action = match[2]|| 'unknown';

            var m = /\//.test(match[3]) ? /(.+)\/(.+)/.exec(match[3]) : [null, match[3], null];
            msg.payload.fromendpointid = m[1] || 'unknown';
            if (m[2]) {
              msg.payload.toendpointid = m[2];
            }

          } else {
            node.error('Unable to form message for topic:'+topic+' and message: '+message);
            msg = null;
          }
          node.send(msg);
        };
        this.filter = rtcConnector.addFilter({
          'category': {
            'session': true,
			'registration': false
            },
           'action': {
             'started':this.started,
             'modified':this.modified,
             'stopped':this.stopped,
             'failed':this.failed },
           'toendpointid': this.toEndpoint,
           'fromendpointid':this.fromEndpoint},
           processMessage);

        this.log('Added Filter - '+this.filter.subscriptions);
      } else {
        this.error("missing broker configuration");
      }
    }

    // Register the node by name. This must be called before overriding any of the
    // Node functions.
    RED.nodes.registerType("rtcomm event",RtcommRtcConnectorNode);

    RtcommRtcConnectorNode.prototype.close = function() {
        if (this.filter) {
          this.rtcConnector.removeFilter(this.filter);
        }
        this.rtcConnector.stop();
    };

    var rtcomm3PCC = require('rtcomm').ThirdPartyCC;

    /*
     * Generate a Random UUID
     */
    var generateUUID = function generateUUID() {
        /*jslint bitwise: true */
        var d = new Date().getTime();
        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = (d + Math.random()*16)%16 | 0;
            d = Math.floor(d/16);
            return (c==='x' ? r : (r&0x7|0x8)).toString(16);
        });
        return uuid;
    };

	var transList = {};

    // The 3PCC node definition
	function Rtcomm3PCCNode(n) {
        RED.nodes.createNode(this,n);
        this.topic = (n.topic || '/rtcomm/') + 'callControl';
        this.broker = n.broker;
        this.brokerConfig = RED.nodes.getNode(this.broker);
        this.thirdPCC = null;

        var node = this;
        if (this.brokerConfig) {
           this.status({fill:"red",shape:"ring",text:"disconnected"});

           var config = {
            'server': this.brokerConfig.broker,
            'port': this.brokerConfig.port,
            'topic': this.topic};

          var thirdPCC = this.thirdPCC = rtcomm3PCC.get(config,function(message){
        	  							var nodeRedMsg;
        	  							var transID = message.transID;
        	  							var trans = transList[transID];

        	  							if (trans == null)
        	  							{
        	  								node.error("ERROR: Unknown transID received from nodeModule");
        	  								return;
        	  							}

        	  							if (message.result == 'SUCCESS')
        	  							{
											node.log('3PCC call INITIATED successfully');
    	  									nodeRedMsg = {'payload' : {
    	  													'result' : 'SUCCESS',
    	  													'callerEndpointID' : trans.callerEndpointID,
    	  													'calleeEndpointID' : trans.calleeEndpointID,
    	  													'sigSessionID' : trans.sigSessionID}
    	  												};
        	  							}
        	  							else
        	  							{
											node.error('3PCC call FAILED with reason:' + message.reason);
    	  									nodeRedMsg = {'payload' : {
													'result' : 'FAILURE',
													'reason' : message.reason,
													'callerEndpointID' : trans.callerEndpointID,
													'calleeEndpointID' : trans.calleeEndpointID,
													'sigSessionID' : trans.sigSessionID}
											};
        	  							}
        	  							node.send(nodeRedMsg);
									}.bind(this));

		  thirdPCC.on('connected',function(){
              node.log('connected');
              node.status({fill:"green",shape:"dot",text:"connected"});
          });
          thirdPCC.on('disconnected',function(){
              node.log('disconnected');
              node.status({fill:"red",shape:"ring",text:"disconnected"});
          });

          this.on('input', function(msg) {
            if (typeof msg.payload === 'object') {

            	if (msg.payload.callerEndpointID && msg.payload.calleeEndpointID){
					node.log('.input callerEndpointID:'+msg.payload.callerEndpointID);
					node.log('.input calleeEndpointID:'+msg.payload.calleeEndpointID);

					var sigSessionID = null;
					if (msg.payload.sigSessionID)
						sigSessionID = msg.payload.sigSessionID;

					var transID = generateUUID();
					transList[transID] = {
									'callerEndpointID': msg.payload.callerEndpointID,
									'calleeEndpointID': msg.payload.calleeEndpointID,
									'sigSessionID' : sigSessionID
									};

					//	FIX: Currently passing in null for session ID. Should allow this to be input on the node.
					this.thirdPCC.startCall(msg.payload.callerEndpointID,msg.payload.calleeEndpointID, sigSessionID, transID);
            	}
            	else{
                   	node.error('msg.payload does not include callerEndpointID or calleeEndpointID: ' +  msg);
            	}
			}
			else {
              node.error('msg.payload is not an Object. Unable to create 3PCC for: '+ msg);
            }
		  }.bind(this));

		  // Start the 3PCC Node
          thirdPCC.start();
        } else {
          this.error("missing broker configuration");
        }
      }

      // Register the node by name. This must be called before overriding any of the
      // Node functions.
      RED.nodes.registerType("rtcomm 3PCC",Rtcomm3PCCNode);
      Rtcomm3PCCNode.prototype.close = function() {
          this.thirdPCC.stop();
      };

	   var rtcommPresenceTracking = require('rtcomm').RtcConnector;

   // The rtcomm RtcConnector node definition
  function rtcommPresenceTrackingNode(n) {
      RED.nodes.createNode(this,n);
	  var subtopic = n.subtopic;
      this.topic = (n.topic || '/rtcomm/')+'sphere/'+subtopic;
      this.broker = n.broker;
      this.brokerConfig = RED.nodes.getNode(this.broker);
      this.rtcConnector = null;
	  var endpoint = n.fromendpoint;

  //	This defines the event filter

		var unique = n.unique || false;

      var node = this;
      if (this.brokerConfig) {
         this.status({fill:"red",shape:"ring",text:"disconnected"});
        //this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
        var config = {
          'server': this.brokerConfig.broker,
          'port': this.brokerConfig.port,
           'eventPath': this.topic,
           'unique': unique};
        var rtcConnector = this.rtcConnector = rtcommPresenceTracking.get(config);
        rtcConnector.on('connected',function(){
            node.log('connected');
            node.status({fill:"green",shape:"dot",text:"connected"});
        });
        rtcConnector.on('disconnected',function(){
            node.log('disconnected');
            node.status({fill:"red",shape:"ring",text:"disconnected"});
        });
        rtcConnector.on('error',function(){
            node.log('error');
            node.status({fill:"red",shape:"ring",text:"error"});
        });

        // Start the monitor
        rtcConnector.start();

        // Filter Callback
        var processMessage = function processMessage(topic, message) {

		  var endpointStr = /([^\/]+$)/.exec(topic);
		  var filter = endpoint;
		  /*
		   var match = new RegExp("\/(sphere)/("+subtopic+")\/(.+$)");
		    node.log(match);
			*/
			filter = filter.replace("*",".*");
		  var reEx = new RegExp("(" +filter+")");
		  var filterMatch = reEx.exec(endpointStr);

		  if(filterMatch){
          var msg = {};

		  if(message.length == 0){
			  msg.payload = {"state":"unavailable", 'endpointID': endpointStr[1]};
			  msg.topic = topic;
			  node.send(msg);

		  }
		  else{
			  try {
            msg.payload = JSON.parse(message);
          } catch(e) {
            node.error("Message cannot be parsed as an Object: "+message);
          }

          if (
              typeof msg.payload === 'object' &&
              msg.payload.method === 'DOCUMENT' ) {

            msg.topic = topic;
			msg.payload = {
				'addressTopic': msg.payload.addressTopic,
				'appContext': msg.payload.appContext,
				'state': msg.payload.state,
				'alias': msg.payload.alias,
				'userDefines': msg.payload.userDefines,
				'endpointID': endpointStr[1]

			}

          } else {
            node.error('Unable to form message for topic:'+topic+' and message: '+message);
            msg = null;
          }
          node.send(msg);
		  }
		  }
        };
        this.filter = rtcConnector.addFilter({
			'type': true ,
			'state': true,
			'alias': true,
			'userDefines': true} ,processMessage);
		   this.log('Added Filter - '+this.filter.subscriptions);
      } else {
        this.error("missing broker configuration");
      }
    }
    // Register the node by name. This must be called before overriding any of the
    // Node functions.
    RED.nodes.registerType("rtcomm presence",rtcommPresenceTrackingNode);
    rtcommPresenceTrackingNode.prototype.close = function() {
		 if (this.filter) {
          this.rtcConnector.removeFilter(this.filter);
        }
        this.rtcConnector.stop();
    };

  };

 <commit_msg>removing some comments and renaming a function from rtcommPresenceTrackingNode to rtcommPresenceNode<commit_after>/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Require main module
module.exports = function(RED) {
  "use strict";

  var rtcommRtcConnector = require('rtcomm').RtcConnector;

   // The rtcomm RtcConnector node definition
  function RtcommRtcConnectorNode(n) {
      RED.nodes.createNode(this,n);
      this.topic = (n.topic || '/rtcomm/')+'event';
      this.broker = n.broker;
      this.brokerConfig = RED.nodes.getNode(this.broker);
      this.rtcConnector = null;

  //	This defines the event filter

      this.started = n.started || false;
      this.failed = n.failed || false;
      this.modified = n.modified || false;
      this.stopped = n.stopped || false;
      this.fromEndpoint = n.fromendpoint;
      this.toEndpoint = n.toendpoint;
      var unique = n.unique || false;

      var node = this;
      if (this.brokerConfig) {
         this.status({fill:"red",shape:"ring",text:"disconnected"});
        //this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
        var config = {
          'server': this.brokerConfig.broker,
          'port': this.brokerConfig.port,
           'eventPath': this.topic,
           'unique': unique};
        var rtcConnector = this.rtcConnector = rtcommRtcConnector.get(config);
        rtcConnector.on('connected',function(){
            node.log('connected');
            node.status({fill:"green",shape:"dot",text:"connected"});
        });
        rtcConnector.on('disconnected',function(){
            node.log('disconnected');
            node.status({fill:"red",shape:"ring",text:"disconnected"});
        });
        rtcConnector.on('error',function(){
            node.log('error');
            node.status({fill:"red",shape:"ring",text:"error"});
        });

        // Start the monitor
        rtcConnector.start();

        // Filter Callback
        var processMessage = function processMessage(topic, message) {
          var msg = {};
          //node.log('.processMessage('+topic+')+ '+message);
          try {
            msg.payload = JSON.parse(message);
          } catch(e) {
            node.error("Message cannot be parsed as an Object: "+message);
          }
          var match = /\/(session)\/(started|stopped|modified|failed)\/(.+$)/.exec(topic);
          if (match &&
              typeof msg.payload === 'object' &&
              msg.payload.method === 'RTCOMM_EVENT_FIRED' ) {
            //console.log('MATCH ARRAY'+match);
            msg.topic = topic;
            msg.payload.category = match[1] || 'unknown';
            msg.payload.action = match[2]|| 'unknown';

            var m = /\//.test(match[3]) ? /(.+)\/(.+)/.exec(match[3]) : [null, match[3], null];
            msg.payload.fromendpointid = m[1] || 'unknown';
            if (m[2]) {
              msg.payload.toendpointid = m[2];
            }

          } else {
            node.error('Unable to form message for topic:'+topic+' and message: '+message);
            msg = null;
          }
          node.send(msg);
        };
        this.filter = rtcConnector.addFilter({
          'category': {
            'session': true,
			'registration': false
            },
           'action': {
             'started':this.started,
             'modified':this.modified,
             'stopped':this.stopped,
             'failed':this.failed },
           'toendpointid': this.toEndpoint,
           'fromendpointid':this.fromEndpoint},
           processMessage);

        this.log('Added Filter - '+this.filter.subscriptions);
      } else {
        this.error("missing broker configuration");
      }
    }

    // Register the node by name. This must be called before overriding any of the
    // Node functions.
    RED.nodes.registerType("rtcomm event",RtcommRtcConnectorNode);

    RtcommRtcConnectorNode.prototype.close = function() {
        if (this.filter) {
          this.rtcConnector.removeFilter(this.filter);
        }
        this.rtcConnector.stop();
    };

    var rtcomm3PCC = require('rtcomm').ThirdPartyCC;

    /*
     * Generate a Random UUID
     */
    var generateUUID = function generateUUID() {
        /*jslint bitwise: true */
        var d = new Date().getTime();
        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = (d + Math.random()*16)%16 | 0;
            d = Math.floor(d/16);
            return (c==='x' ? r : (r&0x7|0x8)).toString(16);
        });
        return uuid;
    };

	var transList = {};

    // The 3PCC node definition
	function Rtcomm3PCCNode(n) {
        RED.nodes.createNode(this,n);
        this.topic = (n.topic || '/rtcomm/') + 'callControl';
        this.broker = n.broker;
        this.brokerConfig = RED.nodes.getNode(this.broker);
        this.thirdPCC = null;

        var node = this;
        if (this.brokerConfig) {
           this.status({fill:"red",shape:"ring",text:"disconnected"});

           var config = {
            'server': this.brokerConfig.broker,
            'port': this.brokerConfig.port,
            'topic': this.topic};

          var thirdPCC = this.thirdPCC = rtcomm3PCC.get(config,function(message){
        	  							var nodeRedMsg;
        	  							var transID = message.transID;
        	  							var trans = transList[transID];

        	  							if (trans == null)
        	  							{
        	  								node.error("ERROR: Unknown transID received from nodeModule");
        	  								return;
        	  							}

        	  							if (message.result == 'SUCCESS')
        	  							{
											node.log('3PCC call INITIATED successfully');
    	  									nodeRedMsg = {'payload' : {
    	  													'result' : 'SUCCESS',
    	  													'callerEndpointID' : trans.callerEndpointID,
    	  													'calleeEndpointID' : trans.calleeEndpointID,
    	  													'sigSessionID' : trans.sigSessionID}
    	  												};
        	  							}
        	  							else
        	  							{
											node.error('3PCC call FAILED with reason:' + message.reason);
    	  									nodeRedMsg = {'payload' : {
													'result' : 'FAILURE',
													'reason' : message.reason,
													'callerEndpointID' : trans.callerEndpointID,
													'calleeEndpointID' : trans.calleeEndpointID,
													'sigSessionID' : trans.sigSessionID}
											};
        	  							}
        	  							node.send(nodeRedMsg);
									}.bind(this));

		  thirdPCC.on('connected',function(){
              node.log('connected');
              node.status({fill:"green",shape:"dot",text:"connected"});
          });
          thirdPCC.on('disconnected',function(){
              node.log('disconnected');
              node.status({fill:"red",shape:"ring",text:"disconnected"});
          });

          this.on('input', function(msg) {
            if (typeof msg.payload === 'object') {

            	if (msg.payload.callerEndpointID && msg.payload.calleeEndpointID){
					node.log('.input callerEndpointID:'+msg.payload.callerEndpointID);
					node.log('.input calleeEndpointID:'+msg.payload.calleeEndpointID);

					var sigSessionID = null;
					if (msg.payload.sigSessionID)
						sigSessionID = msg.payload.sigSessionID;

					var transID = generateUUID();
					transList[transID] = {
									'callerEndpointID': msg.payload.callerEndpointID,
									'calleeEndpointID': msg.payload.calleeEndpointID,
									'sigSessionID' : sigSessionID
									};

					//	FIX: Currently passing in null for session ID. Should allow this to be input on the node.
					this.thirdPCC.startCall(msg.payload.callerEndpointID,msg.payload.calleeEndpointID, sigSessionID, transID);
            	}
            	else{
                   	node.error('msg.payload does not include callerEndpointID or calleeEndpointID: ' +  msg);
            	}
			}
			else {
              node.error('msg.payload is not an Object. Unable to create 3PCC for: '+ msg);
            }
		  }.bind(this));

		  // Start the 3PCC Node
          thirdPCC.start();
        } else {
          this.error("missing broker configuration");
        }
      }

      // Register the node by name. This must be called before overriding any of the
      // Node functions.
      RED.nodes.registerType("rtcomm 3PCC",Rtcomm3PCCNode);
      Rtcomm3PCCNode.prototype.close = function() {
          this.thirdPCC.stop();
      };

	   var rtcommPresenceTracking = require('rtcomm').RtcConnector;

   // The rtcomm Presence node definition
  function rtcommPresenceNode(n) {
      RED.nodes.createNode(this,n);
	  var subtopic = n.subtopic;
      this.topic = (n.topic || '/rtcomm/')+'sphere/'+subtopic;
      this.broker = n.broker;
      this.brokerConfig = RED.nodes.getNode(this.broker);
      this.rtcConnector = null;
	  var endpoint = n.fromendpoint;
	  var unique = n.unique || false;

      var node = this;
      if (this.brokerConfig) {
         this.status({fill:"red",shape:"ring",text:"disconnected"});
        //this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
        var config = {
          'server': this.brokerConfig.broker,
          'port': this.brokerConfig.port,
           'eventPath': this.topic,
           'unique': unique};
        var rtcConnector = this.rtcConnector = rtcommPresenceTracking.get(config);
        rtcConnector.on('connected',function(){
            node.log('connected');
            node.status({fill:"green",shape:"dot",text:"connected"});
        });
        rtcConnector.on('disconnected',function(){
            node.log('disconnected');
            node.status({fill:"red",shape:"ring",text:"disconnected"});
        });
        rtcConnector.on('error',function(){
            node.log('error');
            node.status({fill:"red",shape:"ring",text:"error"});
        });

        // Start the monitor
        rtcConnector.start();

        // Filter Callback
        var processMessage = function processMessage(topic, message) {

		  var endpointStr = /([^\/]+$)/.exec(topic);
		  var filter = endpoint;

			filter = filter.replace("*",".*");
		  var reEx = new RegExp("(" +filter+")");
		  var filterMatch = reEx.exec(endpointStr);

		  if(filterMatch){
          var msg = {};

		  if(message.length == 0){
			  msg.payload = {"state":"unavailable", 'endpointID': endpointStr[1]};
			  msg.topic = topic;
			  node.send(msg);

		  }
		  else{
			  try {
            msg.payload = JSON.parse(message);
          } catch(e) {
            node.error("Message cannot be parsed as an Object: "+message);
          }

          if (
              typeof msg.payload === 'object' &&
              msg.payload.method === 'DOCUMENT' ) {

            msg.topic = topic;
			msg.payload = {
				'addressTopic': msg.payload.addressTopic,
				'appContext': msg.payload.appContext,
				'state': msg.payload.state,
				'alias': msg.payload.alias,
				'userDefines': msg.payload.userDefines,
				'endpointID': endpointStr[1]
			}

          } else {
            node.error('Unable to form message for topic:'+topic+' and message: '+message);
            msg = null;
          }
          node.send(msg);
		  }
		  }
        };
        this.filter = rtcConnector.addFilter({
			'type': true ,
			'state': true,
			'alias': true,
			'userDefines': true} ,processMessage);
		   this.log('Added Filter - '+this.filter.subscriptions);
      } else {
        this.error("missing broker configuration");
      }
    }
    // Register the node by name. This must be called before overriding any of the
    // Node functions.
    RED.nodes.registerType("rtcomm presence",rtcommPresenceNode);
    rtcommPresenceNode.prototype.close = function() {
		 if (this.filter) {
          this.rtcConnector.removeFilter(this.filter);
        }
        this.rtcConnector.stop();
    };

  };

 <|endoftext|>


<commit_before>/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 **/

/**************************************************************
 *	Curved Path - a curve path is simply a array of connected
 *  curves, but retains the api of a curve
 **************************************************************/

THREE.CurvePath = function () {

	this.curves = [];

	this.autoClose = false; // Automatically closes the path

};

THREE.CurvePath.prototype = Object.assign( Object.create( THREE.Curve.prototype ), {

	constructor: THREE.CurvePath,

	add: function ( curve ) {

		this.curves.push( curve );

	},

	closePath: function () {

		// Add a line curve if start and end of lines are not connected
		var startPoint = this.curves[ 0 ].getPoint( 0 );
		var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );

		if ( ! startPoint.equals( endPoint ) ) {

			this.curves.push( new THREE.LineCurve( endPoint, startPoint ) );

		}

	},

	// To get accurate point with reference to
	// entire path distance at time t,
	// following has to be done:

	// 1. Length of each sub path have to be known
	// 2. Locate and identify type of curve
	// 3. Get t for the curve
	// 4. Return curve.getPointAt(t')

	getPoint: function ( t ) {

		var d = t * this.getLength();
		var curveLengths = this.getCurveLengths();
		var i = 0;

		// To think about boundaries points.

		while ( i < curveLengths.length ) {

			if ( curveLengths[ i ] >= d ) {

				var diff = curveLengths[ i ] - d;
				var curve = this.curves[ i ];

				var segmentLength = curve.getLength();
				var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;

				return curve.getPointAt( u );

			}

			i ++;

		}

		return null;

		// loop where sum != 0, sum > d , sum+1 <d

	},

	// We cannot use the default THREE.Curve getPoint() with getLength() because in
	// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
	// getPoint() depends on getLength

	getLength: function () {

		var lens = this.getCurveLengths();
		return lens[ lens.length - 1 ];

	},

	// cacheLengths must be recalculated.
	updateArcLengths: function () {

		this.needsUpdate = true;
		this.cacheLengths = null;
		this.getLengths();

	},

	// Compute lengths and cache them
	// We cannot overwrite getLengths() because UtoT mapping uses it.

	getCurveLengths: function () {

		// We use cache values if curves and cache array are same length

		if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {

			return this.cacheLengths;

		}

		// Get length of sub-curve
		// Push sums into cached array

		var lengths = [], sums = 0;

		for ( var i = 0, l = this.curves.length; i < l; i ++ ) {

			sums += this.curves[ i ].getLength();
			lengths.push( sums );

		}

		this.cacheLengths = lengths;

		return lengths;

	},

	getSpacedPoints: function ( divisions ) {

		if ( ! divisions ) divisions = 40;

		var points = [];

		for ( var i = 0; i <= divisions; i ++ ) {

			points.push( this.getPoint( i / divisions ) );

		}

		if ( this.autoClose ) {

			points.push( points[ 0 ] );

		}

		return points;

	},

	getPoints: function ( divisions ) {

		divisions = divisions || 12;

		var points = [], last;

		for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {

			var curve = curves[ i ];
			var pts = curve.getPoints( curve instanceof THREE.LineCurve ? 1 : divisions );

			for ( var j = 0; j < pts.length; j++ ) {

				var point = pts[ j ];

				if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates

				points.push( point );
				last = point;

			}

		}

		if ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {

			points.push( points[ 0 ] );

		}

		return points;

	},

	/**************************************************************
	 *	Create Geometries Helpers
	 **************************************************************/

	/// Generate geometry from path points (for Line or Points objects)

	createPointsGeometry: function ( divisions ) {

		var pts = this.getPoints( divisions );
		return this.createGeometry( pts );

	},

	// Generate geometry from equidistant sampling along the path

	createSpacedPointsGeometry: function ( divisions ) {

		var pts = this.getSpacedPoints( divisions );
		return this.createGeometry( pts );

	},

	createGeometry: function ( points ) {

		var geometry = new THREE.Geometry();

		for ( var i = 0, l = points.length; i < l; i ++ ) {

			var point = points[ i ];
			geometry.vertices.push( new THREE.Vector3( point.x, point.y, point.z || 0 ) );

		}

		return geometry;

	}

} );
<commit_msg>CurvePath.getPoints() for Arcs resolution should be doubled (#9168)<commit_after>/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 *
 **/

/**************************************************************
 *	Curved Path - a curve path is simply a array of connected
 *  curves, but retains the api of a curve
 **************************************************************/

THREE.CurvePath = function () {

	this.curves = [];

	this.autoClose = false; // Automatically closes the path

};

THREE.CurvePath.prototype = Object.assign( Object.create( THREE.Curve.prototype ), {

	constructor: THREE.CurvePath,

	add: function ( curve ) {

		this.curves.push( curve );

	},

	closePath: function () {

		// Add a line curve if start and end of lines are not connected
		var startPoint = this.curves[ 0 ].getPoint( 0 );
		var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );

		if ( ! startPoint.equals( endPoint ) ) {

			this.curves.push( new THREE.LineCurve( endPoint, startPoint ) );

		}

	},

	// To get accurate point with reference to
	// entire path distance at time t,
	// following has to be done:

	// 1. Length of each sub path have to be known
	// 2. Locate and identify type of curve
	// 3. Get t for the curve
	// 4. Return curve.getPointAt(t')

	getPoint: function ( t ) {

		var d = t * this.getLength();
		var curveLengths = this.getCurveLengths();
		var i = 0;

		// To think about boundaries points.

		while ( i < curveLengths.length ) {

			if ( curveLengths[ i ] >= d ) {

				var diff = curveLengths[ i ] - d;
				var curve = this.curves[ i ];

				var segmentLength = curve.getLength();
				var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;

				return curve.getPointAt( u );

			}

			i ++;

		}

		return null;

		// loop where sum != 0, sum > d , sum+1 <d

	},

	// We cannot use the default THREE.Curve getPoint() with getLength() because in
	// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
	// getPoint() depends on getLength

	getLength: function () {

		var lens = this.getCurveLengths();
		return lens[ lens.length - 1 ];

	},

	// cacheLengths must be recalculated.
	updateArcLengths: function () {

		this.needsUpdate = true;
		this.cacheLengths = null;
		this.getLengths();

	},

	// Compute lengths and cache them
	// We cannot overwrite getLengths() because UtoT mapping uses it.

	getCurveLengths: function () {

		// We use cache values if curves and cache array are same length

		if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {

			return this.cacheLengths;

		}

		// Get length of sub-curve
		// Push sums into cached array

		var lengths = [], sums = 0;

		for ( var i = 0, l = this.curves.length; i < l; i ++ ) {

			sums += this.curves[ i ].getLength();
			lengths.push( sums );

		}

		this.cacheLengths = lengths;

		return lengths;

	},

	getSpacedPoints: function ( divisions ) {

		if ( ! divisions ) divisions = 40;

		var points = [];

		for ( var i = 0; i <= divisions; i ++ ) {

			points.push( this.getPoint( i / divisions ) );

		}

		if ( this.autoClose ) {

			points.push( points[ 0 ] );

		}

		return points;

	},

	getPoints: function ( divisions ) {

		divisions = divisions || 12;

		var points = [], last;

		for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {

			var curve = curves[ i ];
			var resolution = curve instanceof THREE.EllipseCurve ? divisions * 2
				: curve instanceof THREE.LineCurve ? 1
				: curve instanceof THREE.SplineCurve ? divisions * curves.points.length
				: divisions;

			var pts = curve.getPoints( resolution );

			for ( var j = 0; j < pts.length; j++ ) {

				var point = pts[ j ];

				if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates

				points.push( point );
				last = point;

			}

		}

		if ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {

			points.push( points[ 0 ] );

		}

		return points;

	},

	/**************************************************************
	 *	Create Geometries Helpers
	 **************************************************************/

	/// Generate geometry from path points (for Line or Points objects)

	createPointsGeometry: function ( divisions ) {

		var pts = this.getPoints( divisions );
		return this.createGeometry( pts );

	},

	// Generate geometry from equidistant sampling along the path

	createSpacedPointsGeometry: function ( divisions ) {

		var pts = this.getSpacedPoints( divisions );
		return this.createGeometry( pts );

	},

	createGeometry: function ( points ) {

		var geometry = new THREE.Geometry();

		for ( var i = 0, l = points.length; i < l; i ++ ) {

			var point = points[ i ];
			geometry.vertices.push( new THREE.Vector3( point.x, point.y, point.z || 0 ) );

		}

		return geometry;

	}

} );
<|endoftext|>


<commit_before>import { UIManager } from 'react-native'
import { React, Component, PureComponent } from '../Component.js'

import { CreditCardInput, LiteCreditCardInput } from "react-native-credit-card-input";
import { observable, action, autorun, computed, asMap } from 'mobx'
import { observer } from 'mobx-react/native'
import { CardIOModule, CardIOUtilities } from 'react-native-awesome-card-io'

import { LargeButton } from '../Button.js'
import { logger } from '../Curry.js'
import { paymentStore } from './PaymentStore.js'

const log = logger('Payment/CardInput.js')

// const placeHolders = { number: "xxxx xxxx xxxx xxxx", expiry: "MM/YY", cvc: "CVC" }

const scanConfig = {
    requirePostalCode: true,
    // useCardIOLogo: true,
    hideCardIOLogo: true,
}

const largeButtonStyle = {
    height: 55,
    margin: 5,
}

@observer
export class CardInput extends PureComponent {
    scanCard = () => {
        CardIOModule
            .scanCard(scanConfig)
            .then(card => {
                paymentStore.addCard(card)
            })
            .catch(() => {
                // the user cancelled
            })
    }

    render = () => {
        return <LargeButton
                    label="Add a New Card"
                    onPress={this.scanCard}
                    style={largeButtonStyle}
                    />
    }
}

@observer
export class CardInput2 extends PureComponent {

    onChange = (value) => {
        log(value)
    }

    render = () => {
        return <CreditCardInput
                    onChange={this.onChange}
                    placeholders={placeHolders}
                    validColor={'#000000'}
                    placeholderColor={'rgba(0, 0, 0, 0.65)'}
                    />
    }
}

UIManager.setLayoutAnimationEnabledExperimental(true)
<commit_msg>Preload card scanner on iOS for better perf.<commit_after>import { UIManager } from 'react-native'
import { React, Component, PureComponent, Platform } from '../Component.js'

import { CreditCardInput, LiteCreditCardInput } from "react-native-credit-card-input";
import { observable, action, autorun, computed, asMap } from 'mobx'
import { observer } from 'mobx-react/native'
import { CardIOModule, CardIOUtilities } from 'react-native-awesome-card-io'

import { LargeButton } from '../Button.js'
import { logger } from '../Curry.js'
import { paymentStore } from './PaymentStore.js'

const log = logger('Payment/CardInput.js')

// const placeHolders = { number: "xxxx xxxx xxxx xxxx", expiry: "MM/YY", cvc: "CVC" }

const scanConfig = {
    requirePostalCode: true,
    // useCardIOLogo: true,
    hideCardIOLogo: true,
}

const largeButtonStyle = {
    height: 55,
    margin: 5,
}

@observer
export class CardInput extends PureComponent {

    componentWillMount = () => {
        if (Platform.OS === 'ios')
            CardIOUtilities.preload()
    }

    scanCard = () => {
        CardIOModule
            .scanCard(scanConfig)
            .then(card => {
                paymentStore.addCard(card)
            })
            .catch(() => {
                // the user cancelled
            })
    }

    render = () => {
        return <LargeButton
                    label="Add a New Card"
                    onPress={this.scanCard}
                    style={largeButtonStyle}
                    />
    }
}

@observer
export class CardInput2 extends PureComponent {

    onChange = (value) => {
        log(value)
    }

    render = () => {
        return <CreditCardInput
                    onChange={this.onChange}
                    placeholders={placeHolders}
                    validColor={'#000000'}
                    placeholderColor={'rgba(0, 0, 0, 0.65)'}
                    />
    }
}

UIManager.setLayoutAnimationEnabledExperimental(true)
<|endoftext|>


<commit_before>/*
 Copyright 2018 Carmilla Mina Jankovic

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

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

const dataHandler = require('../../data/DataHandler');
const eventCentral = require('../../EventCentral');
const storageManager = require('../../StorageManager');
const roomComposer = require('../../data/composers/RoomComposer');
const userComposer = require('../../data/composers/UserComposer');

class RoomFollowingList extends List {
  constructor({
    title,
    classes = [],
    elementId = `rFList-${Date.now()}`,
  }) {
    classes.push('roomList');
    classes.push('chatRoomFollowingList');

    super({
      title,
      elementId,
      classes,
      listType: 'followedRooms',
      filter: {
        rules: [
          { paramName: 'isUser', paramValue: false },
          { paramName: 'isWhisper', paramValue: false },
        ],
      },
      userFilter: {
        rules: [{
          paramName: 'followingRooms',
          shouldInclude: true,
          shouldBeTrue: true,
          objectParamName: 'objectId',
        }],
      },
      listItemFields: [
        {
          paramName: 'objectId',
          convertFunc: (objectId) => {
            const room = roomComposer.getRoom({ roomId: objectId });

            if (room) {
              return room.roomName;
            }

            return objectId;
          },
        },
      ],
      focusedId: storageManager.getCurrentRoom(),
      listItemClickFuncs: {
        leftFunc: (objectId) => {
          eventCentral.emitEvent({
            event: eventCentral.Events.SWITCH_ROOM,
            params: {
              listType: this.ListTypes.ROOMS,
              origin: this.elementId,
              room: {
                objectId,
              },
            },
          });
        },
        right: (objectId) => {
          roomComposer.unfollow({
            roomId: objectId,
          });
        },
      },
      dependencies: [
        dataHandler.rooms,
        dataHandler.users,
        dataHandler.aliases,
        dataHandler.teams,
      ],
      collector: dataHandler.rooms,
    });

    eventCentral.addWatcher({
      event: eventCentral.Events.SWITCH_ROOM,
      func: ({
        room,
        origin,
        listType = '',
      }) => {
        const { objectId } = room;

        this.unmarkItem({ objectId });

        if (!origin || origin !== this.elementId) {
          this.removeFocusOnItem();
        }
      },
    });

    eventCentral.addWatcher({
      event: eventCentral.Events.FOLLOWED_ROOM,
      func: ({
        room,
      }) => {
        const { objectId } = room;

        this.addOneItem({ object: room });
        this.setFocusedListItem(objectId);
      },
    });

    eventCentral.addWatcher({
      event: eventCentral.Events.MESSAGE,
      func: ({
        message,
      }) => {
        const { roomId } = message;

        if (storageManager.getCurrentRoom() === roomId) {
          return;
        }

        this.markItem({ objectId: roomId });
      },
    });
  }

  getCollectorObjects() {
    const currentUser = userComposer.getCurrentUser();

    if (!currentUser) {
      return [];
    }

    const allRooms = this.collector.getObjects({
      filter: this.filter,
    });
    const { followingRooms = [] } = currentUser;

    return allRooms.filter(object => followingRooms.includes(object.objectId)).sort((a, b) => {
      const aParam = a.roomName.toLowerCase();
      const bParam = b.roomName.toLowerCase();

      if (aParam < bParam) {
        return -1;
      } else if (aParam > bParam) {
        return 1;
      }

      return 0;
    });
  }
}

module.exports = RoomFollowingList;
<commit_msg>Unused<commit_after>/*
 Copyright 2018 Carmilla Mina Jankovic

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

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

const dataHandler = require('../../data/DataHandler');
const eventCentral = require('../../EventCentral');
const storageManager = require('../../StorageManager');
const roomComposer = require('../../data/composers/RoomComposer');
const userComposer = require('../../data/composers/UserComposer');

class RoomFollowingList extends List {
  constructor({
    title,
    classes = [],
    elementId = `rFList-${Date.now()}`,
  }) {
    classes.push('roomList');
    classes.push('chatRoomFollowingList');

    super({
      title,
      elementId,
      classes,
      listType: 'followedRooms',
      filter: {
        rules: [
          { paramName: 'isUser', paramValue: false },
          { paramName: 'isWhisper', paramValue: false },
        ],
      },
      userFilter: {
        rules: [{
          paramName: 'followingRooms',
          shouldInclude: true,
          shouldBeTrue: true,
          objectParamName: 'objectId',
        }],
      },
      listItemFields: [
        {
          paramName: 'objectId',
          convertFunc: (objectId) => {
            const room = roomComposer.getRoom({ roomId: objectId });

            if (room) {
              return room.roomName;
            }

            return objectId;
          },
        },
      ],
      focusedId: storageManager.getCurrentRoom(),
      listItemClickFuncs: {
        leftFunc: (objectId) => {
          eventCentral.emitEvent({
            event: eventCentral.Events.SWITCH_ROOM,
            params: {
              listType: this.ListTypes.ROOMS,
              origin: this.elementId,
              room: {
                objectId,
              },
            },
          });
        },
        right: (objectId) => {
          roomComposer.unfollow({
            roomId: objectId,
          });
        },
      },
      dependencies: [
        dataHandler.rooms,
        dataHandler.users,
        dataHandler.aliases,
        dataHandler.teams,
      ],
      collector: dataHandler.rooms,
    });

    eventCentral.addWatcher({
      event: eventCentral.Events.SWITCH_ROOM,
      func: ({
        room,
        origin,
      }) => {
        const { objectId } = room;

        this.unmarkItem({ objectId });

        if (!origin || origin !== this.elementId) {
          this.removeFocusOnItem();
        }
      },
    });

    eventCentral.addWatcher({
      event: eventCentral.Events.FOLLOWED_ROOM,
      func: ({
        room,
      }) => {
        const { objectId } = room;

        this.addOneItem({ object: room });
        this.setFocusedListItem(objectId);
      },
    });

    eventCentral.addWatcher({
      event: eventCentral.Events.MESSAGE,
      func: ({
        message,
      }) => {
        const { roomId } = message;

        if (storageManager.getCurrentRoom() === roomId) {
          return;
        }

        this.markItem({ objectId: roomId });
      },
    });
  }

  getCollectorObjects() {
    const currentUser = userComposer.getCurrentUser();

    if (!currentUser) {
      return [];
    }

    const allRooms = this.collector.getObjects({
      filter: this.filter,
    });
    const { followingRooms = [] } = currentUser;

    return allRooms.filter(object => followingRooms.includes(object.objectId)).sort((a, b) => {
      const aParam = a.roomName.toLowerCase();
      const bParam = b.roomName.toLowerCase();

      if (aParam < bParam) {
        return -1;
      } else if (aParam > bParam) {
        return 1;
      }

      return 0;
    });
  }
}

module.exports = RoomFollowingList;
<|endoftext|>


<commit_before>
/**
 *  Layer selector: it allows to select the layers that will be shown in the map
 *  - It needs the mapview, the element template and the dropdown template
 *
 *  var layer_selector = new cdb.geo.ui.LayerSelector({
 *    mapView: mapView,
 *    template: element_template,
 *    dropdown_template: dropdown_template
 *  });
 */

cdb.geo.ui.LayerSelector = cdb.core.View.extend({

  className: 'cartodb-layer-selector-box',

  events: {
    "click":     '_openDropdown',
    "dblclick":  'killEvent',
    "mousedown": 'killEvent'
  },

  initialize: function() {
    this.map = this.options.mapView.map;

    this.mapView  = this.options.mapView;
    this.mapView.bind('click zoomstart drag', function() {
      this.dropdown && this.dropdown.hide()
    }, this);
    this.add_related_model(this.mapView);

    this.layers = [];
  },

  render: function() {

    this.$el.html(this.options.template(this.options));

    this.dropdown = new cdb.ui.common.Dropdown({
      className:"cartodb-dropdown border",
      template: this.options.dropdown_template,
      target: this.$el.find("a"),
      speedIn: 300,
      speedOut: 200,
      position: "position",
      tick: "right",
      vertical_position: "down",
      horizontal_position: "right",
      vertical_offset: 7,
      horizontal_offset: 13
    });

    if (cdb.god) cdb.god.bind("closeDialogs", this.dropdown.hide, this.dropdown);

    this.$el.append(this.dropdown.render().el);

    this._getLayers();
    this._setCount();

    return this;
  },

  _getLayers: function() {
    var self = this;

    _.each(this.map.layers.models, function(layer) {

      if (layer.get("type") == 'layergroup') {
        var layerGroupView = self.mapView.getLayerByCid(layer.cid);
        for (var i = 0 ; i < layerGroupView.getLayerCount(); ++i) {
          var l = layerGroupView.getLayer(i);
          var m = new cdb.core.Model(l);
          m.set('order', i);
          m.set('type', 'layergroup');

          m.set('visible', !layerGroupView.getSubLayer(i).get('hidden'));
          m.bind('change:visible', function(model) {
            this.trigger("change:visible", model.get('visible'), model.get('order'), model);
          }, self);

          if(self.options.layer_names) {
            m.set('layer_name', self.options.layer_names[i]);
          } else {
            m.set('layer_name', l.options.layer_name);
          }

          var layerView = self._createLayer('LayerViewFromLayerGroup', {
            model: m,
            layerView: layerGroupView,
            layerIndex: i
          });
          layerView.bind('switchChanged', self._setCount, self);
          self.layers.push(layerView);
        }
      } else if (layer.get("type") === "CartoDB" || layer.get('type') === 'torque') {
        var layerView = self._createLayer('LayerView', { model: layer });
        layerView.bind('switchChanged', self._setCount, self);
        self.layers.push(layerView);
        layerView.model.bind('change:visible', function(model) {
          this.trigger("change:visible", model.get('visible'), model.get('order'), model);
        }, self);
      }

    });
  },

  _createLayer: function(_class, opts) {
    var layerView = new cdb.geo.ui[_class](opts);
    this.$("ul").append(layerView.render().el);
    this.addView(layerView);
    return layerView;
  },

  _setCount: function() {
    var count = 0;
    for (var i = 0, l = this.layers.length; i < l; ++i) {
      var lyr = this.layers[i];

      if (lyr.model.get('visible')) {
        count++;
      }
    }

    this.$('.count').text(count);
    this.trigger("switchChanged", this);
  },

  _openDropdown: function() {
    this.dropdown.open();
  }

});

/**
 *  View for each CartoDB layer
 *  - It needs a model to make it work.
 *
 *  var layerView = new cdb.geo.ui.LayerView({
 *    model: layer_model,
 *    layer_definition: layer_definition
 *  });
 *
 */

cdb.geo.ui.LayerView = cdb.core.View.extend({

  tagName: "li",

  defaults: {
    template: '\
      <%= table_name %>\
      <a href="#switch" class="right <%= visible ? "enabled" : "disabled" %> switch">\
    '
  },

  events: {
    "click": '_onSwitchClick'
  },

  initialize: function() {

    if (!this.model.has('visible')) this.model.set('visible', false);

    this.model.bind("change:visible", this._onSwitchSelected, this);

    this.add_related_model(this.model);

    this._onSwitchSelected();

    // Template
    this.template = this.options.template ? cdb.templates.getTemplate(this.options.template) : _.template(this.defaults.template);
  },

  render: function() {
    this.$el.append(this.template(this.model.attributes));
    return this;
  },

  /*
  * Throw an event when the user clicks in the switch button
  */
  _onSwitchSelected: function() {
    var enabled = this.model.get('visible');

    // Change switch
    this.$el.find(".switch")
      .removeClass(enabled ? 'disabled' : 'enabled')
      .addClass(enabled    ? 'enabled'  : 'disabled');

    // Send trigger
    this.trigger('switchChanged');

  },

  _onSwitchClick: function(e){
    this.killEvent(e);

    // Set model
    this.model.set("visible", !this.model.get("visible"));
  }

});

/**
 *  View for each layer from a layer group
 *  - It needs a model and the layer_definition to make it work.
 *
 *  var layerView = new cdb.geo.ui.LayerViewFromLayerGroup({
 *    model: layer_model,
 *    layerView: layweView
 *  });
 *
 */

cdb.geo.ui.LayerViewFromLayerGroup = cdb.geo.ui.LayerView.extend({

  defaults: {
    template: '\
      <%= layer_name %>\
      <a href="#switch" class="right <%= visible ? "enabled" : "disabled" %> switch">\
    '
  },

  _onSwitchSelected: function() {

    cdb.geo.ui.LayerView.prototype._onSwitchSelected.call(this);
    var sublayer = this.options.layerView.getSubLayer(this.options.layerIndex)
    var visible = this.model.get('visible');

    if (visible) {
      sublayer.show();
    } else {
      sublayer.hide();
    }
  }
});
<commit_msg>fixed double layer counter in layer selector CDB-935<commit_after>
/**
 *  Layer selector: it allows to select the layers that will be shown in the map
 *  - It needs the mapview, the element template and the dropdown template
 *
 *  var layer_selector = new cdb.geo.ui.LayerSelector({
 *    mapView: mapView,
 *    template: element_template,
 *    dropdown_template: dropdown_template
 *  });
 */

cdb.geo.ui.LayerSelector = cdb.core.View.extend({

  className: 'cartodb-layer-selector-box',

  events: {
    "click":     '_openDropdown',
    "dblclick":  'killEvent',
    "mousedown": 'killEvent'
  },

  initialize: function() {
    this.map = this.options.mapView.map;

    this.mapView  = this.options.mapView;
    this.mapView.bind('click zoomstart drag', function() {
      this.dropdown && this.dropdown.hide()
    }, this);
    this.add_related_model(this.mapView);

    this.layers = [];
  },

  render: function() {

    this.$el.html(this.options.template(this.options));

    this.dropdown = new cdb.ui.common.Dropdown({
      className:"cartodb-dropdown border",
      template: this.options.dropdown_template,
      target: this.$el.find("a"),
      speedIn: 300,
      speedOut: 200,
      position: "position",
      tick: "right",
      vertical_position: "down",
      horizontal_position: "right",
      vertical_offset: 7,
      horizontal_offset: 13
    });

    if (cdb.god) cdb.god.bind("closeDialogs", this.dropdown.hide, this.dropdown);

    this.$el.append(this.dropdown.render().el);

    this._getLayers();
    this._setCount();

    return this;
  },

  _getLayers: function() {
    var self = this;
    this.layers = [];

    _.each(this.map.layers.models, function(layer) {

      if (layer.get("type") == 'layergroup') {
        var layerGroupView = self.mapView.getLayerByCid(layer.cid);
        for (var i = 0 ; i < layerGroupView.getLayerCount(); ++i) {
          var l = layerGroupView.getLayer(i);
          var m = new cdb.core.Model(l);
          m.set('order', i);
          m.set('type', 'layergroup');

          m.set('visible', !layerGroupView.getSubLayer(i).get('hidden'));
          m.bind('change:visible', function(model) {
            this.trigger("change:visible", model.get('visible'), model.get('order'), model);
          }, self);

          if(self.options.layer_names) {
            m.set('layer_name', self.options.layer_names[i]);
          } else {
            m.set('layer_name', l.options.layer_name);
          }

          var layerView = self._createLayer('LayerViewFromLayerGroup', {
            model: m,
            layerView: layerGroupView,
            layerIndex: i
          });
          layerView.bind('switchChanged', self._setCount, self);
          self.layers.push(layerView);
        }
      } else if (layer.get("type") === "CartoDB" || layer.get('type') === 'torque') {
        var layerView = self._createLayer('LayerView', { model: layer });
        layerView.bind('switchChanged', self._setCount, self);
        self.layers.push(layerView);
        layerView.model.bind('change:visible', function(model) {
          this.trigger("change:visible", model.get('visible'), model.get('order'), model);
        }, self);
      }

    });
  },

  _createLayer: function(_class, opts) {
    var layerView = new cdb.geo.ui[_class](opts);
    this.$("ul").append(layerView.render().el);
    this.addView(layerView);
    return layerView;
  },

  _setCount: function() {
    var count = 0;
    for (var i = 0, l = this.layers.length; i < l; ++i) {
      var lyr = this.layers[i];

      if (lyr.model.get('visible')) {
        count++;
      }
    }

    this.$('.count').text(count);
    this.trigger("switchChanged", this);
  },

  _openDropdown: function() {
    this.dropdown.open();
  }

});

/**
 *  View for each CartoDB layer
 *  - It needs a model to make it work.
 *
 *  var layerView = new cdb.geo.ui.LayerView({
 *    model: layer_model,
 *    layer_definition: layer_definition
 *  });
 *
 */

cdb.geo.ui.LayerView = cdb.core.View.extend({

  tagName: "li",

  defaults: {
    template: '\
      <%= table_name %>\
      <a href="#switch" class="right <%= visible ? "enabled" : "disabled" %> switch">\
    '
  },

  events: {
    "click": '_onSwitchClick'
  },

  initialize: function() {

    if (!this.model.has('visible')) this.model.set('visible', false);

    this.model.bind("change:visible", this._onSwitchSelected, this);

    this.add_related_model(this.model);

    this._onSwitchSelected();

    // Template
    this.template = this.options.template ? cdb.templates.getTemplate(this.options.template) : _.template(this.defaults.template);
  },

  render: function() {
    this.$el.append(this.template(this.model.attributes));
    return this;
  },

  /*
  * Throw an event when the user clicks in the switch button
  */
  _onSwitchSelected: function() {
    var enabled = this.model.get('visible');

    // Change switch
    this.$el.find(".switch")
      .removeClass(enabled ? 'disabled' : 'enabled')
      .addClass(enabled    ? 'enabled'  : 'disabled');

    // Send trigger
    this.trigger('switchChanged');

  },

  _onSwitchClick: function(e){
    this.killEvent(e);

    // Set model
    this.model.set("visible", !this.model.get("visible"));
  }

});

/**
 *  View for each layer from a layer group
 *  - It needs a model and the layer_definition to make it work.
 *
 *  var layerView = new cdb.geo.ui.LayerViewFromLayerGroup({
 *    model: layer_model,
 *    layerView: layweView
 *  });
 *
 */

cdb.geo.ui.LayerViewFromLayerGroup = cdb.geo.ui.LayerView.extend({

  defaults: {
    template: '\
      <%= layer_name %>\
      <a href="#switch" class="right <%= visible ? "enabled" : "disabled" %> switch">\
    '
  },

  _onSwitchSelected: function() {

    cdb.geo.ui.LayerView.prototype._onSwitchSelected.call(this);
    var sublayer = this.options.layerView.getSubLayer(this.options.layerIndex)
    var visible = this.model.get('visible');

    if (visible) {
      sublayer.show();
    } else {
      sublayer.hide();
    }
  }
});
<|endoftext|>


<commit_before>// LICENSE : MIT

// Original code is https://github.com/azer/prettify-error
// Author : azer
"use strict";
var format = require("format-text");
var leftpad = require("left-pad");
var style = require("style-format");

var template = style('{grey}{ruleId}: {bold}{red}{title} {grey}{filename}:{failingLineNo}:{failingColNo}{reset}\n'
+ '    {red}{v}\n'
+ '    {grey}{previousLineNo}. {previousLine}\n'
+ '    {reset}{failingLineNo}. {failingLine}\n'
+ '    {grey}{nextLineNo}. {nextLine}\n'
+ '    {red}{^}{reset}\n'
+ '{reset}');

/**
 *
 * @param {string} code
 * @param {TextLintMessage} message
 * @returns {*}
 */
function failingCode(code, message) {
    var result = [];
    var lines = code.split('\n');
    var i = message.line - 3;
    while (++i < message.line + 1) {
        if (i + 1 !== message.line) {
            result.push({
                line: message.line - (message.line - i - 1),
                code: lines[i]
            });
            continue;
        }

        result.push({
            line: message.line,
            col: message.column,
            code: lines[i],
            failed: true
        });
    }

    return result;
}

function showColumn(code, tabn, ch) {
    var result = '';
    var i = String(code[1].line).length + code[1].col + 1 + tabn;

    while (i--) {
        result += ' ';
    }

    return result + ch;
}
/**
 *
 * @param {string} code
 * @param {string} filePath
 * @param {TextLintMessage} message
 * @returns {*}
 */
function prettifyError(code, filePath, message) {
    if (!code) {
        return;
    }
    var parsed = failingCode(code, message);
    var previousLineNo = String(parsed[0].line);
    var failingLineNo = String(parsed[1].line);
    var nextLineNo = String(parsed[2].line);
    var linumlen = Math.max(previousLineNo.length,
        failingLineNo.length,
        nextLineNo.length);

    return format(template, {
        ruleId: message.ruleId,
        title: message.message,
        filename: filePath,
        previousLine: parsed[0].code,
        previousLineNo: leftpad(previousLineNo, linumlen),
        previousColNo: parsed[0].col,
        failingLine: parsed[1].code,
        failingLineNo: leftpad(failingLineNo, linumlen),
        failingColNo: parsed[1].col,
        nextLine: parsed[2].code,
        nextLineNo: leftpad(nextLineNo, linumlen),
        nextColNo: parsed[2].col,
        '^': showColumn(parsed, linumlen - failingLineNo.length, '^'),
        'v': showColumn(parsed, linumlen - failingLineNo.length, 'v')
    });
}

/**
 *
 * @param {[TextLintResult]} results
 * @returns {string}
 */
module.exports = function (results) {
    var output = "";
    output += results.map(function (result) {
        var code = require("fs").readFileSync(result.filePath, "utf-8");
        return result.messages.map(function (message) {
            return prettifyError(code, result.filePath, message);
        }).join("\n");
    }).join("\n");

    return output;
};
<commit_msg>chore(pretty-error): add break line for JetBrains IDE<commit_after>// LICENSE : MIT

// Original code is https://github.com/azer/prettify-error
// Author : azer
"use strict";
var format = require("format-text");
var leftpad = require("left-pad");
var style = require("style-format");

var template = style('{grey}{ruleId}: {bold}{red}{title}\n'
    + '{grey}{filename}:{failingLineNo}:{failingColNo}{reset}\n'
    + '    {red}{v}\n'
    + '    {grey}{previousLineNo}. {previousLine}\n'
    + '    {reset}{failingLineNo}. {failingLine}\n'
    + '    {grey}{nextLineNo}. {nextLine}\n'
    + '    {red}{^}{reset}\n'
    + '{reset}');

/**
 *
 * @param {string} code
 * @param {TextLintMessage} message
 * @returns {*}
 */
function failingCode(code, message) {
    var result = [];
    var lines = code.split('\n');
    var i = message.line - 3;
    while (++i < message.line + 1) {
        if (i + 1 !== message.line) {
            result.push({
                line: message.line - (message.line - i - 1),
                code: lines[i]
            });
            continue;
        }

        result.push({
            line: message.line,
            col: message.column,
            code: lines[i],
            failed: true
        });
    }

    return result;
}

function showColumn(code, tabn, ch) {
    var result = '';
    var i = String(code[1].line).length + code[1].col + 1 + tabn;

    while (i--) {
        result += ' ';
    }

    return result + ch;
}
/**
 *
 * @param {string} code
 * @param {string} filePath
 * @param {TextLintMessage} message
 * @returns {*}
 */
function prettifyError(code, filePath, message) {
    if (!code) {
        return;
    }
    var parsed = failingCode(code, message);
    var previousLineNo = String(parsed[0].line);
    var failingLineNo = String(parsed[1].line);
    var nextLineNo = String(parsed[2].line);
    var linumlen = Math.max(previousLineNo.length,
        failingLineNo.length,
        nextLineNo.length);

    return format(template, {
        ruleId: message.ruleId,
        title: message.message,
        filename: filePath,
        previousLine: parsed[0].code,
        previousLineNo: leftpad(previousLineNo, linumlen),
        previousColNo: parsed[0].col,
        failingLine: parsed[1].code,
        failingLineNo: leftpad(failingLineNo, linumlen),
        failingColNo: parsed[1].col,
        nextLine: parsed[2].code,
        nextLineNo: leftpad(nextLineNo, linumlen),
        nextColNo: parsed[2].col,
        '^': showColumn(parsed, linumlen - failingLineNo.length, '^'),
        'v': showColumn(parsed, linumlen - failingLineNo.length, 'v')
    });
}

/**
 *
 * @param {[TextLintResult]} results
 * @returns {string}
 */
module.exports = function (results) {
    var output = "";
    output += results.map(function (result) {
        var code = require("fs").readFileSync(result.filePath, "utf-8");
        return result.messages.map(function (message) {
            return prettifyError(code, result.filePath, message);
        }).join("\n");
    }).join("\n");

    return output;
};
<|endoftext|>


<commit_before>import path from 'path'
import fs from 'fs-extra'
import errors from 'feathers-errors'
import grib2json from 'weacast-grib2json'
import logger from 'winston'
import makeDebug from 'debug'
const debug = makeDebug('weacast:weacast-gfs')

export default {

  // Perform conversion from input TIFF to JSON
  convertForecastTime (runTime, forecastTime) {
    let promise = new Promise((resolve, reject) => {
      const filePath = this.getForecastTimeFilePath(runTime, forecastTime)
      const convertedFilePath = this.getForecastTimeConvertedFilePath(runTime, forecastTime)
      if (fs.existsSync(convertedFilePath)) {
        logger.verbose('Already converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
        fs.readJson(convertedFilePath, 'utf8')
        .then(grid => {
          resolve(grid)
        })
        .catch(error => {
          logger.error('Cannot read converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
          debug('Input JSON file was : ' + convertedFilePath)
          reject(error)
        })
        return
      }

      grib2json(filePath, {
        data: true,
        bufferSize: 1024 * 1024 * 1024
      })
      .then(json => {
        if (json.length === 0 || !json[0].data || !json[0].data.length > 0) {
          const errorMessage = 'Converted ' + this.forecast.name + '/' + this.element.name + ' forecast data at ' + forecastTime.format() + ' for run ' + runTime.format() + ' is invalid or empty'
          logger.error(errorMessage)
          debug('Output JSON file was : ' + convertedFilePath)
          reject(errors.Unprocessable(errorMessage))
          return
        } else {
          logger.verbose('Converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
        }
        // Change extension from tiff to json
        fs.outputJson(convertedFilePath, json[0].data, 'utf8')
        .then(_ => {
          logger.verbose('Written ' + this.forecast.name + '/' + this.element.name + ' converted forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
          resolve(json[0].data)
        })
        .catch(error => {
          logger.error('Cannot write converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
          debug('Output JSON file was : ' + convertedFilePath)
          reject(error)
        })
      })
      .catch(error => {
        reject(error)
      })
    })

    return promise
  },

  // Generate file name to store temporary input data with the right format extension
  getForecastTimeFilePath (runTime, forecastTime) {
    return path.join(this.app.get('forecastPath'), this.forecast.name, this.element.name, runTime.format('YYYY-MM-DD[_]HH-mm-ss') + '_' + forecastTime.format('YYYY-MM-DD[_]HH-mm-ss') + '.grib')
  },

  // Build the request options to download given forecast time from input WCS data source
  getForecastTimeRequest (runTime, forecastTime) {
    // Directories are organized by run time
    let subDirectory = '/gfs.' + runTime.format('YYYYMMDDHH')
    // Then we need to target the right file for forecast time
    // Get offset from run time
    let hours = forecastTime.diff(runTime, 'hours')
    // Convert to string with zero padding like 006
    hours = hours.toFixed(0)
    while (hours.length < 3) hours = '0' + hours
    // Get resolution expressed as XpXX
    let resolution = this.forecast.resolution.length > 0 ? this.forecast.resolution[0] : 0.5
    resolution = resolution.toFixed(2).replace('.', 'p')
    // Specific case of 0.5° model
    if (resolution === '0p50') {
      resolution = 'full.' + resolution
    } else {
      resolution = '.' + resolution
    }
    let file = 'gfs.t' + runTime.format('HH') + 'z.pgrb2' + resolution + '.f' + hours
    // Setup request with URL, variable, level parameters for HTTP filter
    let queryParameters = {
      dir: subDirectory,
      file
    }
    if (this.element.variable.startsWith('var_')) {
      queryParameters[this.element.variable] = 'on'
    } else {
      queryParameters['var_' + this.element.variable.toUpperCase()] = 'on'
    }
    if (this.element.levels) {
      this.element.levels.forEach(level => {
        queryParameters[level.startsWith('lev_') ? level : 'lev_' + level] = 'on'
      })
    }
    return {
      url: this.forecast.baseUrl,
      qs: queryParameters
    }
  }
}
<commit_msg>Fixed https://github.com/weacast/weacast-gfs/issues/1<commit_after>import path from 'path'
import fs from 'fs-extra'
import errors from 'feathers-errors'
import grib2json from 'weacast-grib2json'
import logger from 'winston'
import makeDebug from 'debug'
const debug = makeDebug('weacast:weacast-gfs')

export default {

  // Perform conversion from input TIFF to JSON
  convertForecastTime (runTime, forecastTime) {
    let promise = new Promise((resolve, reject) => {
      const filePath = this.getForecastTimeFilePath(runTime, forecastTime)
      const convertedFilePath = this.getForecastTimeConvertedFilePath(runTime, forecastTime)
      if (fs.existsSync(convertedFilePath)) {
        logger.verbose('Already converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
        fs.readJson(convertedFilePath, 'utf8')
        .then(grid => {
          resolve(grid)
        })
        .catch(error => {
          logger.error('Cannot read converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
          debug('Input JSON file was : ' + convertedFilePath)
          reject(error)
        })
        return
      }

      grib2json(filePath, {
        data: true,
        bufferSize: 1024 * 1024 * 1024
      })
      .then(json => {
        if (json.length === 0 || !json[0].data || !json[0].data.length > 0) {
          const errorMessage = 'Converted ' + this.forecast.name + '/' + this.element.name + ' forecast data at ' + forecastTime.format() + ' for run ' + runTime.format() + ' is invalid or empty'
          logger.error(errorMessage)
          debug('Output JSON file was : ' + convertedFilePath)
          reject(new errors.Unprocessable(errorMessage))
          return
        } else {
          logger.verbose('Converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
        }
        // Change extension from tiff to json
        fs.outputJson(convertedFilePath, json[0].data, 'utf8')
        .then(_ => {
          logger.verbose('Written ' + this.forecast.name + '/' + this.element.name + ' converted forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
          resolve(json[0].data)
        })
        .catch(error => {
          logger.error('Cannot write converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
          debug('Output JSON file was : ' + convertedFilePath)
          reject(error)
        })
      })
      .catch(error => {
        reject(error)
      })
    })

    return promise
  },

  // Generate file name to store temporary input data with the right format extension
  getForecastTimeFilePath (runTime, forecastTime) {
    return path.join(this.app.get('forecastPath'), this.forecast.name, this.element.name, runTime.format('YYYY-MM-DD[_]HH-mm-ss') + '_' + forecastTime.format('YYYY-MM-DD[_]HH-mm-ss') + '.grib')
  },

  // Build the request options to download given forecast time from input WCS data source
  getForecastTimeRequest (runTime, forecastTime) {
    // Directories are organized by run time
    let subDirectory = '/gfs.' + runTime.format('YYYYMMDDHH')
    // Then we need to target the right file for forecast time
    // Get offset from run time
    let hours = forecastTime.diff(runTime, 'hours')
    // Convert to string with zero padding like 006
    hours = hours.toFixed(0)
    while (hours.length < 3) hours = '0' + hours
    // Get resolution expressed as XpXX
    let resolution = this.forecast.resolution.length > 0 ? this.forecast.resolution[0] : 0.5
    resolution = resolution.toFixed(2).replace('.', 'p')
    // Specific case of 0.5° model
    if (resolution === '0p50') {
      resolution = 'full.' + resolution
    } else {
      resolution = '.' + resolution
    }
    let file = 'gfs.t' + runTime.format('HH') + 'z.pgrb2' + resolution + '.f' + hours
    // Setup request with URL, variable, level parameters for HTTP filter
    let queryParameters = {
      dir: subDirectory,
      file
    }
    if (this.element.variable.startsWith('var_')) {
      queryParameters[this.element.variable] = 'on'
    } else {
      queryParameters['var_' + this.element.variable.toUpperCase()] = 'on'
    }
    if (this.element.levels) {
      this.element.levels.forEach(level => {
        queryParameters[level.startsWith('lev_') ? level : 'lev_' + level] = 'on'
      })
    }
    return {
      url: this.forecast.baseUrl,
      qs: queryParameters
    }
  }
}
<|endoftext|>


<commit_before>import userDisplayName from './userDisplayName.js'
import initials from './initials.js'

/**
 * Returns two characters to display for a camp collaboration based on its user
 */
export default function (user) {
  return initials(userDisplayName(user))
}
<commit_msg>Fix documentation comment<commit_after>import userDisplayName from './userDisplayName.js'
import initials from './initials.js'

/**
 * Returns two characters to display for a user
 */
export default function (user) {
  return initials(userDisplayName(user))
}
<|endoftext|>


<commit_before>import React from 'react';
import styled from 'styled-components';

const Inner = styled.div`
  padding: 2rem;
`;

const NewPost = styled.section`
  width: 100%;
  margin-top: 30px;
  padding-bottom: 50px;
`;
const Toolbar = styled.div`
  width: 100%;
  height: 50px;
  background-color: #66bb6a;
  color: #fff;
  line-height: 24px;
  vertical-align: middle;
  font-size: 18px;
  font-weight: 600;
  padding-left: 1rem;
  display: flex;
  align-items: center;
`;

export { NewPost, Toolbar, Inner, Wrapper };
<commit_msg>resolves failing test by removing an undefined export<commit_after>import React from 'react';
import styled from 'styled-components';

const Inner = styled.div`
  padding: 2rem;
`;

const NewPost = styled.section`
  width: 100%;
  margin-top: 30px;
  padding-bottom: 50px;
`;
const Toolbar = styled.div`
  width: 100%;
  height: 50px;
  background-color: #66bb6a;
  color: #fff;
  line-height: 24px;
  vertical-align: middle;
  font-size: 18px;
  font-weight: 600;
  padding-left: 1rem;
  display: flex;
  align-items: center;
`;

export { NewPost, Toolbar, Inner };
<|endoftext|>


<commit_before>/**
 * Chris Troutner 4/22/16
 * ConnextCMS.com
 * This plugin allows linking to locally hosted files.
 */

/**
 * Example plugin that adds a toolbar button and menu item.
 */
tinymce.PluginManager.add('file_link', function(editor, url) {

  //Easier to just store the selected filename into a global variable.
  var selectedFileName = '';

  // Add a button that opens a window
	editor.addButton('file_link', {
		icon: 'link',
    tooltip: 'Insert/edit file',
		onclick: createLinkList(showDialog),
    stateSelector: 'a[href]'
	});

  function createLinkList(callback) {
    //debugger;
		return function() {
			var linkList = editor.settings.link_list;

			if (typeof linkList == "string") {
				tinymce.util.XHR.send({
					url: linkList,
					success: function(text) {
						callback(tinymce.util.JSON.parse(text));
					}
				});
			} else if (typeof linkList == "function") {
				linkList(callback);
			} else {
				callback(linkList);
			}
		};
	}

  function buildListItems(inputList, itemCallback, startItems) {
    debugger;
		function appendItems(values, output) {
			output = output || [];

			tinymce.each(values, function(item) {
				var menuItem = {text: item.text || item.title};

				if (item.menu) {
					menuItem.menu = appendItems(item.menu);
				} else {
					menuItem.value = item.value;

					if (itemCallback) {
						itemCallback(menuItem);
					}
				}

				output.push(menuItem);
			});

			return output;
		}

		return appendItems(inputList, startItems || []);
	}

  function showDialog(linkList) {
    debugger;
		var data = {}, selection = editor.selection, dom = editor.dom, selectedElm, anchorElm, initialText;
		var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, fileListCtrl, classListCtrl, linkTitleCtrl, value;

		function linkListChangeHandler(e) {
			var textCtrl = win.find('#text');

			if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) {
				textCtrl.value(e.control.text());
			}

			win.find('#href').value(e.control.value());
		}

		function buildAnchorListControl(url) {
      debugger;
			var anchorList = [];

			tinymce.each(editor.dom.select('a:not([href])'), function(anchor) {
        debugger;
				var id = anchor.name || anchor.id;

				if (id) {
					anchorList.push({
						text: id,
						value: '#' + id,
						selected: url.indexOf('#' + id) != -1
					});
				}
			});

			if (anchorList.length) {
				anchorList.unshift({text: 'None', value: ''});

				return {
					name: 'anchor',
					type: 'listbox',
					label: 'Anchors',
					values: anchorList,
					onselect: linkListChangeHandler
				};
			}
		}

		function updateText() {
      debugger;
			if (!initialText && data.text.length === 0 && onlyText) {
				this.parent().parent().find('#text')[0].value(this.value());
			}
		}

		function urlChange(e) {
			var meta = e.meta || {};

			if (linkListCtrl) {
				linkListCtrl.value(editor.convertURL(this.value(), 'href'));
			}

			tinymce.each(e.meta, function(value, key) {
				win.find('#' + key).value(value);
			});

			if (!meta.text) {
				updateText.call(this);
			}
		}

		function isOnlyTextSelected(anchorElm) {
      debugger;
			var html = selection.getContent();

			// Partial html and not a fully selected anchor element
			if (/</.test(html) && (!/^<a [^>]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') == -1)) {
				return false;
			}

			if (anchorElm) {
				var nodes = anchorElm.childNodes, i;

				if (nodes.length === 0) {
					return false;
				}

				for (i = nodes.length - 1; i >= 0; i--) {
					if (nodes[i].nodeType != 3) {
						return false;
					}
				}
			}

			return true;
		}

		selectedElm = selection.getNode();
		anchorElm = dom.getParent(selectedElm, 'a[href]');
		onlyText = isOnlyTextSelected();

		data.text = initialText = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({format: 'text'});
		data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : '';

		if (anchorElm) {
			data.target = dom.getAttrib(anchorElm, 'target');
		} else if (editor.settings.default_link_target) {
			data.target = editor.settings.default_link_target;
		}

		if ((value = dom.getAttrib(anchorElm, 'rel'))) {
			data.rel = value;
		}

		if ((value = dom.getAttrib(anchorElm, 'class'))) {
			data['class'] = value;
		}

		if ((value = dom.getAttrib(anchorElm, 'title'))) {
			data.title = value;
		}

		if (onlyText) {
			textListCtrl = {
				name: 'text',
				type: 'textbox',
				size: 40,
				label: 'Text to display',
				onchange: function() {
					data.text = this.value();
				}
			};
		}

		if (linkList) {
			linkListCtrl = {
				type: 'listbox',
				label: 'Link list',
				values: buildListItems(
					linkList,
					function(item) {
						item.value = editor.convertURL(item.value || item.url, 'href');
					},
					[{text: 'None', value: ''}]
				),
				onselect: linkListChangeHandler,
				value: editor.convertURL(data.href, 'href'),
				onPostRender: function() {
					/*eslint consistent-this:0*/
					linkListCtrl = this;
				}
			};
		}

		if (editor.settings.target_list !== false) {
			if (!editor.settings.target_list) {
				editor.settings.target_list = [
					{text: 'None', value: ''},
					{text: 'New window', value: '_blank'}
				];
			}

			targetListCtrl = {
				name: 'target',
				type: 'listbox',
				label: 'Target',
				values: buildListItems(editor.settings.target_list)
			};
		}

    //CT
    //Create the drop-down list of files in CMS
    if (editor.settings.file_list !== false) {
			if (!editor.settings.file_list) {
        debugger;

        editor.settings.file_list = [];
        for( var i=0; i < global.fileUploadCollection.length; i++ ) {
          editor.settings.file_list.push(
            //{text: global.fileUploadCollection.models[i].get('fileName'), value: global.fileUploadCollection.models[i].get('url')}
            {text: global.fileUploadCollection.models[i].get('fileName'), value: i}
          );
        }

				//editor.settings.file_list = [
				//	{text: 'None', value: ''},
				//	{text: 'New window', value: '_blank'}
				//];
			}

			fileListCtrl = {
				name: 'file',
				type: 'listbox',
				label: 'File',
				values: buildListItems(editor.settings.file_list)
			};
		}

		if (editor.settings.rel_list) {
			relListCtrl = {
				name: 'rel',
				type: 'listbox',
				label: 'Rel',
				values: buildListItems(editor.settings.rel_list)
			};
		}

		if (editor.settings.link_class_list) {
			classListCtrl = {
				name: 'class',
				type: 'listbox',
				label: 'Class',
				values: buildListItems(
					editor.settings.link_class_list,
					function(item) {
						if (item.value) {
							item.textStyle = function() {
								return editor.formatter.getCssText({inline: 'a', classes: [item.value]});
							};
						}
					}
				)
			};
		}

		if (editor.settings.link_title !== false) {
			linkTitleCtrl = {
				name: 'title',
				type: 'textbox',
				label: 'Title',
				value: data.title
			};
		}

		win = editor.windowManager.open({
			title: 'Insert link',
			data: data,
			body: [
				fileListCtrl,
        /*
        {
					name: 'href',
					type: 'filepicker',
					filetype: 'file',
					size: 40,
					autofocus: true,
					label: 'Url',
					onchange: urlChange,
					//onkeyup: updateText
				},
        */
				textListCtrl,
				linkTitleCtrl,
				buildAnchorListControl(data.href),
				linkListCtrl,
				relListCtrl,
				targetListCtrl,
				classListCtrl
			],
			onSubmit: function(e) {
        debugger;
				/*eslint dot-notation: 0*/
				var href;

				data = tinymce.extend(data, e.data);
				//href = data.href;
        href = global.fileUploadCollection.models[data.file].get('url');

				// Delay confirm since onSubmit will move focus
				function delayedConfirm(message, callback) {
					var rng = editor.selection.getRng();

					tinymce.util.Delay.setEditorTimeout(editor, function() {
						editor.windowManager.confirm(message, function(state) {
							editor.selection.setRng(rng);
							callback(state);
						});
					});
				}

				function insertLink() {
          debugger;
					var linkAttrs = {
						href: href,
						target: data.target ? data.target : null,
						rel: data.rel ? data.rel : null,
						"class": data["class"] ? data["class"] : null,
						title: data.title ? data.title : null,
            download: global.fileUploadCollection.models[data.file].get('fileName')
					};

					if (anchorElm) {
						editor.focus();

						if (onlyText && data.text != initialText) {
							if ("innerText" in anchorElm) {
								anchorElm.innerText = data.text;
							} else {
								anchorElm.textContent = data.text;
							}
						}

						dom.setAttribs(anchorElm, linkAttrs);

						selection.select(anchorElm);
						editor.undoManager.add();
					} else {
						if (onlyText) {
							editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(data.text)));
						} else {
							editor.execCommand('mceInsertLink', false, linkAttrs);
						}
					}
				}

				if (!href) {
					editor.execCommand('unlink');
					return;
				}

				// Is email and not //user@domain.com
				if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) {
					delayedConfirm(
						'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
						function(state) {
							if (state) {
								href = 'mailto:' + href;
							}

							insertLink();
						}
					);

					return;
				}

				// Is not protocol prefixed
				if ((editor.settings.link_assume_external_targets && !/^\w+:/i.test(href)) ||
					(!editor.settings.link_assume_external_targets && /^\s*www[\.|\d\.]/i.test(href))) {
					delayedConfirm(
						'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
						function(state) {
							if (state) {
								href = 'http://' + href;
							}

							insertLink();
						}
					);

					return;
				}

				insertLink();
			}
		});
	}

});<commit_msg>adding file extension to file name during upload.<commit_after>/**
 * Chris Troutner 4/22/16
 * ConnextCMS.com
 * This plugin allows linking to locally hosted files.
 */

/**
 * Example plugin that adds a toolbar button and menu item.
 */
tinymce.PluginManager.add('file_link', function(editor, url) {

  //Easier to just store the selected filename into a global variable.
  var selectedFileName = '';

  // Add a button that opens a window
	editor.addButton('file_link', {
		icon: 'link',
    tooltip: 'Insert/edit file',
		onclick: createLinkList(showDialog),
    stateSelector: 'a[href]'
	});

  function createLinkList(callback) {
    //debugger;
		return function() {
			var linkList = editor.settings.link_list;

			if (typeof linkList == "string") {
				tinymce.util.XHR.send({
					url: linkList,
					success: function(text) {
						callback(tinymce.util.JSON.parse(text));
					}
				});
			} else if (typeof linkList == "function") {
				linkList(callback);
			} else {
				callback(linkList);
			}
		};
	}

  function buildListItems(inputList, itemCallback, startItems) {
    //debugger;
		function appendItems(values, output) {
			output = output || [];

			tinymce.each(values, function(item) {
				var menuItem = {text: item.text || item.title};

				if (item.menu) {
					menuItem.menu = appendItems(item.menu);
				} else {
					menuItem.value = item.value;

					if (itemCallback) {
						itemCallback(menuItem);
					}
				}

				output.push(menuItem);
			});

			return output;
		}

		return appendItems(inputList, startItems || []);
	}

  function showDialog(linkList) {
    //debugger;
		var data = {}, selection = editor.selection, dom = editor.dom, selectedElm, anchorElm, initialText;
		var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, fileListCtrl, classListCtrl, linkTitleCtrl, value;

		function linkListChangeHandler(e) {
			var textCtrl = win.find('#text');

			if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) {
				textCtrl.value(e.control.text());
			}

			win.find('#href').value(e.control.value());
		}

		function buildAnchorListControl(url) {
      //debugger;
			var anchorList = [];

			tinymce.each(editor.dom.select('a:not([href])'), function(anchor) {
        //debugger;
				var id = anchor.name || anchor.id;

				if (id) {
					anchorList.push({
						text: id,
						value: '#' + id,
						selected: url.indexOf('#' + id) != -1
					});
				}
			});

			if (anchorList.length) {
				anchorList.unshift({text: 'None', value: ''});

				return {
					name: 'anchor',
					type: 'listbox',
					label: 'Anchors',
					values: anchorList,
					onselect: linkListChangeHandler
				};
			}
		}

		function updateText() {
      //debugger;
			if (!initialText && data.text.length === 0 && onlyText) {
				this.parent().parent().find('#text')[0].value(this.value());
			}
		}

		function urlChange(e) {
			var meta = e.meta || {};

			if (linkListCtrl) {
				linkListCtrl.value(editor.convertURL(this.value(), 'href'));
			}

			tinymce.each(e.meta, function(value, key) {
				win.find('#' + key).value(value);
			});

			if (!meta.text) {
				updateText.call(this);
			}
		}

		function isOnlyTextSelected(anchorElm) {
      //debugger;
			var html = selection.getContent();

			// Partial html and not a fully selected anchor element
			if (/</.test(html) && (!/^<a [^>]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') == -1)) {
				return false;
			}

			if (anchorElm) {
				var nodes = anchorElm.childNodes, i;

				if (nodes.length === 0) {
					return false;
				}

				for (i = nodes.length - 1; i >= 0; i--) {
					if (nodes[i].nodeType != 3) {
						return false;
					}
				}
			}

			return true;
		}

		selectedElm = selection.getNode();
		anchorElm = dom.getParent(selectedElm, 'a[href]');
		onlyText = isOnlyTextSelected();

		data.text = initialText = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({format: 'text'});
		data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : '';

		if (anchorElm) {
			data.target = dom.getAttrib(anchorElm, 'target');
		} else if (editor.settings.default_link_target) {
			data.target = editor.settings.default_link_target;
		}

		if ((value = dom.getAttrib(anchorElm, 'rel'))) {
			data.rel = value;
		}

		if ((value = dom.getAttrib(anchorElm, 'class'))) {
			data['class'] = value;
		}

		if ((value = dom.getAttrib(anchorElm, 'title'))) {
			data.title = value;
		}

		if (onlyText) {
			textListCtrl = {
				name: 'text',
				type: 'textbox',
				size: 40,
				label: 'Text to display',
				onchange: function() {
					data.text = this.value();
				}
			};
		}

		if (linkList) {
			linkListCtrl = {
				type: 'listbox',
				label: 'Link list',
				values: buildListItems(
					linkList,
					function(item) {
						item.value = editor.convertURL(item.value || item.url, 'href');
					},
					[{text: 'None', value: ''}]
				),
				onselect: linkListChangeHandler,
				value: editor.convertURL(data.href, 'href'),
				onPostRender: function() {
					/*eslint consistent-this:0*/
					linkListCtrl = this;
				}
			};
		}

		if (editor.settings.target_list !== false) {
			if (!editor.settings.target_list) {
				editor.settings.target_list = [
					{text: 'None', value: ''},
					{text: 'New window', value: '_blank'}
				];
			}

			targetListCtrl = {
				name: 'target',
				type: 'listbox',
				label: 'Target',
				values: buildListItems(editor.settings.target_list)
			};
		}

    //CT
    //Create the drop-down list of files in CMS
    if (editor.settings.file_list !== false) {
			if (!editor.settings.file_list) {
        //debugger;

        editor.settings.file_list = [];
        for( var i=0; i < global.fileUploadCollection.length; i++ ) {
          editor.settings.file_list.push(
            //{text: global.fileUploadCollection.models[i].get('fileName'), value: global.fileUploadCollection.models[i].get('url')}
            {text: global.fileUploadCollection.models[i].get('fileName'), value: i}
          );
        }

				//editor.settings.file_list = [
				//	{text: 'None', value: ''},
				//	{text: 'New window', value: '_blank'}
				//];
			}

			fileListCtrl = {
				name: 'file',
				type: 'listbox',
				label: 'File',
				values: buildListItems(editor.settings.file_list)
			};
		}

		if (editor.settings.rel_list) {
			relListCtrl = {
				name: 'rel',
				type: 'listbox',
				label: 'Rel',
				values: buildListItems(editor.settings.rel_list)
			};
		}

		if (editor.settings.link_class_list) {
			classListCtrl = {
				name: 'class',
				type: 'listbox',
				label: 'Class',
				values: buildListItems(
					editor.settings.link_class_list,
					function(item) {
						if (item.value) {
							item.textStyle = function() {
								return editor.formatter.getCssText({inline: 'a', classes: [item.value]});
							};
						}
					}
				)
			};
		}

		if (editor.settings.link_title !== false) {
			linkTitleCtrl = {
				name: 'title',
				type: 'textbox',
				label: 'Title',
				value: data.title
			};
		}

		win = editor.windowManager.open({
			title: 'Insert link',
			data: data,
			body: [
				fileListCtrl,
        /*
        {
					name: 'href',
					type: 'filepicker',
					filetype: 'file',
					size: 40,
					autofocus: true,
					label: 'Url',
					onchange: urlChange,
					//onkeyup: updateText
				},
        */
				textListCtrl,
				linkTitleCtrl,
				buildAnchorListControl(data.href),
				linkListCtrl,
				relListCtrl,
				targetListCtrl,
				classListCtrl
			],
			onSubmit: function(e) {
        //debugger;
				/*eslint dot-notation: 0*/
				var href;

				data = tinymce.extend(data, e.data);
				//href = data.href;
        href = global.fileUploadCollection.models[data.file].get('url');

				// Delay confirm since onSubmit will move focus
				function delayedConfirm(message, callback) {
					var rng = editor.selection.getRng();

					tinymce.util.Delay.setEditorTimeout(editor, function() {
						editor.windowManager.confirm(message, function(state) {
							editor.selection.setRng(rng);
							callback(state);
						});
					});
				}

				function insertLink() {
          //debugger;
					var linkAttrs = {
						href: href,
						target: data.target ? data.target : null,
						rel: data.rel ? data.rel : null,
						"class": data["class"] ? data["class"] : null,
						title: data.title ? data.title : null,
            download: global.fileUploadCollection.models[data.file].get('fileName')
					};

					if (anchorElm) {
						editor.focus();

						if (onlyText && data.text != initialText) {
							if ("innerText" in anchorElm) {
								anchorElm.innerText = data.text;
							} else {
								anchorElm.textContent = data.text;
							}
						}

						dom.setAttribs(anchorElm, linkAttrs);

						selection.select(anchorElm);
						editor.undoManager.add();
					} else {
						if (onlyText) {
							editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(data.text)));
						} else {
							editor.execCommand('mceInsertLink', false, linkAttrs);
						}
					}
				}

				if (!href) {
					editor.execCommand('unlink');
					return;
				}

				// Is email and not //user@domain.com
				if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) {
					delayedConfirm(
						'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
						function(state) {
							if (state) {
								href = 'mailto:' + href;
							}

							insertLink();
						}
					);

					return;
				}

				// Is not protocol prefixed
				if ((editor.settings.link_assume_external_targets && !/^\w+:/i.test(href)) ||
					(!editor.settings.link_assume_external_targets && /^\s*www[\.|\d\.]/i.test(href))) {
					delayedConfirm(
						'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
						function(state) {
							if (state) {
								href = 'http://' + href;
							}

							insertLink();
						}
					);

					return;
				}

				insertLink();
			}
		});
	}

});<|endoftext|>