<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import {on, position, closest, width, height, isFunction,
        outerWidthWithMargin, outerHeightWithMargin} from './utils';

function handleSortableItemReadyToMove(e) {
  const target = closest((e.target || e.srcElement), '.ui-sortable-item');
  const evt = {
    pageX: (e.pageX || e.clientX || e.touches[0].pageX),
    pageY: (e.pageY || e.clientY || e.touches[0].pageY),
    offset: position(target)
  };

  if (this.props.onSortableItemReadyToMove) {
    this.props.onSortableItemReadyToMove(evt, this.props.sortableIndex);
  }
}

function handleComponentDidMount() {
  const node = ReactDOM.findDOMNode(this);

  on(node, 'selectstart', (e) => {
    if (e.preventDefault) {
      e.preventDefault();
    }
    else {
      e.returnValue = false;
    }
  });

  if (isFunction(this.props.onSortableItemMount)) {
    this.props.onSortableItemMount(position(node),
                                   width(node),
                                   height(node),
                                   outerWidthWithMargin(node),
                                   outerHeightWithMargin(node),
                                   this.props.sortableIndex);
  }
}

function handleComponentDidUpdate() {
  const node = ReactDOM.findDOMNode(this);

  if (isFunction(this.props.onSortableItemMount)) {
    this.props.onSortableItemMount(position(node),
                                   width(node),
                                   height(node),
                                   outerWidthWithMargin(node),
                                   outerHeightWithMargin(node),
                                   this.props.sortableIndex);
  }
}

const _defaultProps = {
  sortableClassName: '',
  sortableStyle: {},
  onSortableItemMount: () => {},
  onSortableItemReadyToMove: () => {}
};

/**
 * @class A factory for generating either mixin or High Order Component
 *        depending if there is a argument passed in
 *
 * @param {React} Component An optinal argument for creating HOCs, leave it
 *                blank if you'd like old mixin
 */
export default (Component) => {
  if (Component) {
    return class SortableItem extends React.Component {
      static defaultProps = _defaultProps;

      handleSortableItemReadyToMove(e) {
        handleSortableItemReadyToMove.call(this, e);
      }

      componentDidMount() {
        handleComponentDidMount.call(this);
      }

      componentDidUpdate() {
        handleComponentDidUpdate.call(this);
      }

      render() {
        const { sortableClassName, sortableStyle, sortableIndex, ...rest } = this.props;
        return (
          <Component {...rest} className={sortableClassName} style={sortableStyle} key={sortableIndex}
                     onMouseDown={::this.handleSortableItemReadyToMove}
                     onTouchStart={::this.handleSortableItemReadyToMove} />
        );
      }
    }
  }

  return {
    getDefaultProps() {
      return _defaultProps;
    },

    handleSortableItemReadyToMove: handleSortableItemReadyToMove,

    componentDidMount: handleComponentDidMount,

    componentDidUpdate: handleComponentDidUpdate,

    renderWithSortable(item) {
      return React.cloneElement(item, {
        className: this.props.sortableClassName,
        style: this.props.sortableStyle,
        key: this.props.sortableIndex,
        onMouseDown: this.handleSortableItemReadyToMove,
        onTouchStart: this.handleSortableItemReadyToMove
      });
    }
  }
};
<commit_msg>fix: a proper merge for sortable item classname<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import {on, position, closest, width, height, isFunction,
        outerWidthWithMargin, outerHeightWithMargin} from './utils';

function handleSortableItemReadyToMove(e) {
  const target = closest((e.target || e.srcElement), '.ui-sortable-item');
  const evt = {
    pageX: (e.pageX || e.clientX || e.touches[0].pageX),
    pageY: (e.pageY || e.clientY || e.touches[0].pageY),
    offset: position(target)
  };

  if (this.props.onSortableItemReadyToMove) {
    this.props.onSortableItemReadyToMove(evt, this.props.sortableIndex);
  }
}

function handleComponentDidMount() {
  const node = ReactDOM.findDOMNode(this);

  on(node, 'selectstart', (e) => {
    if (e.preventDefault) {
      e.preventDefault();
    }
    else {
      e.returnValue = false;
    }
  });

  if (isFunction(this.props.onSortableItemMount)) {
    this.props.onSortableItemMount(position(node),
                                   width(node),
                                   height(node),
                                   outerWidthWithMargin(node),
                                   outerHeightWithMargin(node),
                                   this.props.sortableIndex);
  }
}

function handleComponentDidUpdate() {
  const node = ReactDOM.findDOMNode(this);

  if (isFunction(this.props.onSortableItemMount)) {
    this.props.onSortableItemMount(position(node),
                                   width(node),
                                   height(node),
                                   outerWidthWithMargin(node),
                                   outerHeightWithMargin(node),
                                   this.props.sortableIndex);
  }
}

const _defaultProps = {
  sortableClassName: '',
  sortableStyle: {},
  onSortableItemMount: () => {},
  onSortableItemReadyToMove: () => {}
};

/**
 * @class A factory for generating either mixin or High Order Component
 *        depending if there is a argument passed in
 *
 * @param {React} Component An optinal argument for creating HOCs, leave it
 *                blank if you'd like old mixin
 */
export default (Component) => {
  if (Component) {
    return class SortableItem extends React.Component {
      static defaultProps = _defaultProps;

      handleSortableItemReadyToMove(e) {
        handleSortableItemReadyToMove.call(this, e);
      }

      componentDidMount() {
        handleComponentDidMount.call(this);
      }

      componentDidUpdate() {
        handleComponentDidUpdate.call(this);
      }

      render() {
        const { sortableClassName, sortableStyle, sortableIndex, ...rest } = this.props;
        return (
          <Component {...rest} className={sortableClassName} style={sortableStyle} key={sortableIndex}
                     onMouseDown={::this.handleSortableItemReadyToMove}
                     onTouchStart={::this.handleSortableItemReadyToMove} />
        );
      }
    }
  }

  return {
    getDefaultProps() {
      return _defaultProps;
    },

    handleSortableItemReadyToMove: handleSortableItemReadyToMove,

    componentDidMount: handleComponentDidMount,

    componentDidUpdate: handleComponentDidUpdate,

    renderWithSortable(item) {
      return React.cloneElement(item, {
        className: this.props.sortableClassName + ' ' + item.props.className,
        style: this.props.sortableStyle,
        key: this.props.sortableIndex,
        onMouseDown: this.handleSortableItemReadyToMove,
        onTouchStart: this.handleSortableItemReadyToMove
      });
    }
  }
};
<|endoftext|>


<commit_before>
var elasticsearchSqlApp = angular.module('elasticsearchSqlApp', ["ngAnimate", "ngSanitize"]);

elasticsearchSqlApp.controller('MainController', function ($scope, $http, $sce,$compile) {
	scroll_url = "_search/scroll?scroll=1m&scroll_id=";
	$scope.url = getUrl();
	$scope.showResults = false;
	$scope.error = "";
	$scope.resultsColumns =[];
	$scope.resultsRows = [];
	$scope.searchLoading = false;
	$scope.explainLoading = false;
	$scope.nextLoading = false;
	$scope.resultExplan = false;
	$scope.scrollId = undefined;
  $scope.amountDescription = "";
  var fetched = 0;
  var total = 0 ;
  //checkboxes
	$scope.gotNext = false;
  $scope.useOldTable = false;
	$scope.delimiter = ',';

  var tablePresenter = new TablePresenter('searchResult','#searchResultZone');

 	// pull version and put it on the scope
    $http.get($scope.url).success(function (data) {
        $http.get($scope.url + "_nodes/" + data.name).success(function (nodeData) {
            var node = nodeData.nodes[Object.keys(nodeData.nodes)[0]];
            angular.forEach(node.plugins, function (plugin) {
                if (plugin.name === "sql") {
                    $scope.version = plugin.version;
                }
            });
        });
    });

	$scope.nextSearch = function(){
		$scope.error = "";
		$scope.nextLoading = true;
		$scope.$apply();
    var needToBuildTable = false;

		if($scope.scrollId == undefined || $scope.scrollId == "" ){
			$scope.error = "tryed scrolling with empty scrollId";
			return;
		}

		$http.get($scope.url + scroll_url + $scope.scrollId)
		.success(function(data, status, headers, config) {
          var handler = ResultHandlerFactory.create(data,$scope.isFlat);
          updateDescription(handler);
          var body = handler.getBody()

          if(body.length == undefined || body.length == 0){
          	$scope.gotNext=false;
          }
          else
          {
          	  $scope.scrollId = handler.getScrollId();
          }

          if($scope.resultsRows.length > 0){
            tablePresenter.addRows(handler.getBody());
          	$scope.resultsRows = $scope.resultsRows.concat(handler.getBody());
          }
          else {
          	$scope.resultsColumns = handler.getHead();
            $scope.resultsRows = handler.getBody();
            needToBuildTable = true;
          }

        })
        .error(function(data, status, headers, config) {
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
    	  }
    	  else {
    	  	$scope.error = JSON.stringify(data);
    	  	$scope.scrollId = undefined;
		  }
        })
        .finally(function() {
          $scope.nextLoading = false;
          $scope.$apply();
          if(needToBuildTable) {
            tablePresenter.createOrReplace($scope.resultsColumns,$scope.resultsRows);
          }

        });

	}

	$scope.search = function() {
		// Reset results and error box
		$scope.error = "";
		fetched = 0;
		total = 0;
		$scope.amountDescription = 0;
		$scope.resultsColumns = [];
		$scope.resultsRows = [];
		$scope.searchLoading = true;

		$scope.resultExplan = false;
    $scope.$apply();
		saveUrl()

    var query = window.editor.getValue();

		$http.post($scope.url + "_sql", query)
		.success(function(data, status, headers, config) {
          var handler = ResultHandlerFactory.create(data,$scope.isFlat);
          updateDescription(handler);
          if(handler.isScroll){

          	$scope.scrollId = handler.getScrollId();
          	if($scope.isAutoSave){
          		searchTillEndAndExportCsv($scope.scrollId);
          	}
          	else {
          		$scope.gotNext=true;
          	}
          }

          else {

          	if($scope.isAutoSave){
                $scope.showResults=true;
          		exportCSVWithoutScope(handler.getHead(),handler.getBody());
          	}
            else {
                $scope.resultsColumns = handler.getHead();
                $scope.resultsRows = handler.getBody();

            }
          }
        })
        .error(function(data, status, headers, config) {
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
    	  }
    	  else {
    	  	$scope.error = JSON.stringify(data);
		  }
        })
        .finally(function() {
          $scope.searchLoading = false;
          $scope.$apply();
          if($scope.resultsColumns.length >0){
            tablePresenter.createOrReplace($scope.resultsColumns,$scope.resultsRows);
          }

        });
	}

	$scope.explain = function() {
		// Reset results and error box
		$scope.error = "";
		$scope.resultsColumns = [];
		$scope.resultsRows = [];
		$scope.explainLoading = true;
		$scope.$apply();
		$scope.resultExplan = true;

		saveUrl()

        var query = window.editor.getValue();
		$http.post($scope.url + "_sql/_explain", query)
		.success(function(data, status, headers, config) {
					 $scope.resultExplan = true;
				   window.explanResult.setValue(JSON.stringify(data, null, "\t"));
        })
        .error(function(data, status, headers, config) {
        	$scope.resultExplan = false;
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
    	  }
    	  else {
    	  	$scope.error = JSON.stringify(data);
		  }
        })
        .finally(function() {
          $scope.explainLoading = false;
          $scope.$apply()
        });
	}

	 function exportCSVWithoutScope(columns,rows) {
		var delimiter = $scope.delimiter;
		var data =arr2csvStr(columns,delimiter) ;
		for(var i=0; i<rows.length ; i++){
		data += "\n";
			data += map2csvStr(columns,rows[i],delimiter) ;
		}
		var plain = 'data:text/csv;charset=utf8,' + encodeURIComponent(data);
		download(plain, "query_result.csv", "text/plain");
  		return true;
	}

      $scope.onChangeTablePresnterType = function(){
      //value = ?
      value = $scope.useOldTable;
      tablePresenter.destroy();
      tablePresenter.changeTableType(value,$compile,$scope);
    }

    function searchTillEndAndExportCsv (scrollId) {
      //todo: get total amount show fetched/total
      head = []
      body = []
      $scope.showResults = true;
      callScrollAndFillBodyTillEnd(scrollId,head,body,true);
    }
    function updateDescription (handler) {
        total = handler.getTotal();
        fetched += handler.getCurrentHitsSize();
        if(total == undefined){
          $scope.amountDescription = fetched
        }
        else {
          $scope.amountDescription = fetched + "/" + total
        }
    }
    function callScrollAndFillBodyTillEnd (scrollId,head,body,firstTime) {
    var url = $scope.url + scroll_url + scrollId;
      $http.get(url)
    .success(function(data, status, headers, config) {

          var handler = ResultHandlerFactory.create(data,$scope.isFlat);

            updateDescription(handler);
           recieved = handler.getBody()
          if(body.length > 0){
            body = body.concat(recieved);
            //todo: extend head?
            head = handler.getHead();
          }
          else {
            body = recieved;
            head = handler.getHead();

          }
          if(recieved == undefined || recieved.length == undefined || recieved.length == 0){
            if(firstTime){
             callScrollAndFillBodyTillEnd(handler.getScrollId(),head,body,false);
            }
            else {
              exportCSVWithoutScope(head,body);
            }
          }
          else {
            callScrollAndFillBodyTillEnd(handler.getScrollId(),head,body,false);
          }

        })
        .error(function(data, status, headers, config) {
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
        }
        else {
          $scope.error = JSON.stringify(data);
          $scope.scrollId = undefined;
      }
        })
        .finally(function() {
          $scope.nextLoading = false;
          $scope.$apply()
        });

      // body...
    }

	$scope.exportCSV = function() {
		var columns = $scope.resultsColumns ;
		var rows = $scope.resultsRows ;
		exportCSVWithoutScope(columns,rows);
	}

	$scope.getButtonContent = function(isLoading , defName) {
		var loadingContent = " Loading...";
		var returnValue = isLoading ? loadingContent : defName;
		return $sce.trustAsHtml(returnValue);
	}

	function arr2csvStr(arr,op){
		var data = arr[0];
		for(var i=1; i<arr.length ; i++){
				data += op;
				data += arr[i] ;
		}
		return data ;
	}

	function map2csvStr(columns,arr,op){
		var data = JSON.stringify(arr[columns[0]]);
		for(var i=1; i<columns.length ; i++){
				data += op;
				data += JSON.stringify(arr[columns[i]]) ;
		}
		return data ;
	}

	function getUrl() {
		var url = localStorage.getItem("lasturl");
		if(url == undefined) {
			if(location.protocol == "file") {
				url = "http://localhost:9200"
			}
			else {
				url = location.protocol+'//' + location.hostname + (location.port ? ':'+location.port : '');
			}
		}

		if(url.substr(url.length - 1, 1) != '/') {
			url += '/'
		}

		return url
	}

	function saveUrl() {
		localStorage.setItem("lasturl", $scope.url);
	}
});<commit_msg>Site - extend header on autosave+scroll<commit_after>
var elasticsearchSqlApp = angular.module('elasticsearchSqlApp', ["ngAnimate", "ngSanitize"]);

elasticsearchSqlApp.controller('MainController', function ($scope, $http, $sce,$compile) {
	scroll_url = "_search/scroll?scroll=1m&scroll_id=";
	$scope.url = getUrl();
	$scope.showResults = false;
	$scope.error = "";
	$scope.resultsColumns =[];
	$scope.resultsRows = [];
	$scope.searchLoading = false;
	$scope.explainLoading = false;
	$scope.nextLoading = false;
	$scope.resultExplan = false;
	$scope.scrollId = undefined;
  $scope.amountDescription = "";
  var fetched = 0;
  var total = 0 ;
  //checkboxes
	$scope.gotNext = false;
  $scope.useOldTable = false;
	$scope.delimiter = ',';

  var tablePresenter = new TablePresenter('searchResult','#searchResultZone');

 	// pull version and put it on the scope
    $http.get($scope.url).success(function (data) {
        $http.get($scope.url + "_nodes/" + data.name).success(function (nodeData) {
            var node = nodeData.nodes[Object.keys(nodeData.nodes)[0]];
            angular.forEach(node.plugins, function (plugin) {
                if (plugin.name === "sql") {
                    $scope.version = plugin.version;
                }
            });
        });
    });

	$scope.nextSearch = function(){
		$scope.error = "";
		$scope.nextLoading = true;
		$scope.$apply();
    var needToBuildTable = false;

		if($scope.scrollId == undefined || $scope.scrollId == "" ){
			$scope.error = "tryed scrolling with empty scrollId";
			return;
		}

		$http.get($scope.url + scroll_url + $scope.scrollId)
		.success(function(data, status, headers, config) {
          var handler = ResultHandlerFactory.create(data,$scope.isFlat);
          updateDescription(handler);
          var body = handler.getBody()

          if(body.length == undefined || body.length == 0){
          	$scope.gotNext=false;
          }
          else
          {
          	  $scope.scrollId = handler.getScrollId();
          }

          if($scope.resultsRows.length > 0){
            tablePresenter.addRows(handler.getBody());
          	$scope.resultsRows = $scope.resultsRows.concat(handler.getBody());
          }
          else {
          	$scope.resultsColumns = handler.getHead();
            $scope.resultsRows = handler.getBody();
            needToBuildTable = true;
          }

        })
        .error(function(data, status, headers, config) {
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
    	  }
    	  else {
    	  	$scope.error = JSON.stringify(data);
    	  	$scope.scrollId = undefined;
		  }
        })
        .finally(function() {
          $scope.nextLoading = false;
          $scope.$apply();
          if(needToBuildTable) {
            tablePresenter.createOrReplace($scope.resultsColumns,$scope.resultsRows);
          }

        });

	}

	$scope.search = function() {
		// Reset results and error box
		$scope.error = "";
		fetched = 0;
		total = 0;
		$scope.amountDescription = 0;
		$scope.resultsColumns = [];
		$scope.resultsRows = [];
		$scope.searchLoading = true;

		$scope.resultExplan = false;
    $scope.$apply();
		saveUrl()

    var query = window.editor.getValue();

		$http.post($scope.url + "_sql", query)
		.success(function(data, status, headers, config) {
          var handler = ResultHandlerFactory.create(data,$scope.isFlat);
          updateDescription(handler);
          if(handler.isScroll){

          	$scope.scrollId = handler.getScrollId();
          	if($scope.isAutoSave){
          		searchTillEndAndExportCsv($scope.scrollId);
          	}
          	else {
          		$scope.gotNext=true;
          	}
          }

          else {

          	if($scope.isAutoSave){
                $scope.showResults=true;
          		exportCSVWithoutScope(handler.getHead(),handler.getBody());
          	}
            else {
                $scope.resultsColumns = handler.getHead();
                $scope.resultsRows = handler.getBody();

            }
          }
        })
        .error(function(data, status, headers, config) {
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
    	  }
    	  else {
    	  	$scope.error = JSON.stringify(data);
		  }
        })
        .finally(function() {
          $scope.searchLoading = false;
          $scope.$apply();
          if($scope.resultsColumns.length >0){
            tablePresenter.createOrReplace($scope.resultsColumns,$scope.resultsRows);
          }

        });
	}

	$scope.explain = function() {
		// Reset results and error box
		$scope.error = "";
		$scope.resultsColumns = [];
		$scope.resultsRows = [];
		$scope.explainLoading = true;
		$scope.$apply();
		$scope.resultExplan = true;

		saveUrl()

        var query = window.editor.getValue();
		$http.post($scope.url + "_sql/_explain", query)
		.success(function(data, status, headers, config) {
					 $scope.resultExplan = true;
				   window.explanResult.setValue(JSON.stringify(data, null, "\t"));
        })
        .error(function(data, status, headers, config) {
        	$scope.resultExplan = false;
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
    	  }
    	  else {
    	  	$scope.error = JSON.stringify(data);
		  }
        })
        .finally(function() {
          $scope.explainLoading = false;
          $scope.$apply()
        });
	}

	 function exportCSVWithoutScope(columns,rows) {
		var delimiter = $scope.delimiter;
		var data =arr2csvStr(columns,delimiter) ;
		for(var i=0; i<rows.length ; i++){
		data += "\n";
			data += map2csvStr(columns,rows[i],delimiter) ;
		}
		var plain = 'data:text/csv;charset=utf8,' + encodeURIComponent(data);
		download(plain, "query_result.csv", "text/plain");
  		return true;
	}

      $scope.onChangeTablePresnterType = function(){
      //value = ?
      value = $scope.useOldTable;
      tablePresenter.destroy();
      tablePresenter.changeTableType(value,$compile,$scope);
    }

    function searchTillEndAndExportCsv (scrollId) {
      //todo: get total amount show fetched/total
      head = []
      body = []
      $scope.showResults = true;
      callScrollAndFillBodyTillEnd(scrollId,head,body,true);
    }
    function updateDescription (handler) {
        total = handler.getTotal();
        fetched += handler.getCurrentHitsSize();
        if(total == undefined){
          $scope.amountDescription = fetched
        }
        else {
          $scope.amountDescription = fetched + "/" + total
        }
    }
    function callScrollAndFillBodyTillEnd (scrollId,head,body,firstTime) {
    var url = $scope.url + scroll_url + scrollId;
      $http.get(url)
    .success(function(data, status, headers, config) {

          var handler = ResultHandlerFactory.create(data,$scope.isFlat);

            updateDescription(handler);
           recieved = handler.getBody()
          if(body.length > 0){
            body = body.concat(recieved);

            head = $.extend(head,handler.getHead());
          }
          else {
            body = recieved;
            head = handler.getHead();

          }
          if(recieved == undefined || recieved.length == undefined || recieved.length == 0){
            if(firstTime){
             callScrollAndFillBodyTillEnd(handler.getScrollId(),head,body,false);
            }
            else {
              exportCSVWithoutScope(head,body);
            }
          }
          else {
            callScrollAndFillBodyTillEnd(handler.getScrollId(),head,body,false);
          }

        })
        .error(function(data, status, headers, config) {
          if(data == "") {
            $scope.error = "Error occured! response is not avalible.";
        }
        else {
          $scope.error = JSON.stringify(data);
          $scope.scrollId = undefined;
      }
        })
        .finally(function() {
          $scope.nextLoading = false;
          $scope.$apply()
        });

      // body...
    }

	$scope.exportCSV = function() {
		var columns = $scope.resultsColumns ;
		var rows = $scope.resultsRows ;
		exportCSVWithoutScope(columns,rows);
	}

	$scope.getButtonContent = function(isLoading , defName) {
		var loadingContent = " Loading...";
		var returnValue = isLoading ? loadingContent : defName;
		return $sce.trustAsHtml(returnValue);
	}

	function arr2csvStr(arr,op){
		var data = arr[0];
		for(var i=1; i<arr.length ; i++){
				data += op;
				data += arr[i] ;
		}
		return data ;
	}

	function map2csvStr(columns,arr,op){
		var data = JSON.stringify(arr[columns[0]]);
		for(var i=1; i<columns.length ; i++){
				data += op;
				data += JSON.stringify(arr[columns[i]]) ;
		}
		return data ;
	}

	function getUrl() {
		var url = localStorage.getItem("lasturl");
		if(url == undefined) {
			if(location.protocol == "file") {
				url = "http://localhost:9200"
			}
			else {
				url = location.protocol+'//' + location.hostname + (location.port ? ':'+location.port : '');
			}
		}

		if(url.substr(url.length - 1, 1) != '/') {
			url += '/'
		}

		return url
	}

	function saveUrl() {
		localStorage.setItem("lasturl", $scope.url);
	}
});<|endoftext|>


<commit_before>(function() {
  'use strict';

  var noop = angular.noop;
  var objectFreeze  = (Object.freeze) ? Object.freeze : noop;
  var objectDefineProperty = Object.defineProperty;
  var isString   = angular.isString;
  var isFunction = angular.isFunction;
  var isDefined  = angular.isDefined;
  var isObject   = angular.isObject;
  var isArray    = angular.isArray;
  var forEach    = angular.forEach;
  var arraySlice = Array.prototype.slice;
  // ie8 wat
  if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(elt /*, from*/) {
      var len = this.length >>> 0;
      var from = Number(arguments[1]) || 0;
      from = (from < 0) ? Math.ceil(from) : Math.floor(from);
      if (from < 0) {
        from += len;
      }

      for (; from < len; from++) {
        if (from in this && this[from] === elt) { return from; }
      }
      return -1;
    };
  }

  // $WebSocketProvider.$inject = ['$rootScope', '$q', '$timeout', '$websocketBackend'];
  function $WebSocketProvider($rootScope, $q, $timeout, $websocketBackend) {

    function $WebSocket(url, protocols, options) {
      if (!options && isObject(protocols) && !isArray(protocols)) {
        options = protocols;
        protocols = undefined;
      }

      this.protocols = protocols;
      this.url = url || 'Missing URL';
      this.ssl = /(wss)/i.test(this.url);

      // this.binaryType = '';
      // this.extensions = '';
      // this.bufferedAmount = 0;
      // this.trasnmitting = false;
      // this.buffer = [];

      // TODO: refactor options to use isDefined
      this.scope                       = options && options.scope                      || $rootScope;
      this.rootScopeFailover           = options && options.rootScopeFailover          && true;
      this.useApplyAsync               = options && options.useApplyAsync              || false;
      this.initialTimeout              = options && options.initialTimeout             || 500; // 500ms
      this.maxTimeout                  = options && options.maxTimeout                 || 5 * 60 * 1000; // 5 minutes
      this.reconnectIfNotNormalClose   = options && options.reconnectIfNotNormalClose  || false;

      this._reconnectAttempts = 0;
      this.sendQueue          = [];
      this.onOpenCallbacks    = [];
      this.onMessageCallbacks = [];
      this.onErrorCallbacks   = [];
      this.onCloseCallbacks   = [];

      objectFreeze(this._readyStateConstants);

      if (url) {
        this._connect();
      } else {
        this._setInternalState(0);
      }

    }

    $WebSocket.prototype._readyStateConstants = {
      'CONNECTING': 0,
      'OPEN': 1,
      'CLOSING': 2,
      'CLOSED': 3,
      'RECONNECT_ABORTED': 4
    };

    $WebSocket.prototype._normalCloseCode = 1000;

    $WebSocket.prototype._reconnectableStatusCodes = [
      4000
    ];

    $WebSocket.prototype.safeDigest = function safeDigest(autoApply) {
      if (autoApply && !this.scope.$$phase) {
        this.scope.$digest();
      }
    };

    $WebSocket.prototype.bindToScope = function bindToScope(scope) {
      var self = this;
      if (scope) {
        this.scope = scope;
        if (this.rootScopeFailover) {
          this.scope.$on('$destroy', function() {
            self.scope = $rootScope;
          });
        }
      }
      return self;
    };

    $WebSocket.prototype._connect = function _connect(force) {
      if (force || !this.socket || this.socket.readyState !== this._readyStateConstants.OPEN) {
        this.socket = $websocketBackend.create(this.url, this.protocols);
        this.socket.onmessage = angular.bind(this, this._onMessageHandler);
        this.socket.onopen  = angular.bind(this, this._onOpenHandler);
        this.socket.onerror = angular.bind(this, this._onErrorHandler);
        this.socket.onclose = angular.bind(this, this._onCloseHandler);
      }
    };

    $WebSocket.prototype.fireQueue = function fireQueue() {
      while (this.sendQueue.length && this.socket.readyState === this._readyStateConstants.OPEN) {
        var data = this.sendQueue.shift();

        this.socket.send(
          isString(data.message) ? data.message : JSON.stringify(data.message)
        );
        data.deferred.resolve();
      }
    };

    $WebSocket.prototype.notifyOpenCallbacks = function notifyOpenCallbacks(event) {
      for (var i = 0; i < this.onOpenCallbacks.length; i++) {
        this.onOpenCallbacks[i].call(this, event);
      }
    };

    $WebSocket.prototype.notifyCloseCallbacks = function notifyCloseCallbacks(event) {
      for (var i = 0; i < this.onCloseCallbacks.length; i++) {
        this.onCloseCallbacks[i].call(this, event);
      }
    };

    $WebSocket.prototype.notifyErrorCallbacks = function notifyErrorCallbacks(event) {
      for (var i = 0; i < this.onErrorCallbacks.length; i++) {
        this.onErrorCallbacks[i].call(this, event);
      }
    };

    $WebSocket.prototype.onOpen = function onOpen(cb) {
      this.onOpenCallbacks.push(cb);
      return this;
    };

    $WebSocket.prototype.onClose = function onClose(cb) {
      this.onCloseCallbacks.push(cb);
      return this;
    };

    $WebSocket.prototype.onError = function onError(cb) {
      this.onErrorCallbacks.push(cb);
      return this;
    };

    $WebSocket.prototype.onMessage = function onMessage(callback, options) {
      if (!isFunction(callback)) {
        throw new Error('Callback must be a function');
      }

      if (options && isDefined(options.filter) && !isString(options.filter) && !(options.filter instanceof RegExp)) {
        throw new Error('Pattern must be a string or regular expression');
      }

      this.onMessageCallbacks.push({
        fn: callback,
        pattern: options ? options.filter : undefined,
        autoApply: options ? options.autoApply : true
      });
      return this;
    };

    $WebSocket.prototype._onOpenHandler = function _onOpenHandler(event) {
      this._reconnectAttempts = 0;
      this.notifyOpenCallbacks(event);
      this.fireQueue();
    };

    $WebSocket.prototype._onCloseHandler = function _onCloseHandler(event) {
      this.notifyCloseCallbacks(event);
      if ((this.reconnectIfNotNormalClose && event.code !== this._normalCloseCode) || this._reconnectableStatusCodes.indexOf(event.code) > -1) {
        this.reconnect();
      }
    };

    $WebSocket.prototype._onErrorHandler = function _onErrorHandler(event) {
      this.notifyErrorCallbacks(event);
    };

    $WebSocket.prototype._onMessageHandler = function _onMessageHandler(message) {
      var pattern;
      var self = this;
      var currentCallback;
      for (var i = 0; i < self.onMessageCallbacks.length; i++) {
        currentCallback = self.onMessageCallbacks[i];
        pattern = currentCallback.pattern;
        if (pattern) {
          if (isString(pattern) && message.data === pattern) {
            applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message);
          }
          else if (pattern instanceof RegExp && pattern.exec(message.data)) {
            applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message);
          }
        }
        else {
          applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message);
        }
      }

      function applyAsyncOrDigest(callback, autoApply, args) {
        args = arraySlice.call(arguments, 2);
        if (self.useApplyAsync) {
          self.scope.$applyAsync(function() {
            callback.apply(self, args);
          });
        } else {
          callback.apply(self, args);
          self.safeDigest(autoApply);
        }
      }

    };

    $WebSocket.prototype.close = function close(force) {
      if (force || !this.socket.bufferedAmount) {
        this.socket.close();
      }
      return this;
    };

    $WebSocket.prototype.send = function send(data) {
      var deferred = $q.defer();
      var self = this;
      var promise = cancelableify(deferred.promise);

      if (self.readyState === self._readyStateConstants.RECONNECT_ABORTED) {
        deferred.reject('Socket connection has been closed');
      }
      else {
        self.sendQueue.push({
          message: data,
          deferred: deferred
        });
        self.fireQueue();
      }

      // Credit goes to @btford
      function cancelableify(promise) {
        promise.cancel = cancel;
        var then = promise.then;
        promise.then = function() {
          var newPromise = then.apply(this, arguments);
          return cancelableify(newPromise);
        };
        return promise;
      }

      function cancel(reason) {
        self.sendQueue.splice(self.sendQueue.indexOf(data), 1);
        deferred.reject(reason);
        return self;
      }

      if ($websocketBackend.isMocked && $websocketBackend.isMocked() &&
              $websocketBackend.isConnected(this.url)) {
        this._onMessageHandler($websocketBackend.mockSend());
      }

      return promise;
    };

    $WebSocket.prototype.reconnect = function reconnect() {
      this.close();

      var backoffDelay = this._getBackoffDelay(++this._reconnectAttempts);

      var backoffDelaySeconds = backoffDelay / 1000;
      console.log('Reconnecting in ' + backoffDelaySeconds + ' seconds');

      $timeout(angular.bind(this, this._connect), backoffDelay);

      return this;
    };
    // Exponential Backoff Formula by Prof. Douglas Thain
    // http://dthain.blogspot.co.uk/2009/02/exponential-backoff-in-distributed.html
    $WebSocket.prototype._getBackoffDelay = function _getBackoffDelay(attempt) {
      var R = Math.random() + 1;
      var T = this.initialTimeout;
      var F = 2;
      var N = attempt;
      var M = this.maxTimeout;

      return Math.floor(Math.min(R * T * Math.pow(F, N), M));
    };

    $WebSocket.prototype._setInternalState = function _setInternalState(state) {
      if (Math.floor(state) !== state || state < 0 || state > 4) {
        throw new Error('state must be an integer between 0 and 4, got: ' + state);
      }

      // ie8 wat
      if (!objectDefineProperty) {
        this.readyState = state || this.socket.readyState;
      }
      this._internalConnectionState = state;

      forEach(this.sendQueue, function(pending) {
        pending.deferred.reject('Message cancelled due to closed socket connection');
      });
    };

    // Read only .readyState
    if (objectDefineProperty) {
      objectDefineProperty($WebSocket.prototype, 'readyState', {
        get: function() {
          return this._internalConnectionState || this.socket.readyState;
        },
        set: function() {
          throw new Error('The readyState property is read-only');
        }
      });
    }

    return function(url, protocols) {
      return new $WebSocket(url, protocols);
    };
  }

  // $WebSocketBackendProvider.$inject = ['$window', '$log'];
  function $WebSocketBackendProvider($window, $log) {
    this.create = function create(url, protocols) {
      var match = /wss?:\/\//.exec(url);
      var Socket, ws;
      if (!match) {
        throw new Error('Invalid url provided');
      }

      // CommonJS
      if (typeof exports === 'object' && require) {
        try {
          ws = require('ws');
          Socket = (ws.Client || ws.client || ws);
        } catch(e) {}
      }

      // Browser
      Socket = Socket || $window.WebSocket || $window.MozWebSocket;

      if (protocols) {
        return new Socket(url, protocols);
      }

      return new Socket(url);
    };
    this.createWebSocketBackend = function createWebSocketBackend(url, protocols) {
      $log.warn('Deprecated: Please use .create(url, protocols)');
      return this.create(url, protocols);
    };
  }

  angular.module('ngWebSocket', [])
  .factory('$websocket', ['$rootScope', '$q', '$timeout', '$websocketBackend', $WebSocketProvider])
  .factory('WebSocket',  ['$rootScope', '$q', '$timeout', 'WebsocketBackend',  $WebSocketProvider])
  .service('$websocketBackend', ['$window', '$log', $WebSocketBackendProvider])
  .service('WebSocketBackend',  ['$window', '$log', $WebSocketBackendProvider]);

  angular.module('angular-websocket', ['ngWebSocket']);

  if (typeof module === 'object' && typeof define !== 'function') {
    module.exports = angular.module('ngWebSocket');
  }
}());
<commit_msg>It was not possible to pass options to the $websocket constructor. This fix should also resolve the issue : https://github.com/gdi2290/angular-websocket/issues/18, if you do : ws = $websocket('ws://127.0.0.1:8888', null, {reconnectIfNotNormalClose: true});<commit_after>(function() {
  'use strict';

  var noop = angular.noop;
  var objectFreeze  = (Object.freeze) ? Object.freeze : noop;
  var objectDefineProperty = Object.defineProperty;
  var isString   = angular.isString;
  var isFunction = angular.isFunction;
  var isDefined  = angular.isDefined;
  var isObject   = angular.isObject;
  var isArray    = angular.isArray;
  var forEach    = angular.forEach;
  var arraySlice = Array.prototype.slice;
  // ie8 wat
  if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(elt /*, from*/) {
      var len = this.length >>> 0;
      var from = Number(arguments[1]) || 0;
      from = (from < 0) ? Math.ceil(from) : Math.floor(from);
      if (from < 0) {
        from += len;
      }

      for (; from < len; from++) {
        if (from in this && this[from] === elt) { return from; }
      }
      return -1;
    };
  }

  // $WebSocketProvider.$inject = ['$rootScope', '$q', '$timeout', '$websocketBackend'];
  function $WebSocketProvider($rootScope, $q, $timeout, $websocketBackend) {

    function $WebSocket(url, protocols, options) {
      if (!options && isObject(protocols) && !isArray(protocols)) {
        options = protocols;
        protocols = undefined;
      }

      this.protocols = protocols;
      this.url = url || 'Missing URL';
      this.ssl = /(wss)/i.test(this.url);

      // this.binaryType = '';
      // this.extensions = '';
      // this.bufferedAmount = 0;
      // this.trasnmitting = false;
      // this.buffer = [];

      // TODO: refactor options to use isDefined
      this.scope                       = options && options.scope                      || $rootScope;
      this.rootScopeFailover           = options && options.rootScopeFailover          && true;
      this.useApplyAsync               = options && options.useApplyAsync              || false;
      this.initialTimeout              = options && options.initialTimeout             || 500; // 500ms
      this.maxTimeout                  = options && options.maxTimeout                 || 5 * 60 * 1000; // 5 minutes
      this.reconnectIfNotNormalClose   = options && options.reconnectIfNotNormalClose  || false;

      this._reconnectAttempts = 0;
      this.sendQueue          = [];
      this.onOpenCallbacks    = [];
      this.onMessageCallbacks = [];
      this.onErrorCallbacks   = [];
      this.onCloseCallbacks   = [];

      objectFreeze(this._readyStateConstants);

      if (url) {
        this._connect();
      } else {
        this._setInternalState(0);
      }

    }

    $WebSocket.prototype._readyStateConstants = {
      'CONNECTING': 0,
      'OPEN': 1,
      'CLOSING': 2,
      'CLOSED': 3,
      'RECONNECT_ABORTED': 4
    };

    $WebSocket.prototype._normalCloseCode = 1000;

    $WebSocket.prototype._reconnectableStatusCodes = [
      4000
    ];

    $WebSocket.prototype.safeDigest = function safeDigest(autoApply) {
      if (autoApply && !this.scope.$$phase) {
        this.scope.$digest();
      }
    };

    $WebSocket.prototype.bindToScope = function bindToScope(scope) {
      var self = this;
      if (scope) {
        this.scope = scope;
        if (this.rootScopeFailover) {
          this.scope.$on('$destroy', function() {
            self.scope = $rootScope;
          });
        }
      }
      return self;
    };

    $WebSocket.prototype._connect = function _connect(force) {
      if (force || !this.socket || this.socket.readyState !== this._readyStateConstants.OPEN) {
        this.socket = $websocketBackend.create(this.url, this.protocols);
        this.socket.onmessage = angular.bind(this, this._onMessageHandler);
        this.socket.onopen  = angular.bind(this, this._onOpenHandler);
        this.socket.onerror = angular.bind(this, this._onErrorHandler);
        this.socket.onclose = angular.bind(this, this._onCloseHandler);
      }
    };

    $WebSocket.prototype.fireQueue = function fireQueue() {
      while (this.sendQueue.length && this.socket.readyState === this._readyStateConstants.OPEN) {
        var data = this.sendQueue.shift();

        this.socket.send(
          isString(data.message) ? data.message : JSON.stringify(data.message)
        );
        data.deferred.resolve();
      }
    };

    $WebSocket.prototype.notifyOpenCallbacks = function notifyOpenCallbacks(event) {
      for (var i = 0; i < this.onOpenCallbacks.length; i++) {
        this.onOpenCallbacks[i].call(this, event);
      }
    };

    $WebSocket.prototype.notifyCloseCallbacks = function notifyCloseCallbacks(event) {
      for (var i = 0; i < this.onCloseCallbacks.length; i++) {
        this.onCloseCallbacks[i].call(this, event);
      }
    };

    $WebSocket.prototype.notifyErrorCallbacks = function notifyErrorCallbacks(event) {
      for (var i = 0; i < this.onErrorCallbacks.length; i++) {
        this.onErrorCallbacks[i].call(this, event);
      }
    };

    $WebSocket.prototype.onOpen = function onOpen(cb) {
      this.onOpenCallbacks.push(cb);
      return this;
    };

    $WebSocket.prototype.onClose = function onClose(cb) {
      this.onCloseCallbacks.push(cb);
      return this;
    };

    $WebSocket.prototype.onError = function onError(cb) {
      this.onErrorCallbacks.push(cb);
      return this;
    };

    $WebSocket.prototype.onMessage = function onMessage(callback, options) {
      if (!isFunction(callback)) {
        throw new Error('Callback must be a function');
      }

      if (options && isDefined(options.filter) && !isString(options.filter) && !(options.filter instanceof RegExp)) {
        throw new Error('Pattern must be a string or regular expression');
      }

      this.onMessageCallbacks.push({
        fn: callback,
        pattern: options ? options.filter : undefined,
        autoApply: options ? options.autoApply : true
      });
      return this;
    };

    $WebSocket.prototype._onOpenHandler = function _onOpenHandler(event) {
      this._reconnectAttempts = 0;
      this.notifyOpenCallbacks(event);
      this.fireQueue();
    };

    $WebSocket.prototype._onCloseHandler = function _onCloseHandler(event) {
      this.notifyCloseCallbacks(event);
      if ((this.reconnectIfNotNormalClose && event.code !== this._normalCloseCode) || this._reconnectableStatusCodes.indexOf(event.code) > -1) {
        this.reconnect();
      }
    };

    $WebSocket.prototype._onErrorHandler = function _onErrorHandler(event) {
      this.notifyErrorCallbacks(event);
    };

    $WebSocket.prototype._onMessageHandler = function _onMessageHandler(message) {
      var pattern;
      var self = this;
      var currentCallback;
      for (var i = 0; i < self.onMessageCallbacks.length; i++) {
        currentCallback = self.onMessageCallbacks[i];
        pattern = currentCallback.pattern;
        if (pattern) {
          if (isString(pattern) && message.data === pattern) {
            applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message);
          }
          else if (pattern instanceof RegExp && pattern.exec(message.data)) {
            applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message);
          }
        }
        else {
          applyAsyncOrDigest(currentCallback.fn, currentCallback.autoApply, message);
        }
      }

      function applyAsyncOrDigest(callback, autoApply, args) {
        args = arraySlice.call(arguments, 2);
        if (self.useApplyAsync) {
          self.scope.$applyAsync(function() {
            callback.apply(self, args);
          });
        } else {
          callback.apply(self, args);
          self.safeDigest(autoApply);
        }
      }

    };

    $WebSocket.prototype.close = function close(force) {
      if (force || !this.socket.bufferedAmount) {
        this.socket.close();
      }
      return this;
    };

    $WebSocket.prototype.send = function send(data) {
      var deferred = $q.defer();
      var self = this;
      var promise = cancelableify(deferred.promise);

      if (self.readyState === self._readyStateConstants.RECONNECT_ABORTED) {
        deferred.reject('Socket connection has been closed');
      }
      else {
        self.sendQueue.push({
          message: data,
          deferred: deferred
        });
        self.fireQueue();
      }

      // Credit goes to @btford
      function cancelableify(promise) {
        promise.cancel = cancel;
        var then = promise.then;
        promise.then = function() {
          var newPromise = then.apply(this, arguments);
          return cancelableify(newPromise);
        };
        return promise;
      }

      function cancel(reason) {
        self.sendQueue.splice(self.sendQueue.indexOf(data), 1);
        deferred.reject(reason);
        return self;
      }

      if ($websocketBackend.isMocked && $websocketBackend.isMocked() &&
              $websocketBackend.isConnected(this.url)) {
        this._onMessageHandler($websocketBackend.mockSend());
      }

      return promise;
    };

    $WebSocket.prototype.reconnect = function reconnect() {
      this.close();

      var backoffDelay = this._getBackoffDelay(++this._reconnectAttempts);

      var backoffDelaySeconds = backoffDelay / 1000;
      console.log('Reconnecting in ' + backoffDelaySeconds + ' seconds');

      $timeout(angular.bind(this, this._connect), backoffDelay);

      return this;
    };
    // Exponential Backoff Formula by Prof. Douglas Thain
    // http://dthain.blogspot.co.uk/2009/02/exponential-backoff-in-distributed.html
    $WebSocket.prototype._getBackoffDelay = function _getBackoffDelay(attempt) {
      var R = Math.random() + 1;
      var T = this.initialTimeout;
      var F = 2;
      var N = attempt;
      var M = this.maxTimeout;

      return Math.floor(Math.min(R * T * Math.pow(F, N), M));
    };

    $WebSocket.prototype._setInternalState = function _setInternalState(state) {
      if (Math.floor(state) !== state || state < 0 || state > 4) {
        throw new Error('state must be an integer between 0 and 4, got: ' + state);
      }

      // ie8 wat
      if (!objectDefineProperty) {
        this.readyState = state || this.socket.readyState;
      }
      this._internalConnectionState = state;

      forEach(this.sendQueue, function(pending) {
        pending.deferred.reject('Message cancelled due to closed socket connection');
      });
    };

    // Read only .readyState
    if (objectDefineProperty) {
      objectDefineProperty($WebSocket.prototype, 'readyState', {
        get: function() {
          return this._internalConnectionState || this.socket.readyState;
        },
        set: function() {
          throw new Error('The readyState property is read-only');
        }
      });
    }

    return function(url, protocols, options) {
      return new $WebSocket(url, protocols, options);
    };
  }

  // $WebSocketBackendProvider.$inject = ['$window', '$log'];
  function $WebSocketBackendProvider($window, $log) {
    this.create = function create(url, protocols) {
      var match = /wss?:\/\//.exec(url);
      var Socket, ws;
      if (!match) {
        throw new Error('Invalid url provided');
      }

      // CommonJS
      if (typeof exports === 'object' && require) {
        try {
          ws = require('ws');
          Socket = (ws.Client || ws.client || ws);
        } catch(e) {}
      }

      // Browser
      Socket = Socket || $window.WebSocket || $window.MozWebSocket;

      if (protocols) {
        return new Socket(url, protocols);
      }

      return new Socket(url);
    };
    this.createWebSocketBackend = function createWebSocketBackend(url, protocols) {
      $log.warn('Deprecated: Please use .create(url, protocols)');
      return this.create(url, protocols);
    };
  }

  angular.module('ngWebSocket', [])
  .factory('$websocket', ['$rootScope', '$q', '$timeout', '$websocketBackend', $WebSocketProvider])
  .factory('WebSocket',  ['$rootScope', '$q', '$timeout', 'WebsocketBackend',  $WebSocketProvider])
  .service('$websocketBackend', ['$window', '$log', $WebSocketBackendProvider])
  .service('WebSocketBackend',  ['$window', '$log', $WebSocketBackendProvider]);

  angular.module('angular-websocket', ['ngWebSocket']);

  if (typeof module === 'object' && typeof define !== 'function') {
    module.exports = angular.module('ngWebSocket');
  }
}());
<|endoftext|>


<commit_before>import { Key } from '../key';
import { ListBinder } from '../binder/list_binder';
import { MapBinder } from '../binder/map_binder';

class Annotations {
  static setAnnotation(annotation, target, key) {
    const annotations = Reflect.getMetadata('annotations', target, key) || [];
    annotations.push(annotation);
    return Reflect.defineMetadata('annotations', annotations, target, key);
  }
  static getAnnotations(AnnotationType, target, key) {
    const annotations = Reflect.getMetadata('annotations', target, key) || [];
    const result = annotations.filter(x => (x instanceof AnnotationType));
    return result;
  }
  static hasAnnotation(AnnotationType, target, key) {
    return Annotations.getAnnotations(AnnotationType, target, key).length !== 0;
  }

  static getAnnotation(AnnotationType, target, key) {
    const res = Annotations.getAnnotations(AnnotationType, target, key);
    if (res.length !== 1) {
      throw new Error(`There is ${res.length} annotations available of type ${AnnotationType}`);
    }
    return res[0];
  }
}

class InjectAnnotation {
  constructor(...keys) {
    this._keys = keys.map(k => {
      let r;
      if (!(k instanceof Key)) {
        r = Key.fromToken(k);
      } else {
        r = k;
      }
      return r;
    });
  }
  getKeys() {
    return this._keys;
  }
}

class InjectableAnnotation {
  constructor() {

  }
}

class BindingAnnotation {
  constructor(key, asPromise = false) {
    this._key = key;
    this._asPromise = asPromise;
  }
  get key() {
    return this._key;
  }

  get asPromise() {
    return this._asPromise;
  }
  bind(target, targetKey, binder) {
    throw new Error('Binding needs to override bind()');
  }
}

class SingletonAnnotation {
  scope(key, unscopedProvider) {
    const instances = {};
    return () => {
      const rawKey = key.getRawKey();
      let instance = instances[rawKey];
      if (instances[rawKey] === undefined) {
        instance = instances[rawKey] = unscopedProvider();
      }
      return instance;
    };
  }
}

class ProvidesAnnotation extends BindingAnnotation {
  bind(binder, target, targetKey) {
    const provide = this;
    const fn = target[targetKey];
    let scope;
    if (Annotations.hasAnnotation(SingletonAnnotation, target, targetKey)) {
      scope = Annotations.getAnnotation(SingletonAnnotation, target, targetKey);
    }
    // check arguments
    if (fn.length !== 0) {
      if (!Annotations.hasAnnotation(InjectAnnotation, target, targetKey)) {
        throw new Error('@Provides function has unsatisfied parameters, @Inject is missing',
          target, k);
      } else {
        // we have a provides function which should have things injected
        const inject = Annotations.getAnnotation(InjectAnnotation, target, targetKey);
        if (inject.getKeys().length !== fn.length) {
          throw new Error(`@Provides function has unsatisfied parameters, @Inject specifies
                 ${inject.getKeys().length} keys and function expects ${fn.length} parameters`);
        }
        const key = provide.key;
        binder.bindKey(key)
          .toProvider(fn.bind(target), inject.getKeys(), provide.asPromise).in(scope);
      }
    } else {
      const key = provide.key;
      binder.bindKey(key).toProvider(fn.bind(target), null, provide.asPromise).in(scope);
    }
  }
}

class ProvidesToListAnnotation extends BindingAnnotation {
  constructor(key, sortOrder, asPromise) {
    super(key, asPromise);
    this._sortOrder = sortOrder;
  }

  bind(binder, target, targetKey) {
    const listBinder = ListBinder.get(binder, this._key);
    const itemKey = listBinder._getKey(this._sortOrder);
    new ProvidesAnnotation(itemKey, this._asPromise).bind(listBinder, target, targetKey);
  }
}

class ProvidesToMapAnnotation extends BindingAnnotation {
  constructor(key, itemKey, asPromise) {
    super(key, asPromise);
    this._itemKey = itemKey;
    if (!key || !itemKey) {
      throw new Error('Unable to bind to map with key / itemKey', key, itemKey);
    }
  }

  bind(binder, target, targetKey) {
    const mapBinder = MapBinder.get(binder, this._key);
    new ProvidesAnnotation(this._itemKey, this._asPromise).bind(mapBinder, target, targetKey);
  }
}

class PromisesAnnotation extends ProvidesAnnotation {
  constructor(key) {
    super(key, true);
  }
}

/*
function MyAnnotation(options): Decorator {
  return (target, key) => Reflect.defineMetadata('custom:annotation', options, target, key);
}
*/
export {
  InjectAnnotation, ProvidesAnnotation, InjectableAnnotation,
  Annotations, PromisesAnnotation, SingletonAnnotation, BindingAnnotation, ProvidesToListAnnotation,
  ProvidesToMapAnnotation,
};
<commit_msg>Annotations name comparisons if not instanceof<commit_after>import { Key } from '../key';
import { ListBinder } from '../binder/list_binder';
import { MapBinder } from '../binder/map_binder';

class Annotations {
  static setAnnotation(annotation, target, key) {
    const annotations = Reflect.getMetadata('annotations', target, key) || [];
    annotations.push(annotation);
    return Reflect.defineMetadata('annotations', annotations, target, key);
  }
  static getAnnotations(AnnotationType, target, key) {
    const annotations = Reflect.getMetadata('annotations', target, key) || [];
    const result = annotations.filter(x => (x instanceof AnnotationType || (Object.getPrototypeOf(x.constructor).name === AnnotationType.name)));
    return result;
  }
  static hasAnnotation(AnnotationType, target, key) {
    return Annotations.getAnnotations(AnnotationType, target, key).length !== 0;
  }

  static getAnnotation(AnnotationType, target, key) {
    const res = Annotations.getAnnotations(AnnotationType, target, key);
    if (res.length !== 1) {
      throw new Error(`There is ${res.length} annotations available of type ${AnnotationType}`);
    }
    return res[0];
  }
}

class InjectAnnotation {
  constructor(...keys) {
    this._keys = keys.map(k => {
      let r;
      if (!(k instanceof Key)) {
        r = Key.fromToken(k);
      } else {
        r = k;
      }
      return r;
    });
  }
  getKeys() {
    return this._keys;
  }
}

class InjectableAnnotation {
  constructor() {

  }
}

class BindingAnnotation {
  constructor(key, asPromise = false) {
    this._key = key;
    this._asPromise = asPromise;
  }
  get key() {
    return this._key;
  }

  get asPromise() {
    return this._asPromise;
  }
  bind(target, targetKey, binder) {
    throw new Error('Binding needs to override bind()');
  }
}

class SingletonAnnotation {
  scope(key, unscopedProvider) {
    const instances = {};
    return () => {
      const rawKey = key.getRawKey();
      let instance = instances[rawKey];
      if (instances[rawKey] === undefined) {
        instance = instances[rawKey] = unscopedProvider();
      }
      return instance;
    };
  }
}

class ProvidesAnnotation extends BindingAnnotation {
  bind(binder, target, targetKey) {
    const provide = this;
    const fn = target[targetKey];
    let scope;
    if (Annotations.hasAnnotation(SingletonAnnotation, target, targetKey)) {
      scope = Annotations.getAnnotation(SingletonAnnotation, target, targetKey);
    }
    // check arguments
    if (fn.length !== 0) {
      if (!Annotations.hasAnnotation(InjectAnnotation, target, targetKey)) {
        throw new Error('@Provides function has unsatisfied parameters, @Inject is missing',
          target, k);
      } else {
        // we have a provides function which should have things injected
        const inject = Annotations.getAnnotation(InjectAnnotation, target, targetKey);
        if (inject.getKeys().length !== fn.length) {
          throw new Error(`@Provides function has unsatisfied parameters, @Inject specifies
                 ${inject.getKeys().length} keys and function expects ${fn.length} parameters`);
        }
        const key = provide.key;
        binder.bindKey(key)
          .toProvider(fn.bind(target), inject.getKeys(), provide.asPromise).in(scope);
      }
    } else {
      const key = provide.key;
      binder.bindKey(key).toProvider(fn.bind(target), null, provide.asPromise).in(scope);
    }
  }
}

class ProvidesToListAnnotation extends BindingAnnotation {
  constructor(key, sortOrder, asPromise) {
    super(key, asPromise);
    this._sortOrder = sortOrder;
  }

  bind(binder, target, targetKey) {
    const listBinder = ListBinder.get(binder, this._key);
    const itemKey = listBinder._getKey(this._sortOrder);
    new ProvidesAnnotation(itemKey, this._asPromise).bind(listBinder, target, targetKey);
  }
}

class ProvidesToMapAnnotation extends BindingAnnotation {
  constructor(key, itemKey, asPromise) {
    super(key, asPromise);
    this._itemKey = itemKey;
    if (!key || !itemKey) {
      throw new Error('Unable to bind to map with key / itemKey', key, itemKey);
    }
  }

  bind(binder, target, targetKey) {
    const mapBinder = MapBinder.get(binder, this._key);
    new ProvidesAnnotation(this._itemKey, this._asPromise).bind(mapBinder, target, targetKey);
  }
}

class PromisesAnnotation extends ProvidesAnnotation {
  constructor(key) {
    super(key, true);
  }
}

/*
function MyAnnotation(options): Decorator {
  return (target, key) => Reflect.defineMetadata('custom:annotation', options, target, key);
}
*/
export {
  InjectAnnotation, ProvidesAnnotation, InjectableAnnotation,
  Annotations, PromisesAnnotation, SingletonAnnotation, BindingAnnotation, ProvidesToListAnnotation,
  ProvidesToMapAnnotation,
};
<|endoftext|>


<commit_before>const path = Plugin.path;
const less = Npm.require('less');
const Future = Npm.require('fibers/future');
const LessPluginAutoprefixer = Npm.require('less-plugin-autoprefix');

Plugin.registerCompiler({
  // *.lessimport has been deprecated since 0.7.1, but it still works. We
  // *recommend *.import.less or the imports subdirectory instead.
  extensions: ['less', 'lessimport'],
  archMatching: 'web'
}, () => new LessCompiler());

// CompileResult is {css, sourceMap}.
class LessCompiler extends MultiFileCachingCompiler {
  constructor() {
    super({
      compilerName: 'less',
      defaultCacheSize: 1024*1024*10,
    });
  }

  getCacheKey(inputFile) {
    return inputFile.getSourceHash();
  }

  compileResultSize(compileResult) {
    return compileResult.css.length +
      this.sourceMapSize(compileResult.sourceMap);
  }

  // The heuristic is that a file is an import (ie, is not itself processed as a
  // root) if it is in a subdirectory named 'imports' or if it matches
  // *.import.less. This can be overridden in either direction via an explicit
  // `isImport` file option in api.addFiles.
  isRoot(inputFile) {
    const fileOptions = inputFile.getFileOptions();
    if (fileOptions.hasOwnProperty('isImport')) {
      return !fileOptions.isImport;
    }

    const pathInPackage = inputFile.getPathInPackage();
    return !(/\.import\.less$/.test(pathInPackage) ||
             /\.lessimport$/.test(pathInPackage) ||
             /(?:^|\/)imports\//.test(pathInPackage));
  }

  compileOneFile(inputFile, allFiles) {
    const importPlugin = new MeteorImportLessPlugin(allFiles);
    const autoprefixerPlugin = new LessPluginAutoprefixer(parseAutoprefixerOptions(process.env.AUTOPREFIXER_OPTIONS || 'null'));

    const f = new Future;
    let output;
    try {
      less.render(inputFile.getContentsAsBuffer().toString('utf8'), {
        filename: this.getAbsoluteImportPath(inputFile),
        plugins: [importPlugin, autoprefixerPlugin],
        // Generate a source map, and include the source files in the
        // sourcesContent field.  (Note that source files which don't themselves
        // produce text (eg, are entirely variable definitions) won't end up in
        // the source map!)
        sourceMap: { outputSourceFiles: true }
      }, f.resolver());
      output = f.wait();
    } catch (e) {
      inputFile.error({
        message: e.message,
        sourcePath: decodeFilePath(e.filename),
        line: e.line,
        column: e.column
      });
      return null;
    }

    if (output.map) {
      const map = JSON.parse(output.map);
      map.sources = map.sources.map(decodeFilePath);
      output.map = map;
    }

    const compileResult = {css: output.css, sourceMap: output.map};
    const referencedImportPaths = [];
    output.imports.forEach((path) => {
      if (! allFiles.has(path)) {
        throw Error("Imported an unknown file?");
      }
      referencedImportPaths.push(path);
    });

    return {compileResult, referencedImportPaths};
  }

  addCompileResult(inputFile, compileResult) {
    inputFile.addStylesheet({
      data: compileResult.css,
      path: inputFile.getPathInPackage() + '.css',
      sourceMap: compileResult.sourceMap
    });
  }
}

class MeteorImportLessPlugin {
  constructor(allFiles) {
    this.allFiles = allFiles;
    this.minVersion = [2, 5, 0];
  }

  install(less, pluginManager) {
    pluginManager.addFileManager(
      new MeteorImportLessFileManager(this.allFiles));
  }
}

class MeteorImportLessFileManager extends less.AbstractFileManager {
  constructor(allFiles) {
    super();
    this.allFiles = allFiles;
  }

  // We want to be the only active FileManager, so claim to support everything.
  supports() {
    return true;
  }

  loadFile(filename, currentDirectory, options, environment, cb) {
    const packageMatch = currentDirectory.match(/^(\{[^}]*\})/);
    if (! packageMatch) {
      // shouldn't happen.  all filenames less ever sees should involve this {}
      // thing!
      cb(new Error('file without Meteor context? ' + currentDirectory));
      return;
    }
    const currentPackagePrefix = packageMatch[1];

    let resolvedFilename;
    if (filename[0] === '/') {
      // Map `/foo/bar.less` onto `{thispackage}/foo/bar.less`
      resolvedFilename = currentPackagePrefix + filename;
    } else if (filename[0] === '{') {
      resolvedFilename = filename;
    } else {
      resolvedFilename = path.join(currentDirectory, filename);
    }

    if (!this.allFiles.has(resolvedFilename)) {
      cb({type: 'File', message: 'Unknown import: ' + filename});
      return;
    }
    cb(null, {
      contents: this.allFiles.get(resolvedFilename)
        .getContentsAsBuffer().toString('utf8'),
      filename: resolvedFilename
    });
  }
}

function decodeFilePath (filePath) {
  const match = filePath.match(/^{(.*)}\/(.*)$/);
  if (! match){
    return filePath;
  }

  if (match[1] === '') {
    // app
    return match[2];
  }
  return 'packages/' + match[1] + '/' + match[2];
}

function parseAutoprefixerOptions(options) {
  try {
    const o = JSON.parse(options);
    if (o && typeof o === "object" && o !== null) {
      if (Object.keys(o)[0] !== "browsers"){
        console.log('\n less-autoprefixer: invalid AUTOPREFIXER_OPTIONS - "browsers" key not found, falling back to default options - { browsers: "> 1%, last 2 versions, Firefox ESR, Opera 12.1"}, more info - https://github.com/postcss/autoprefixer#options');
      } else {
        return o;
      }
    }
  }
  catch (e) {
    console.log("\n less-autoprefixer: invalid JSON format in AUTOPREFIXER_OPTIONS -", e);
    console.log(' less-autoprefixer: falling back to default options - { browsers: "> 1%, last 2 versions, Firefox ESR, Opera 12.1"}, more info - https://github.com/postcss/autoprefixer#options');
  }
  return {};
}
<commit_msg>restore meteor core less plugin file<commit_after>const path = Plugin.path;
const less = Npm.require('less');
const Future = Npm.require('fibers/future');

Plugin.registerCompiler({
  // *.lessimport has been deprecated since 0.7.1, but it still works. We
  // *recommend *.import.less or the imports subdirectory instead.
  extensions: ['less', 'lessimport'],
  archMatching: 'web'
}, () => new LessCompiler());

// CompileResult is {css, sourceMap}.
class LessCompiler extends MultiFileCachingCompiler {
  constructor() {
    super({
      compilerName: 'less',
      defaultCacheSize: 1024*1024*10,
    });
  }

  getCacheKey(inputFile) {
    return inputFile.getSourceHash();
  }

  compileResultSize(compileResult) {
    return compileResult.css.length +
      this.sourceMapSize(compileResult.sourceMap);
  }

  // The heuristic is that a file is an import (ie, is not itself processed as a
  // root) if it is in a subdirectory named 'imports' or if it matches
  // *.import.less. This can be overridden in either direction via an explicit
  // `isImport` file option in api.addFiles.
  isRoot(inputFile) {
    const fileOptions = inputFile.getFileOptions();
    if (fileOptions.hasOwnProperty('isImport')) {
      return !fileOptions.isImport;
    }

    const pathInPackage = inputFile.getPathInPackage();
    return !(/\.import\.less$/.test(pathInPackage) ||
             /\.lessimport$/.test(pathInPackage) ||
             /(?:^|\/)imports\//.test(pathInPackage));
  }

  compileOneFile(inputFile, allFiles) {
    const importPlugin = new MeteorImportLessPlugin(allFiles);

    const f = new Future;
    let output;
    try {
      less.render(inputFile.getContentsAsBuffer().toString('utf8'), {
        filename: this.getAbsoluteImportPath(inputFile),
        plugins: [importPlugin],
        // Generate a source map, and include the source files in the
        // sourcesContent field.  (Note that source files which don't themselves
        // produce text (eg, are entirely variable definitions) won't end up in
        // the source map!)
        sourceMap: { outputSourceFiles: true }
      }, f.resolver());
      output = f.wait();
    } catch (e) {
      inputFile.error({
        message: e.message,
        sourcePath: decodeFilePath(e.filename),
        line: e.line,
        column: e.column
      });
      return null;
    }

    if (output.map) {
      const map = JSON.parse(output.map);
      map.sources = map.sources.map(decodeFilePath);
      output.map = map;
    }

    const compileResult = {css: output.css, sourceMap: output.map};
    const referencedImportPaths = [];
    output.imports.forEach((path) => {
      // Some files that show up in output.imports are not actually files; for
      // example @import url("...");
      if (allFiles.has(path)) {
        referencedImportPaths.push(path);
      }
    });

    return {compileResult, referencedImportPaths};
  }

  addCompileResult(inputFile, compileResult) {
    inputFile.addStylesheet({
      data: compileResult.css,
      path: inputFile.getPathInPackage() + '.css',
      sourceMap: compileResult.sourceMap
    });
  }
}

class MeteorImportLessPlugin {
  constructor(allFiles) {
    this.allFiles = allFiles;
    this.minVersion = [2, 5, 0];
  }

  install(less, pluginManager) {
    pluginManager.addFileManager(
      new MeteorImportLessFileManager(this.allFiles));
  }
}

class MeteorImportLessFileManager extends less.AbstractFileManager {
  constructor(allFiles) {
    super();
    this.allFiles = allFiles;
  }

  // We want to be the only active FileManager, so claim to support everything.
  supports(filename) {
    // We shouldn't process files that start with `//` or a protocol because
    // those are not relative to the app at all; they are probably native
    // CSS imports
    if (! filename.match(/^(https?:)?\/\//)) {
      return true;
    }

    return false;
  }

  loadFile(filename, currentDirectory, options, environment, cb) {
    const packageMatch = currentDirectory.match(/^(\{[^}]*\})/);
    if (! packageMatch) {
      // shouldn't happen.  all filenames less ever sees should involve this {}
      // thing!
      cb(new Error('file without Meteor context? ' + currentDirectory));
      return;
    }
    const currentPackagePrefix = packageMatch[1];

    let resolvedFilename;
    if (filename[0] === '/') {
      // Map `/foo/bar.less` onto `{thispackage}/foo/bar.less`
      resolvedFilename = currentPackagePrefix + filename;
    } else if (filename[0] === '{') {
      resolvedFilename = filename;
    } else {
      resolvedFilename = path.join(currentDirectory, filename);
    }

    if (!this.allFiles.has(resolvedFilename)) {
      cb({type: 'File', message: 'Unknown import: ' + filename});
      return;
    }
    cb(null, {
      contents: this.allFiles.get(resolvedFilename)
        .getContentsAsBuffer().toString('utf8'),
      filename: resolvedFilename
    });
  }
}

function decodeFilePath (filePath) {
  const match = filePath.match(/^{(.*)}\/(.*)$/);
  if (! match)
    throw new Error('Failed to decode Less path: ' + filePath);

  if (match[1] === '') {
    // app
    return match[2];
  }

  return 'packages/' + match[1] + '/' + match[2];
}
<|endoftext|>


<commit_before>/* global FileReader, confirm, alert */
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var Treeview = require('ethereum-remix').ui.TreeView

var EventManager = require('../lib/eventManager')

var css = csjs`
  .fileexplorer       {
    box-sizing        : border-box;
  }
  .folder,
  .file               {
    font-size         : 14px;
  }
  .hasFocus           {
    background-color  : #F4F6FF;
  }
  .rename             {
    background-color  : white;
  }
  .remove             {
    align-self        : center;
    padding-left      : 10px;
  }
  .activeMode         {
    display           : flex;
    justify-content   : space-between;
    margin-right      : 10px;
    padding-right     : 19px;
  }
  ul                  {
    padding           : 0;
  }
`
module.exports = fileExplorer

function fileExplorer (appAPI, files) {
  var fileEvents = files.event
  var tv = new Treeview({
    extractData: function (value, tree, key) {
      var newValue = {}
      // var isReadOnly = false
      var isFile = false
      Object.keys(value).filter(function keep (x) {
        if (x === '/content') isFile = true
        // if (x === '/readOnly') isReadOnly = true
        if (x[0] !== '/') return true
      }).forEach(function (x) { newValue[x] = value[x] })
      return {
        path: (tree || {}).path ? tree.path + '/' + key : key,
        children: isFile ? undefined
        : value instanceof Array ? value.map((item, index) => ({
          key: index, value: item
        })) : value instanceof Object ? Object.keys(value).map(subkey => ({
          key: subkey, value: value[subkey]
        })) : undefined
      }
    },
    formatSelf: function (key, data) {
      return yo`${key}`
    }
  })

  var deleteButton = yo`

  `

  appAPI.event.register('currentFileChanged', (newFile) => {
    fileFocus(newFile)
  })
  fileEvents.register('fileRemoved', fileRemoved)
  fileEvents.register('fileRenamed', fileRenamed)
  fileEvents.register('fileAdded', fileAdded)

  var filepath = null
  var focusElement = null
  var textUnderEdit = null

  var element = tv.render(files.listAsTree())
  element.className = css.fileexplorer

  var api = new EventManager()
  api.addFile = function addFile (file) {
    var name = file.name
    if (!files.exists(name) || confirm('The file ' + name + ' already exists! Would you like to overwrite it?')) {
      var fileReader = new FileReader()
      fileReader.onload = function (event) {
        var success = files.set(name, event.target.result)
        if (!success) alert('Failed to create file ' + name)
        else api.trigger('focus', [name])
      }
      fileReader.readAsText(file)
    }
  }

  function focus (event) {
    event.cancelBubble = true
    var li = this
    if (focusElement === li) return
    if (focusElement) focusElement.classList.toggle(css.hasFocus)
    focusElement = li
    focusElement.classList.toggle(css.hasFocus)
    var label = getLabelFrom(li)
    var filepath = label.dataset.path
    var isFile = label.className.indexOf('file') === 0
    if (isFile) api.trigger('focus', [filepath])
  }

  function hover (event) {
    if (event.type === 'mouseout') {
      var exitedTo = event.toElement || event.relatedTarget
      if (this.contains(exitedTo)) return
      this.style.backgroundColor = ''
      this.style.paddingRight = '19px'
      return this.removeChild(deleteButton)
    }
    this.style.backgroundColor = '#F4F6FF'
    this.style.paddingRight = '0px'
    this.appendChild(deleteButton)
  }

  function getElement (path) {
    var label = element.querySelector(`label[data-path="${path}"]`)
    if (label) return getLiFrom(label)
  }

  function deletePath (event) {
    event.cancelBubble = true
    var span = this
    var li = span.parentElement.parentElement
    var label = getLabelFrom(li)
    var path = label.dataset.path
    var isFolder = !!~label.className.indexOf('folder')
    if (isFolder) path += '/'
    if (confirm(`Do you really want to delete "${path}" ?`)) {
      li.parentElement.removeChild(li)
      removeSubtree(files, path)
    }
  }

  function editModeOn (event) {
    var label = this
    var li = getLiFrom(label)
    var classes = li.className
    if (~classes.indexOf('hasFocus') && !label.getAttribute('contenteditable')) {
      textUnderEdit = label.innerText
      label.setAttribute('contenteditable', true)
      label.classList.add(css.rename)
      label.focus()
    }
  }

  function editModeOff (event) {
    var label = this
    if (event.type === 'blur' || event.which === 27 || event.which === 13) {
      var save = textUnderEdit !== label.innerText
      if (event.which === 13) event.preventDefault()
      if (save && event.which !== 13) save = confirm('Do you want to rename?')
      if (save) renameSubtree(label)
      else label.innerText = textUnderEdit
      label.removeAttribute('contenteditable')
      label.classList.remove(css.rename)
    }
  }

  function renameSubtree (label, dontcheck) {
    var oldPath = label.dataset.path
    var newPath = oldPath
    newPath = newPath.split('/')
    newPath[newPath.length - 1] = label.innerText
    newPath = newPath.join('/')
    if (!dontcheck) {
      var allPaths = Object.keys(files.list())
      for (var i = 0, len = allPaths.length, path, err; i < len; i++) {
        path = allPaths[i]
        if (files.isReadOnly(path)) {
          err = 'path contains readonly elements'
          break
        } else if (path.indexOf(newPath) === 0) {
          err = 'new path is conflicting with another existing path'
          break
        }
      }
    }
    if (err) {
      alert(`couldn't rename - ${err}`)
      label.innerText = textUnderEdit
    } else {
      textUnderEdit = label.innerText
      updateAllLabels([getElement(oldPath)], oldPath, newPath)
    }
  }

  function updateAllLabels (lis, oldPath, newPath) {
    lis.forEach(function (li) {
      var label = getLabelFrom(li)
      var path = label.dataset.path
      var newName = path.replace(oldPath, newPath)
      label.dataset.path = newName
      var isFile = label.className.indexOf('file') === 0
      if (isFile) files.rename(path, newName)
      var ul = li.lastChild
      if (ul.tagName === 'UL') {
        updateAllLabels([...ul.children], oldPath, newPath)
      }
    })
  }

  function fileFocus (path) {
    if (filepath === path) return
    filepath = path
    var el = getElement(filepath)
    expandPathTo(el)
    setTimeout(function focusNode () { el.click() }, 0)
  }

  function fileRemoved (filepath) {
    var li = getElement(filepath)
    if (li) li.parentElement.removeChild(li)
  }

  function fileRenamed (oldName, newName) {
    var li = getElement(oldName)
    if (li) {
      oldName = oldName.split('/')
      newName = newName.split('/')
      var index = oldName.reduce(function (idx, key, i) {
        return oldName[i] !== newName[i] ? i : idx
      }, undefined)
      var newKey = newName[index]
      var oldPath = oldName.slice(0, index + 1).join('/')
      li = getElement(oldPath)
      var label = getLabelFrom(li)
      label.innerText = newKey
      renameSubtree(label, true)
    }
  }

  function fileAdded (filepath) {
    var el = tv.render(files.listAsTree())
    el.className = css.fileexplorer
    element.parentElement.replaceChild(el, element)
    element = el
  }

  element.api = api
  return element
}
/******************************************************************************
  HELPER FUNCTIONS
******************************************************************************/
function adaptEnvironment (label, focus, hover) {
  var li = getLiFrom(label)
  li.style.position = 'relative'
  var span = li.firstChild
  // add focus
  li.addEventListener('click', focus)
  // add hover
  span.classList.add(css.activeMode)
  span.addEventListener('mouseover', hover)
  span.addEventListener('mouseout', hover)
}

function unadaptEnvironment (label, focus, hover) {
  var li = getLiFrom(label)
  var span = li.firstChild
  li.style.position = undefined
  // remove focus
  li.removeEventListener('click', focus)
  // remove hover
  span.classList.remove(css.activeMode)
  span.removeEventListener('mouseover', hover)
  span.removeEventListener('mouseout', hover)
}

function getLiFrom (label) {
  return label.parentElement.parentElement.parentElement
}

function getLabelFrom (li) {
  return li.children[0].children[1].children[0]
}

function removeSubtree (files, path) {
  var parts = path.split('/')
  var isFile = parts[parts.length - 1].length
  var removePaths = isFile ? [path] : Object.keys(files.list()).filter(keep)
  function keep (p) { return ~p.indexOf(path) }
  removePaths.forEach(function (path) {
    [...window.files.querySelectorAll('.file .name')].forEach(function (span) {
      if (span.innerText === path) {
        var li = span.parentElement
        li.parentElement.removeChild(li) // delete tab
      }
    })
    files.remove(path)
  })
}

function expandPathTo (li) {
  while ((li = li.parentElement.parentElement) && li.tagName === 'LI') {
    var caret = li.firstChild.firstChild
    if (caret.classList.contains('fa-caret-right')) caret.click() // expand
  }
}
<commit_msg>remove 'justify-content' from class ''activeMode'<commit_after>/* global FileReader, confirm, alert */
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var Treeview = require('ethereum-remix').ui.TreeView

var EventManager = require('../lib/eventManager')

var css = csjs`
  .fileexplorer       {
    box-sizing        : border-box;
  }
  .folder,
  .file               {
    font-size         : 14px;
  }
  .hasFocus           {
    background-color  : #F4F6FF;
  }
  .rename             {
    background-color  : white;
  }
  .remove             {
    align-self        : center;
    padding-left      : 10px;
  }
  .activeMode         {
    display           : flex;
    margin-right      : 10px;
    padding-right     : 19px;
  }
  ul                  {
    padding           : 0;
  }
`
module.exports = fileExplorer

function fileExplorer (appAPI, files) {
  var fileEvents = files.event
  var tv = new Treeview({
    extractData: function (value, tree, key) {
      var newValue = {}
      // var isReadOnly = false
      var isFile = false
      Object.keys(value).filter(function keep (x) {
        if (x === '/content') isFile = true
        // if (x === '/readOnly') isReadOnly = true
        if (x[0] !== '/') return true
      }).forEach(function (x) { newValue[x] = value[x] })
      return {
        path: (tree || {}).path ? tree.path + '/' + key : key,
        children: isFile ? undefined
        : value instanceof Array ? value.map((item, index) => ({
          key: index, value: item
        })) : value instanceof Object ? Object.keys(value).map(subkey => ({
          key: subkey, value: value[subkey]
        })) : undefined
      }
    },
    formatSelf: function (key, data) {
      return yo`${key}`
    }
  })

  var deleteButton = yo`

  `

  appAPI.event.register('currentFileChanged', (newFile) => {
    fileFocus(newFile)
  })
  fileEvents.register('fileRemoved', fileRemoved)
  fileEvents.register('fileRenamed', fileRenamed)
  fileEvents.register('fileAdded', fileAdded)

  var filepath = null
  var focusElement = null
  var textUnderEdit = null

  var element = tv.render(files.listAsTree())
  element.className = css.fileexplorer

  var api = new EventManager()
  api.addFile = function addFile (file) {
    var name = file.name
    if (!files.exists(name) || confirm('The file ' + name + ' already exists! Would you like to overwrite it?')) {
      var fileReader = new FileReader()
      fileReader.onload = function (event) {
        var success = files.set(name, event.target.result)
        if (!success) alert('Failed to create file ' + name)
        else api.trigger('focus', [name])
      }
      fileReader.readAsText(file)
    }
  }

  function focus (event) {
    event.cancelBubble = true
    var li = this
    if (focusElement === li) return
    if (focusElement) focusElement.classList.toggle(css.hasFocus)
    focusElement = li
    focusElement.classList.toggle(css.hasFocus)
    var label = getLabelFrom(li)
    var filepath = label.dataset.path
    var isFile = label.className.indexOf('file') === 0
    if (isFile) api.trigger('focus', [filepath])
  }

  function hover (event) {
    if (event.type === 'mouseout') {
      var exitedTo = event.toElement || event.relatedTarget
      if (this.contains(exitedTo)) return
      this.style.backgroundColor = ''
      this.style.paddingRight = '19px'
      return this.removeChild(deleteButton)
    }
    this.style.backgroundColor = '#F4F6FF'
    this.style.paddingRight = '0px'
    this.appendChild(deleteButton)
  }

  function getElement (path) {
    var label = element.querySelector(`label[data-path="${path}"]`)
    if (label) return getLiFrom(label)
  }

  function deletePath (event) {
    event.cancelBubble = true
    var span = this
    var li = span.parentElement.parentElement
    var label = getLabelFrom(li)
    var path = label.dataset.path
    var isFolder = !!~label.className.indexOf('folder')
    if (isFolder) path += '/'
    if (confirm(`Do you really want to delete "${path}" ?`)) {
      li.parentElement.removeChild(li)
      removeSubtree(files, path)
    }
  }

  function editModeOn (event) {
    var label = this
    var li = getLiFrom(label)
    var classes = li.className
    if (~classes.indexOf('hasFocus') && !label.getAttribute('contenteditable')) {
      textUnderEdit = label.innerText
      label.setAttribute('contenteditable', true)
      label.classList.add(css.rename)
      label.focus()
    }
  }

  function editModeOff (event) {
    var label = this
    if (event.type === 'blur' || event.which === 27 || event.which === 13) {
      var save = textUnderEdit !== label.innerText
      if (event.which === 13) event.preventDefault()
      if (save && event.which !== 13) save = confirm('Do you want to rename?')
      if (save) renameSubtree(label)
      else label.innerText = textUnderEdit
      label.removeAttribute('contenteditable')
      label.classList.remove(css.rename)
    }
  }

  function renameSubtree (label, dontcheck) {
    var oldPath = label.dataset.path
    var newPath = oldPath
    newPath = newPath.split('/')
    newPath[newPath.length - 1] = label.innerText
    newPath = newPath.join('/')
    if (!dontcheck) {
      var allPaths = Object.keys(files.list())
      for (var i = 0, len = allPaths.length, path, err; i < len; i++) {
        path = allPaths[i]
        if (files.isReadOnly(path)) {
          err = 'path contains readonly elements'
          break
        } else if (path.indexOf(newPath) === 0) {
          err = 'new path is conflicting with another existing path'
          break
        }
      }
    }
    if (err) {
      alert(`couldn't rename - ${err}`)
      label.innerText = textUnderEdit
    } else {
      textUnderEdit = label.innerText
      updateAllLabels([getElement(oldPath)], oldPath, newPath)
    }
  }

  function updateAllLabels (lis, oldPath, newPath) {
    lis.forEach(function (li) {
      var label = getLabelFrom(li)
      var path = label.dataset.path
      var newName = path.replace(oldPath, newPath)
      label.dataset.path = newName
      var isFile = label.className.indexOf('file') === 0
      if (isFile) files.rename(path, newName)
      var ul = li.lastChild
      if (ul.tagName === 'UL') {
        updateAllLabels([...ul.children], oldPath, newPath)
      }
    })
  }

  function fileFocus (path) {
    if (filepath === path) return
    filepath = path
    var el = getElement(filepath)
    expandPathTo(el)
    setTimeout(function focusNode () { el.click() }, 0)
  }

  function fileRemoved (filepath) {
    var li = getElement(filepath)
    if (li) li.parentElement.removeChild(li)
  }

  function fileRenamed (oldName, newName) {
    var li = getElement(oldName)
    if (li) {
      oldName = oldName.split('/')
      newName = newName.split('/')
      var index = oldName.reduce(function (idx, key, i) {
        return oldName[i] !== newName[i] ? i : idx
      }, undefined)
      var newKey = newName[index]
      var oldPath = oldName.slice(0, index + 1).join('/')
      li = getElement(oldPath)
      var label = getLabelFrom(li)
      label.innerText = newKey
      renameSubtree(label, true)
    }
  }

  function fileAdded (filepath) {
    var el = tv.render(files.listAsTree())
    el.className = css.fileexplorer
    element.parentElement.replaceChild(el, element)
    element = el
  }

  element.api = api
  return element
}
/******************************************************************************
  HELPER FUNCTIONS
******************************************************************************/
function adaptEnvironment (label, focus, hover) {
  var li = getLiFrom(label)
  li.style.position = 'relative'
  var span = li.firstChild
  // add focus
  li.addEventListener('click', focus)
  // add hover
  span.classList.add(css.activeMode)
  span.addEventListener('mouseover', hover)
  span.addEventListener('mouseout', hover)
}

function unadaptEnvironment (label, focus, hover) {
  var li = getLiFrom(label)
  var span = li.firstChild
  li.style.position = undefined
  // remove focus
  li.removeEventListener('click', focus)
  // remove hover
  span.classList.remove(css.activeMode)
  span.removeEventListener('mouseover', hover)
  span.removeEventListener('mouseout', hover)
}

function getLiFrom (label) {
  return label.parentElement.parentElement.parentElement
}

function getLabelFrom (li) {
  return li.children[0].children[1].children[0]
}

function removeSubtree (files, path) {
  var parts = path.split('/')
  var isFile = parts[parts.length - 1].length
  var removePaths = isFile ? [path] : Object.keys(files.list()).filter(keep)
  function keep (p) { return ~p.indexOf(path) }
  removePaths.forEach(function (path) {
    [...window.files.querySelectorAll('.file .name')].forEach(function (span) {
      if (span.innerText === path) {
        var li = span.parentElement
        li.parentElement.removeChild(li) // delete tab
      }
    })
    files.remove(path)
  })
}

function expandPathTo (li) {
  while ((li = li.parentElement.parentElement) && li.tagName === 'LI') {
    var caret = li.firstChild.firstChild
    if (caret.classList.contains('fa-caret-right')) caret.click() // expand
  }
}
<|endoftext|>


<commit_before>/*
This file gives functions to the CIF setup page.
*/

var lineupForm = "https://cdn.rawgit.com/ginshmastc/Volleyball-Bookkeeper/master/HTML/Lineups6p1l.html";

function lineups()
{
    var saved = [];
/*
    saved[0] = document.getElementById('teamA').value + "";
    saved[1] = document.getElementById('teamB').value + "";
    saved[2] = document.getElementById('sets').value + "";
    saved[3] = document.getElementById('playTo').value + "";
    saved[4] = document.getElementById('cap').value + "";
*/
saved[0] = "a;
    saved[1] = "b";
    saved[2] = "c";
    saved[3] = "d";
    saved[4] = "e";
    if(Android != null)
    {
        Android.addData(saved);
        Android.loadNextForm(lineupForm);
    }

}

<commit_msg>Update CIF_Setup1.1.js<commit_after>/*
This file gives functions to the CIF setup page.
*/

var lineupForm = "https://cdn.rawgit.com/ginshmastc/Volleyball-Bookkeeper/master/HTML/Lineups6p1l.html";

function lineups()
{
    var saved = [];
/*
    saved[0] = document.getElementById('teamA').value + "";
    saved[1] = document.getElementById('teamB').value + "";
    saved[2] = document.getElementById('sets').value + "";
    saved[3] = document.getElementById('playTo').value + "";
    saved[4] = document.getElementById('cap').value + "";
*/
saved[0] = "a";
    saved[1] = "b";
    saved[2] = "c";
    saved[3] = "d";
    saved[4] = "e";
    if(Android != null)
    {
        Android.addData(saved);
        Android.loadNextForm(lineupForm);
    }

}

<|endoftext|>