<commit_before>const webpackConfig = require('./webpack.config');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
var originalConfig = webpackConfig({});

module.exports = () => {
  let config = originalConfig;
  // output files without hashes
  config.output.filename = '[name].bundle.js';
  config.plugins.splice(config.plugins.indexOf(HtmlWebpackPlugin));
  config.plugins = [
    // first clean the output directory
    new CleanWebpackPlugin([config.output.path]),
    ...config.plugins
  ];

  return config;
};
<commit_msg>fix(javascriptservices): update configuration to set public path for static resources The webpack build moves files into the /dist/ folder and resources are loaded from the root '/' publicPath This adds a change to the webpack.netcore.config.js file that customizes webpack to work with javascript services by adding the publicPath to the url and file loaders.<commit_after>const webpackConfig = require('./webpack.config');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const project = require('./aurelia_project/aurelia.json');
var originalConfig = webpackConfig({});

module.exports = () => {
  let config = originalConfig;
  // output files without hashes
  config.output.filename = '[name].bundle.js';
  config.plugins.splice(config.plugins.indexOf(HtmlWebpackPlugin));
  // fix output path for .net core development
  config.module.rules = config.module.rules.map(x => {
    if (x.loader && (x.loader === 'url-loader' || x.loader === 'file-loader')) {
      if (!x.options) {
        x.options = {};
      }
      x.options.publicPath = project.platform.output.replace('wwwroot', '') + '/';
    }
    return x;
  });
  config.plugins = [
    // first clean the output directory
    new CleanWebpackPlugin([config.output.path]),
    ...config.plugins
  ];

  return config;
};
<|endoftext|>


<commit_before>'use strict';

angular.module('plates').controller('PlatesController', ['$scope', '$http', '$stateParams', '$location', '$window', 'ngDialog', 'Authentication', 'Plates', 'worklistFactory',
  function($scope, $http, $stateParams, $location, $window, ngDialog, Authentication, Plates, worklistFactory) {
    $scope.authentication = Authentication;

    $scope.authentication = Authentication;
    $scope.gridReady = false;
    $scope.grayOut = false;
    $scope.plateList = [];
    $scope.selectedPlate = null;
    $scope.error = '';
    // Tab flags
    $scope.unassignedTab = false;
    $scope.assignedTab = false;
    $scope.allTab = false;

    $scope.init = function(tab) {
      $scope.closeDialog();
      var url = '/plates';
      switch (tab) {
        case 'unassinged': $scope.unassignedTab = true; url = url.concat('/unassigned'); break;
        case 'assigned':   $scope.assignedTab = true; url = url.concat('/assigned'); break;
        case 'all':        $scope.allTab = true; break;
        default:           $scope.unassignedTab = true; url = url.concat('/unassigned'); break;
      }
      $http.get(url).success(function(response) {
        $scope.plateList = response;
        $scope.initReactGrid();
      }).error(function(err) {
        $scope.error = err.message;
        $scope.errorDialog();
      });
    };

    $scope.switchTab = function(tab) {
      $scope.unassignedTab = false;
      $scope.assignedTab = false;
      $scope.allTab = false;

      $scope.init(tab);
    };

    $scope.currentTab = function() {
      if ($scope.assignedTab) {
        return 'assigned';
      } else if ($scope.allTab) {
        return 'all';
      } else {
        return 'unassigned';
      }
    };

    $scope.initReactGrid = function() {
      // We set the gridReady to false here to force the DOM to update
      $scope.gridReady = false;
      $scope.grid.data = JSON.parse(JSON.stringify($scope.plateList));
      for (var plate = 0; plate < $scope.grid.data.length; ++plate) {
        // Make dates human readable
        $scope.grid.data[plate].project.due = new Date(Date.parse($scope.grid.data[plate].project.due)).toISOString().slice(0,10);
      }
      $scope.gridReady = true;
    };

    $scope.addPlate = function() {

      worklistFactory.addPlateToWorkList($scope.selectedPlate, function(err){
        if(err){
          $scope.error = err;
          $scope.errorDialog();
        } else{
          // Reload ngGrid & emit signal that a plate was added to update Work List plates assigned size in header
          $scope.$emit('workListUpdated');
          $scope.init($scope.currentTab());
        }
      });

    };

    $scope.confirmAdd = function() {
      $scope.closeDialog();
      ngDialog.open({
        template: 'addConfirmDialog',
        className: 'ngdialog-theme-default',
        scope: $scope,
        showClose: false
      });
      $scope.grayOut = true;
    };

    $scope.errorDialog = function() {
      // Save error
      var error = $scope.error;
      // Makes sure we'll never have two confirmation dialogs
      $scope.closeDialog();
      $scope.error = error;
      ngDialog.open({
        template: 'errorDialog',
        className: 'ngdialog-theme-default',
        scope: $scope,
        showClose: false
      });
      $scope.grayOut = true;
    };

    $scope.closeDialog = function() {
      ngDialog.closeAll();
      $scope.error = '';
      $scope.grayOut = false;
    };

    $scope.grid = {
      data: [],
      rowClick: function(plate) {
        console.log($scope.authentication);
        $scope.selectedPlate = plate;
        $scope.confirmAdd();
      },
      columnDefs: [{
        field: 'plateCode',
        displayName: 'Plate Code',
        width: '7%'
      }, {
        field: 'project.organism.name',
        displayName: 'Organism',
      }, {
        field: 'project.customer.name',
        displayName: 'Customer'
      }, {
        field: 'project.due',
        displayName: 'Due Date',
        width: '6%'
      }, {
        field: 'assignee.displayName',
        displayName: 'Assignee',
        width: '7%'
      }]
    };
  }
]);
<commit_msg>Redundany $scope.authentication in plates.client.controller<commit_after>'use strict';

angular.module('plates').controller('PlatesController', ['$scope', '$http', '$stateParams', '$location', '$window', 'ngDialog', 'Authentication', 'Plates', 'worklistFactory',
  function($scope, $http, $stateParams, $location, $window, ngDialog, Authentication, Plates, worklistFactory) {
    $scope.authentication = Authentication;
    $scope.gridReady = false;
    $scope.grayOut = false;
    $scope.plateList = [];
    $scope.selectedPlate = null;
    $scope.error = '';
    // Tab flags
    $scope.unassignedTab = false;
    $scope.assignedTab = false;
    $scope.allTab = false;

    $scope.init = function(tab) {
      $scope.closeDialog();
      var url = '/plates';
      switch (tab) {
        case 'unassinged': $scope.unassignedTab = true; url = url.concat('/unassigned'); break;
        case 'assigned':   $scope.assignedTab = true; url = url.concat('/assigned'); break;
        case 'all':        $scope.allTab = true; break;
        default:           $scope.unassignedTab = true; url = url.concat('/unassigned'); break;
      }
      $http.get(url).success(function(response) {
        $scope.plateList = response;
        $scope.initReactGrid();
      }).error(function(err) {
        $scope.error = err.message;
        $scope.errorDialog();
      });
    };

    $scope.switchTab = function(tab) {
      $scope.unassignedTab = false;
      $scope.assignedTab = false;
      $scope.allTab = false;

      $scope.init(tab);
    };

    $scope.currentTab = function() {
      if ($scope.assignedTab) {
        return 'assigned';
      } else if ($scope.allTab) {
        return 'all';
      } else {
        return 'unassigned';
      }
    };

    $scope.initReactGrid = function() {
      // We set the gridReady to false here to force the DOM to update
      $scope.gridReady = false;
      $scope.grid.data = JSON.parse(JSON.stringify($scope.plateList));
      for (var plate = 0; plate < $scope.grid.data.length; ++plate) {
        // Make dates human readable
        $scope.grid.data[plate].project.due = new Date(Date.parse($scope.grid.data[plate].project.due)).toISOString().slice(0,10);
      }
      $scope.gridReady = true;
    };

    $scope.addPlate = function() {

      worklistFactory.addPlateToWorkList($scope.selectedPlate, function(err){
        if(err){
          $scope.error = err;
          $scope.errorDialog();
        } else{
          // Reload ngGrid & emit signal that a plate was added to update Work List plates assigned size in header
          $scope.$emit('workListUpdated');
          $scope.init($scope.currentTab());
        }
      });

    };

    $scope.confirmAdd = function() {
      $scope.closeDialog();
      ngDialog.open({
        template: 'addConfirmDialog',
        className: 'ngdialog-theme-default',
        scope: $scope,
        showClose: false
      });
      $scope.grayOut = true;
    };

    $scope.errorDialog = function() {
      // Save error
      var error = $scope.error;
      // Makes sure we'll never have two confirmation dialogs
      $scope.closeDialog();
      $scope.error = error;
      ngDialog.open({
        template: 'errorDialog',
        className: 'ngdialog-theme-default',
        scope: $scope,
        showClose: false
      });
      $scope.grayOut = true;
    };

    $scope.closeDialog = function() {
      ngDialog.closeAll();
      $scope.error = '';
      $scope.grayOut = false;
    };

    $scope.grid = {
      data: [],
      rowClick: function(plate) {
        console.log($scope.authentication);
        $scope.selectedPlate = plate;
        $scope.confirmAdd();
      },
      columnDefs: [{
        field: 'plateCode',
        displayName: 'Plate Code',
        width: '7%'
      }, {
        field: 'project.organism.name',
        displayName: 'Organism',
      }, {
        field: 'project.customer.name',
        displayName: 'Customer'
      }, {
        field: 'project.due',
        displayName: 'Due Date',
        width: '6%'
      }, {
        field: 'assignee.displayName',
        displayName: 'Assignee',
        width: '7%'
      }]
    };
  }
]);
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React from 'react'
import {connect} from 'store'
import {getPrimitiveTypes, RecipeState} from './landCoverRecipe'
import styles from './legend.module.css'

const mapStateToProps = (state, ownProps) => {
    const recipeState = RecipeState(ownProps.recipeId)
    return {
        recipe: recipeState()
    }
}

class Legend extends React.Component {
    render() {
        const {recipe} = this.props
        return (

                {getPrimitiveTypes(recipe).map(type => this.renderPrimitiveType(type))}

        )
    }

    renderPrimitiveType(type) {
        console.log({type})
        return (
            <React.Fragment key={type.id}>

                {type.label}
            </React.Fragment>
        )
    }
}

Legend.propTypes = {
    recipeId: PropTypes.string.isRequired
}

export default connect(mapStateToProps)(Legend)
<commit_msg>Removed debug logging.<commit_after>import PropTypes from 'prop-types'
import React from 'react'
import {connect} from 'store'
import {getPrimitiveTypes, RecipeState} from './landCoverRecipe'
import styles from './legend.module.css'

const mapStateToProps = (state, ownProps) => {
    const recipeState = RecipeState(ownProps.recipeId)
    return {
        recipe: recipeState()
    }
}

class Legend extends React.Component {
    render() {
        const {recipe} = this.props
        return (

                {getPrimitiveTypes(recipe).map(type => this.renderPrimitiveType(type))}

        )
    }

    renderPrimitiveType(type) {
        return (
            <React.Fragment key={type.id}>

                {type.label}
            </React.Fragment>
        )
    }
}

Legend.propTypes = {
    recipeId: PropTypes.string.isRequired
}

export default connect(mapStateToProps)(Legend)
<|endoftext|>


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

  angular
    .module('notifs')
    .controller('NotifsListController', NotifsListController);

  NotifsListController.$inject = [
    '$scope',
    'NotifsApi',
    'Authentication',
    '$filter',
    'toastr',
    'ngDialog'
  ];

  function NotifsListController(
    $scope,
    NotifsApi,
    Authentication,
    $filter,
    toast,
    dialog
  ) {
    var vm = this;
    vm.notifs = [];

    // Infinity scroll
    $scope.stopped = false;
    $scope.busy = false;
    $scope.page = 0;
    vm.get_notifs = get_notifs;
    function get_notifs() {
      if ($scope.stopped || $scope.busy) return;
      $scope.busy = true;
      NotifsApi.findNotifs(10, $scope.page)
        .then(res => {
          if (!res.data.length || res.data.length === 0) {
            $scope.stopped = true;
            $scope.busy = false;
            return;
          }
          vm.notifs = _.union(vm.notifs, res.data);
          console.log(vm.notifs);
          $scope.page += 1;
          $scope.busy = false;
        })
        .catch(err => {
          $scope.busy = false;
          $scope.stopped = true;
          toast.error('There were problems get your notifications.', 'Error!');
        });
    }
  }
}());
<commit_msg>Commited from lenh at Tue, Aug 15, 2017  9:18:37 AM<commit_after>(function () {
  'use strict';

  angular
    .module('notifs')
    .controller('NotifsListController', NotifsListController);

  NotifsListController.$inject = [
    '$scope',
    'NotifsApi',
    'Authentication',
    '$filter',
    'toastr',
    'ngDialog'
  ];

  function NotifsListController(
    $scope,
    NotifsApi,
    Authentication,
    $filter,
    toast,
    dialog
  ) {
    var vm = this;
    vm.notifs = [];

    // Infinity scroll
    $scope.stopped = false;
    $scope.busy = false;
    $scope.page = 0;
    $scope.get_notifs = get_notifs;
    function get_notifs() {
      if ($scope.stopped || $scope.busy) return;
      $scope.busy = true;
      NotifsApi.findNotifs(10, $scope.page)
        .then(res => {
          if (!res.data.length || res.data.length === 0) {
            $scope.stopped = true;
            $scope.busy = false;
            return;
          }
          vm.notifs = _.union(vm.notifs, res.data);
          console.log(vm.notifs);
          $scope.page += 1;
          $scope.busy = false;
        })
        .catch(err => {
          $scope.busy = false;
          $scope.stopped = true;
          toast.error('There were problems get your notifications.', 'Error!');
        });
    }
  }
}());
<|endoftext|>


<commit_before>'use strict';

angular.module('projects')
	// General
	.controller('controllerProjectsList', controllerProjectsList)
	.controller('controllerProjectsList2', controllerProjectsList2)
	.controller('controllerProjectsSearch', controllerProjectsSearch);

// -----------------------------------------------------------------------------------
//
// CONTROLLER: Projects
//
// -----------------------------------------------------------------------------------
controllerProjectsSearch.$inject = ['$scope', '$state', 'Authentication', 'ProjectModel', '$rootScope', 'PROJECT_TYPES', 'REGIONS', 'PROJECT_STATUS_PUBLIC', 'PhaseBaseModel'];
/* @ngInject */
function controllerProjectsSearch($scope, $state, Authentication, ProjectModel, $rootScope, PROJECT_TYPES, REGIONS, PROJECT_STATUS_PUBLIC, sPhaseBaseModel) {
	var projectsSearch = this;

	sPhaseBaseModel.getCollection().then( function(data) {
		projectsSearch.phases = data;
	});
	projectsSearch.types = PROJECT_TYPES;
	projectsSearch.regions = REGIONS;
	projectsSearch.status = PROJECT_STATUS_PUBLIC;

	projectsSearch.foundSet = false;
	projectsSearch.projects = [];

	projectsSearch.resetSearch = function() {
		projectsSearch.search = undefined;
		projectsSearch.foundSet = false;
	};

	projectsSearch.performSearch = function() {
		var query = {};

		if (projectsSearch.search.Permit)  {
			query.memPermitID = projectsSearch.search.Permit;
		}
		if (projectsSearch.search.type)  {
			query.type = projectsSearch.search.type;
		}
		if (projectsSearch.search.region)  {
			query.region = projectsSearch.search.region;
		}
		if (projectsSearch.search.status)  {
			query.status = projectsSearch.search.status;
		}
		if (projectsSearch.search.keywords) {
			query.keywords = {'$in': projectsSearch.search.keywords.split(' ') };
		}

		ProjectModel.getQuery (query).then( function(data) {
			projectsSearch.projects = [];
			projectsSearch.foundSet = true;
		}).catch( function(err) {
			projectsSearch.error = err;
		});
	};

}

// -----------------------------------------------------------------------------------
//
// CONTROLLER: Projects
//
// -----------------------------------------------------------------------------------
controllerProjectsList.$inject = ['$scope', 'Authentication', '_', 'uiGmapGoogleMapApi', '$filter'];
/* @ngInject */
function controllerProjectsList($scope, Authentication, _, uiGmapGoogleMapApi, $filter) {
	var projectList = this;

	// The "then" callback function provides the google.maps object.
	uiGmapGoogleMapApi.then(function(maps) {
		projectList.map = {
			center: {
				latitude: 54.726668,
				longitude: -127.647621
			},
			zoom: 5,
			options: {
				scrollwheel: false,
				minZoom: 4
			},
			markers: projectList.projectsFiltered, // array of models to display
			markersEvents: {
				click: function(marker, eventName, model) {
					projectList.map.window.model = model;
					projectList.map.window.show = true;
				}
			},
			window: {
				marker: {},
				show: false,
				closeClick: function() {
					this.show = false;
				},
				options: {
					// offset to fit the custom icon
    					pixelOffset: new maps.Size(0, -35, 'px', 'px')
				} // define when map is ready
			},
			clusterOptions: {
				calculator : function(markers, numStyles) {
					var changeAt = 500;
					var index = 0;
					var count = markers.length;
					var dv = count;
					while (dv !== 0) {
						dv = parseInt(dv / changeAt, 10);
						index++;
					}
					index = Math.min(index, numStyles);
					return {
						text: count,
						index: index
					};
				}
			}
		};
	});

	projectList.showInfoWindow = function(marker, event, model) {
		$scope.infoWin = model;
		$scope.infoWin.show = true;
	};

	$scope.$parent.$watch('filterObj', function(newValue) {
		if (!_.isEmpty(newValue)) {
			projectList.projectsFiltered = $filter("filter")(projectList.projects, function (item) {
				var notFound = false;
				if ( !newValue['currentPhase.name']
					|| (angular.lowercase(item.currentPhase.name).indexOf(angular.lowercase(newValue['currentPhase.name']))) > -1
					|| item.currentPhase.name === "") {
					// console.log("cur:",item.currentPhase.name);
				} else {
					notFound = true;
				}
				if ( !newValue['region']
					|| (angular.lowercase(item.region).indexOf(angular.lowercase(newValue['region']))) > -1
					|| item.region === "") {
					// console.log("cur:",item.region);
				} else {
					notFound = true;
				}
				if ( !newValue['type']
					|| (angular.lowercase(item.type).indexOf(angular.lowercase(newValue['type']))) > -1
					|| item.type === "") {
					// console.log("cur:",item.type);
				} else {
					notFound = true;
				}
				if ( !newValue['name']
					|| (angular.lowercase(item.name).indexOf(angular.lowercase(newValue['name']))) > -1
					|| item.name === "") {
					// console.log("cur:",item.name);
				} else {
					notFound = true;
				}
				if ( !newValue['memPermitID']
					|| (angular.lowercase(item.name).indexOf(angular.lowercase(newValue['memPermitID']))) > -1
					|| item.memPermitID === "") {
					// console.log("cur:",item.name);
				} else {
					notFound = true;
				}
				if (!notFound) return item;
			});
		}
	}, true);

	projectList.clearFilter = function() {
		$scope.$parent.filterObj = undefined;
		// console.log($scope.$parent.filterObj);
	};

	// projectList.types = PROJECT_TYPES;
	// projectList.regions = REGIONS;
	// projectList.status = PROJECT_STATUS_PUBLIC;

	projectList.auth = Authentication;

	$scope.$watch('projects', function(newValue) {
		if (newValue) {
			projectList.projects = newValue;
			projectList.projectsFiltered = $filter("filter")(newValue, $scope.$parent.filterObj);
		}
	});
}
// -----------------------------------------------------------------------------------
//
// CONTROLLER: Projects List 2
//
// -----------------------------------------------------------------------------------
controllerProjectsList2.$inject = ['$scope', 'NgTableParams', 'Authentication', '_', 'ENV', 'PROJECT_TYPES', 'REGIONS', 'PROJECT_STATUS_PUBLIC', '$filter'];
/* @ngInject */
function controllerProjectsList2($scope, NgTableParams, Authentication, _, ENV, PROJECT_TYPES, REGIONS, PROJECT_STATUS_PUBLIC, $filter) {
	var projectList = this;

	$scope.environment = ENV;

	projectList.auth = Authentication;

	projectList.regionArray = [];
	projectList.statusArray = [];
	projectList.typeArray = [];

	$scope.$watch('projects', function(newValue) {
		if (newValue) {
			// add a pos for the map display
			projectList.projects = _.map(newValue, function(item) {
				item.latitude = item.lat;
				item.longitude = item.lon;
				return item;
			});

			var projs = _(angular.copy(newValue)).chain().flatten();
			projs.pluck('region').unique().value().map( function(item) {
				projectList.regionArray.push({id: item, title: $filter('regionName')(item)});
			});
			projs.pluck('status').unique().value().map( function(item) {
				projectList.statusArray.push({id: item, title: item});
			});
			projs.pluck('type').unique().value().map( function(item) {
				projectList.typeArray.push({id: item, title: item});
			});
			if ($scope.$parent.filterObj) {
				projectList.tableParams = new NgTableParams ({
					count: 10,
					filter: $scope.$parent.filterObj
				}, {dataset: newValue});
			} else {
				projectList.tableParams = new NgTableParams ({
					count: 10,
				}, {dataset: newValue});
			}
		}
	});

}

// -----------------------------------------------------------------------------------
//
// CONTROLLER: User Activities
//
// -----------------------------------------------------------------------------------
// controllerUserActivities.$inject = ['$scope', '$state', 'Authentication', 'ProjectModel', 'ActivityModel', '$rootScope', '_'];
// /* @ngInject */
// function controllerUserActivities($scope, $state, Authentication, ProjectModel, sActivityModel, $rootScope, _) {
// 	var userActs = this;
// 	userActs.projectNames = {};

// 	userActs.refresh = function() {
// 		sActivityModel.userActivities(undefined, 'read').then( function(data) {
// 			userActs.activities = data;
// 			$scope.$apply ();
// 		}).catch( function(err) {
// 			$scope.error = err;
// 		});
// 	};

// 	ProjectModel.getCollection().then( function(data) {
// 		userActs.projects = data;

// 		// reference the ID and the name.
// 		_.each(data, function(project) {
// 			userActs.projectNames[project._id] = {'name': project.name, 'region': project.region};
// 		});
// 		$scope.$apply();
// 	});

// 	userActs.refresh();
// }

<commit_msg>Fix while parked.  Lint errors<commit_after>'use strict';

angular.module('projects')
	// General
	.controller('controllerProjectsList', controllerProjectsList)
	.controller('controllerProjectsList2', controllerProjectsList2)
	.controller('controllerProjectsSearch', controllerProjectsSearch);

// -----------------------------------------------------------------------------------
//
// CONTROLLER: Projects
//
// -----------------------------------------------------------------------------------
controllerProjectsSearch.$inject = ['$scope', '$state', 'Authentication', 'ProjectModel', '$rootScope', 'PROJECT_TYPES', 'REGIONS', 'PROJECT_STATUS_PUBLIC', 'PhaseBaseModel'];
/* @ngInject */
function controllerProjectsSearch($scope, $state, Authentication, ProjectModel, $rootScope, PROJECT_TYPES, REGIONS, PROJECT_STATUS_PUBLIC, sPhaseBaseModel) {
	var projectsSearch = this;

	sPhaseBaseModel.getCollection().then( function(data) {
		projectsSearch.phases = data;
	});
	projectsSearch.types = PROJECT_TYPES;
	projectsSearch.regions = REGIONS;
	projectsSearch.status = PROJECT_STATUS_PUBLIC;

	projectsSearch.foundSet = false;
	projectsSearch.projects = [];

	projectsSearch.resetSearch = function() {
		projectsSearch.search = undefined;
		projectsSearch.foundSet = false;
	};

	projectsSearch.performSearch = function() {
		var query = {};

		if (projectsSearch.search.Permit)  {
			query.memPermitID = projectsSearch.search.Permit;
		}
		if (projectsSearch.search.type)  {
			query.type = projectsSearch.search.type;
		}
		if (projectsSearch.search.region)  {
			query.region = projectsSearch.search.region;
		}
		if (projectsSearch.search.status)  {
			query.status = projectsSearch.search.status;
		}
		if (projectsSearch.search.keywords) {
			query.keywords = {'$in': projectsSearch.search.keywords.split(' ') };
		}

		ProjectModel.getQuery (query).then( function(data) {
			projectsSearch.projects = [];
			projectsSearch.foundSet = true;
		}).catch( function(err) {
			projectsSearch.error = err;
		});
	};

}

// -----------------------------------------------------------------------------------
//
// CONTROLLER: Projects
//
// -----------------------------------------------------------------------------------
controllerProjectsList.$inject = ['$scope', 'Authentication', '_', 'uiGmapGoogleMapApi', '$filter'];
/* @ngInject */
function controllerProjectsList($scope, Authentication, _, uiGmapGoogleMapApi, $filter) {
	var projectList = this;

	// The "then" callback function provides the google.maps object.
	uiGmapGoogleMapApi.then(function(maps) {
		projectList.map = {
			center: {
				latitude: 54.726668,
				longitude: -127.647621
			},
			zoom: 5,
			options: {
				scrollwheel: false,
				minZoom: 4
			},
			markers: projectList.projectsFiltered, // array of models to display
			markersEvents: {
				click: function(marker, eventName, model) {
					projectList.map.window.model = model;
					projectList.map.window.show = true;
				}
			},
			window: {
				marker: {},
				show: false,
				closeClick: function() {
					this.show = false;
				},
				options: {
					// offset to fit the custom icon
    					pixelOffset: new maps.Size(0, -35, 'px', 'px')
				} // define when map is ready
			},
			clusterOptions: {
				calculator : function(markers, numStyles) {
					var changeAt = 500;
					var index = 0;
					var count = markers.length;
					var dv = count;
					while (dv !== 0) {
						dv = parseInt(dv / changeAt, 10);
						index++;
					}
					index = Math.min(index, numStyles);
					return {
						text: count,
						index: index
					};
				}
			}
		};
	});

	projectList.showInfoWindow = function(marker, event, model) {
		$scope.infoWin = model;
		$scope.infoWin.show = true;
	};

	$scope.$parent.$watch('filterObj', function(newValue) {
		if (!_.isEmpty(newValue)) {
			projectList.projectsFiltered = $filter("filter")(projectList.projects, function (item) {
				var notFound = false;
				if ( !newValue['currentPhase.name'] || (angular.lowercase(item.currentPhase.name).indexOf(angular.lowercase(newValue['currentPhase.name']))) > -1 || item.currentPhase.name === "") {
					// console.log("cur:",item.currentPhase.name);
				} else {
					notFound = true;
				}
				if ( !newValue.region || (angular.lowercase(item.region).indexOf(angular.lowercase(newValue.region))) > -1 || item.region === "") {
					// console.log("cur:",item.region);
				} else {
					notFound = true;
				}
				if ( !newValue.type || (angular.lowercase(item.type).indexOf(angular.lowercase(newValue.type))) > -1 || item.type === "") {
					// console.log("cur:",item.type);
				} else {
					notFound = true;
				}
				if ( !newValue.name || (angular.lowercase(item.name).indexOf(angular.lowercase(newValue.name))) > -1 || item.name === "") {
					// console.log("cur:",item.name);
				} else {
					notFound = true;
				}
				if ( !newValue.memPermitID || (angular.lowercase(item.name).indexOf(angular.lowercase(newValue.memPermitID))) > -1 || item.memPermitID === "") {
					// console.log("cur:",item.name);
				} else {
					notFound = true;
				}
				if (!notFound) return item;
			});
		}
	}, true);

	projectList.clearFilter = function() {
		$scope.$parent.filterObj = undefined;
		// console.log($scope.$parent.filterObj);
	};

	// projectList.types = PROJECT_TYPES;
	// projectList.regions = REGIONS;
	// projectList.status = PROJECT_STATUS_PUBLIC;

	projectList.auth = Authentication;

	$scope.$watch('projects', function(newValue) {
		if (newValue) {
			projectList.projects = newValue;
			projectList.projectsFiltered = $filter("filter")(newValue, $scope.$parent.filterObj);
		}
	});
}
// -----------------------------------------------------------------------------------
//
// CONTROLLER: Projects List 2
//
// -----------------------------------------------------------------------------------
controllerProjectsList2.$inject = ['$scope', 'NgTableParams', 'Authentication', '_', 'ENV', 'PROJECT_TYPES', 'REGIONS', 'PROJECT_STATUS_PUBLIC', '$filter'];
/* @ngInject */
function controllerProjectsList2($scope, NgTableParams, Authentication, _, ENV, PROJECT_TYPES, REGIONS, PROJECT_STATUS_PUBLIC, $filter) {
	var projectList = this;

	$scope.environment = ENV;

	projectList.auth = Authentication;

	projectList.regionArray = [];
	projectList.statusArray = [];
	projectList.typeArray = [];

	$scope.$watch('projects', function(newValue) {
		if (newValue) {
			// add a pos for the map display
			projectList.projects = _.map(newValue, function(item) {
				item.latitude = item.lat;
				item.longitude = item.lon;
				return item;
			});

			var projs = _(angular.copy(newValue)).chain().flatten();
			projs.pluck('region').unique().value().map( function(item) {
				projectList.regionArray.push({id: item, title: $filter('regionName')(item)});
			});
			projs.pluck('status').unique().value().map( function(item) {
				projectList.statusArray.push({id: item, title: item});
			});
			projs.pluck('type').unique().value().map( function(item) {
				projectList.typeArray.push({id: item, title: item});
			});
			if ($scope.$parent.filterObj) {
				projectList.tableParams = new NgTableParams ({
					count: 10,
					filter: $scope.$parent.filterObj
				}, {dataset: newValue});
			} else {
				projectList.tableParams = new NgTableParams ({
					count: 10,
				}, {dataset: newValue});
			}
		}
	});

}

// -----------------------------------------------------------------------------------
//
// CONTROLLER: User Activities
//
// -----------------------------------------------------------------------------------
// controllerUserActivities.$inject = ['$scope', '$state', 'Authentication', 'ProjectModel', 'ActivityModel', '$rootScope', '_'];
// /* @ngInject */
// function controllerUserActivities($scope, $state, Authentication, ProjectModel, sActivityModel, $rootScope, _) {
// 	var userActs = this;
// 	userActs.projectNames = {};

// 	userActs.refresh = function() {
// 		sActivityModel.userActivities(undefined, 'read').then( function(data) {
// 			userActs.activities = data;
// 			$scope.$apply ();
// 		}).catch( function(err) {
// 			$scope.error = err;
// 		});
// 	};

// 	ProjectModel.getCollection().then( function(data) {
// 		userActs.projects = data;

// 		// reference the ID and the name.
// 		_.each(data, function(project) {
// 			userActs.projectNames[project._id] = {'name': project.name, 'region': project.region};
// 		});
// 		$scope.$apply();
// 	});

// 	userActs.refresh();
// }

<|endoftext|>


<commit_before>require('backbone-base');

var
  _ = require('lodash'),
  backbone = require('backbone'),
  BaseModalView = require('../base/modal');

module.exports = backbone.BaseListView.extend(BaseModalView.prototype).extend({
  ItemView: backbone.BaseView.extend({
    attributes: {class: 'result panel panel-default'},

    render: function() {
      this.$el.html(this.template(_.extend(this.model.toJSON(), {
        isheader: this.model.get('row_index') === 0
      })));

      return this;
    },

    template: window.TEMPLATES['create-dp/validation-report-item.hbs']
  }),

  render: function() { this.$el.html(this.template(this.errors)); return this; },

  reset: function(errors) {
    this.errors = errors;
    console.log(errors);

    backbone.BaseListView.prototype.reset.call(this, new backbone.Collection(
      _.map(this.errors, function(error) { return _.values(error)[0]; })
    ));

    return this;
  },

  template: window.TEMPLATES['create-dp/validation-report.hbs']
});<commit_msg>Removed debug<commit_after>require('backbone-base');

var
  _ = require('lodash'),
  backbone = require('backbone'),
  BaseModalView = require('../base/modal');

module.exports = backbone.BaseListView.extend(BaseModalView.prototype).extend({
  ItemView: backbone.BaseView.extend({
    attributes: {class: 'result panel panel-default'},

    render: function() {
      this.$el.html(this.template(_.extend(this.model.toJSON(), {
        isheader: this.model.get('row_index') === 0
      })));

      return this;
    },

    template: window.TEMPLATES['create-dp/validation-report-item.hbs']
  }),

  render: function() { this.$el.html(this.template(this.errors)); return this; },

  reset: function(errors) {
    this.errors = errors;

    backbone.BaseListView.prototype.reset.call(this, new backbone.Collection(
      _.map(this.errors, function(error) { return _.values(error)[0]; })
    ));

    return this;
  },

  template: window.TEMPLATES['create-dp/validation-report.hbs']
});<|endoftext|>


<commit_before>const elasticClient = require('./helpers/db.js')
const passwordHash = require('password-hash')
const logger = require('../log/logger')

let doLogin = (login, password) => {
  logger.info(`Check if user ${login} can login`)
  if (!login || !password) {
    throw 'Invalid params'
  }
  return findByLogin(login, true).then(user => {
      if (!passwordHash.verify(password, user.hash)) {
        throw 'Wrong credentionals'
      }
      return Promise.resolve(user)
    },
    error => {
      throw error
    }
  )
}

let _findById = userId => new Promise((resolve, reject) => {
  logger.info(`Find user by ID ${userId}`)
  if (!userId) {
    return reject('Invalid ID')
  }
  elasticClient.search({
    index: 'dharmadict',
    type: 'users',
    body: {
      query: {
        ids: {
          values: [userId]
        }
      }
    }
  }).then(response => {
    const result = response.hits.hits[0]
    if (!result || !result._source) {
      return reject('No ID found')
    }
    result._source.id = result._id
    return resolve(result._source)
  },
  error => {
    logger.error(error)
    return reject('Database error')
  })
})

let findByLogin = userLogin => new Promise((resolve, reject) => {
  logger.info(`Find user by login ${userLogin}`)
  if (!userLogin) {
    return reject('Invalid login')
  }
  elasticClient.search({
    index: 'dharmadict',
    type: 'users',
    body: {
      query: {
        match: {
          login: userLogin
        }
      }
    }
  }).then(response => {
    const result = response.hits.hits[0]
    if (!result || !result._source) {
      return reject('No login found')
    }
    result._source.id = result._id
    return resolve(result._source)
  }, error => {
    logger.error(error.message)
    return reject('Database error')
  })
})

let findAll = () => new Promise((resolve, reject) => {
  logger.info(`Find all users`)
  elasticClient.search({
    index: 'dharmadict',
    type: 'users',
    body: {}
  }).then(result => {
    let users = result.hits.hits
    if (!users.length) {
      return reject(`Can't find all users`)
    }
    logger.info('A users was found')
    return resolve(users)
  }, error => {
    logger.error(error.message)
    return reject('Database error')
  })
})
.then(users => {  // perfection of data
  users = users.map(elem => {
    let cleanUserInfo = elem._source
    cleanUserInfo.id = elem._id
    return getUserInfo(cleanUserInfo)
  })
  return Promise.resolve(users)
})

let create = newUser => new Promise((resolve, reject) => {
  // data validation
  if (!newUser) {
    return reject('Error in create user. Invalid data')
  }
  if (!newUser.id) {
    return reject('Error in create user. Invalid id')
  }
  if (!newUser.role) {
    return reject('Error in create user. Invalid role')
  }
  if (!newUser.roleId) {
    return reject('Error in create user. Invalid roleId')
  }
  if (!newUser.login) {
    return reject('Error in create user. Invalid login')
  }
  if (!newUser.name) {
    return reject('Error in create user. Invalid name')
  }
  if (!newUser.password) {
    return reject('Error in create user. Invalid password')
  }
  if (!newUser.description) {
    return reject('Error in create user. Invalid description')
  }
  newUser.hash = passwordHash.generate(newUser.password)
  let userId = newUser.id
  delete newUser.password
  delete newUser.id
  return resolve({ newUser, userId })
})
.then(data =>  // check login uniqueness
  findByLogin(data.newUser.login).then(
    result => {
      throw `Login not unique`
    },
    error => Promise.resolve(data)
  )
)
.then(data =>  // check id uniqueness)
  _findById(data.userId).then(
    result => {
      throw `Id not unique`
    },
    error => Promise.resolve(data)
  )
)
.then(data =>  // Adding new user
  elasticClient.index({
    index: 'dharmadict',
    type: 'users',
    id: data.userId,
    body: data.newUser
  }).then(result => {
    logger.info('User was successfully created')
    return Promise.resolve({
      success: true
    })
  }, error => {
    logger.error(error.message)
    throw `Create user error`
  })
)

let removeById = userId => new Promise((resolve, reject) => {
  if (!userId) {
    return reject('Error in delete user. Invalid id')
  }
  elasticClient.delete({
    index: 'dharmadict',
    type: 'users',
    id: userId
  }).then(response => {
    logger.info('User was deleted')
    return resolve({
      success: true
    })
  }, error => {
    logger.error(error.message)
    return reject('Delete user error')
  })
})

let getUserInfo = user => ({
  id: user.id,
  name: user.name,
  login: user.login,
  role: user.role,
  roleId: user.roleId,
  description: user.description
})

module.exports = {
  getUserInfo,
  doLogin,
  findByLogin,
  findAll,
  create,
  removeById
}
<commit_msg>Add comments<commit_after>const elasticClient = require('./helpers/db.js')
const passwordHash = require('password-hash')
const logger = require('../log/logger')

let doLogin = (login, password) => {
  logger.info(`Check if user ${login} can login`)
  if (!login || !password) {
    throw 'Invalid params'
  }
  return findByLogin(login, true).then(user => {
      if (!passwordHash.verify(password, user.hash)) {
        throw 'Wrong credentionals'
      }
      return Promise.resolve(user)
    },
    error => {
      throw error
    }
  )
}

let _findById = userId => new Promise((resolve, reject) => {
  logger.info(`Find user by ID ${userId}`)
  if (!userId) {
    return reject('Invalid ID')
  }
  elasticClient.search({
    index: 'dharmadict',
    type: 'users',
    body: {
      query: {
        ids: {
          values: [userId]
        }
      }
    }
  }).then(response => {
    const result = response.hits.hits[0]
    if (!result || !result._source) {
      return reject('No ID found')
    }
    result._source.id = result._id
    return resolve(result._source)
  },
  error => {
    logger.error(error)
    return reject('Database error')
  })
})

let findByLogin = userLogin => new Promise((resolve, reject) => {
  logger.info(`Find user by login ${userLogin}`)
  if (!userLogin) {
    return reject('Invalid login')
  }
  elasticClient.search({
    index: 'dharmadict',
    type: 'users',
    body: {
      query: {
        match: {
          login: userLogin
        }
      }
    }
  }).then(response => {
    const result = response.hits.hits[0]
    if (!result || !result._source) {
      return reject('No login found')
    }
    result._source.id = result._id
    return resolve(result._source)
  }, error => {
    logger.error(error.message)
    return reject('Database error')
  })
})

let findAll = () => new Promise((resolve, reject) => {
  logger.info(`Find all users`)
  elasticClient.search({
    index: 'dharmadict',
    type: 'users',
    body: {}
  }).then(result => {
    let users = result.hits.hits
    if (!users.length) {
      return reject(`Can't find all users`)
    }
    logger.info('A users was found')
    return resolve(users)
  }, error => {
    logger.error(error.message)
    return reject('Database error')
  })
})
.then(users => {  // perfection of data
  users = users.map(elem => {
    let cleanUserInfo = elem._source
    cleanUserInfo.id = elem._id
    return getUserInfo(cleanUserInfo)
  })
  return Promise.resolve(users)
})

let create = newUser => new Promise((resolve, reject) => {
  // data validation
  if (!newUser) {
    return reject('Error in create user. Invalid data')
  }
  if (!newUser.id) {
    return reject('Error in create user. Invalid id')
  }
  if (!newUser.role) {
    return reject('Error in create user. Invalid role')
  }
  if (!newUser.roleId) {
    return reject('Error in create user. Invalid roleId')
  }
  if (!newUser.login) {
    return reject('Error in create user. Invalid login')
  }
  if (!newUser.name) {
    return reject('Error in create user. Invalid name')
  }
  if (!newUser.password) {
    return reject('Error in create user. Invalid password')
  }
  if (!newUser.description) {
    return reject('Error in create user. Invalid description')
  }
  newUser.hash = passwordHash.generate(newUser.password)
  let userId = newUser.id
  delete newUser.password
  delete newUser.id
  return resolve({ newUser, userId })
})
.then(data =>  // check login uniqueness
  findByLogin(data.newUser.login).then(
    result => {
      throw `Login not unique`
    },
    error => {
      // The error should mean the absence of data.
      // And correspond to the message about this error in the method findByLogin.
      if (error == 'No login found') {
        return Promise.resolve(data)
      }
    }
  )
)
.then(data =>  // check id uniqueness)
  _findById(data.userId).then(
    result => {
      throw `Id not unique`
    },
    error => {
      // The error should mean the absence of data.
      // And correspond to the message about this error in the method _findById.
      if (error == 'No ID found') {
        return Promise.resolve(data)
      }
    }
  )
)
.then(data =>  // Adding new user
  elasticClient.index({
    index: 'dharmadict',
    type: 'users',
    id: data.userId,
    body: data.newUser
  }).then(result => {
    logger.info('User was successfully created')
    return Promise.resolve({
      success: true
    })
  }, error => {
    logger.error(error.message)
    throw `Create user error`
  })
)

let removeById = userId => new Promise((resolve, reject) => {
  if (!userId) {
    return reject('Error in delete user. Invalid id')
  }
  elasticClient.delete({
    index: 'dharmadict',
    type: 'users',
    id: userId
  }).then(response => {
    logger.info('User was deleted')
    return resolve({
      success: true
    })
  }, error => {
    logger.error(error.message)
    return reject('Delete user error')
  })
})

let getUserInfo = user => ({
  id: user.id,
  name: user.name,
  login: user.login,
  role: user.role,
  roleId: user.roleId,
  description: user.description
})

module.exports = {
  getUserInfo,
  doLogin,
  findByLogin,
  findAll,
  create,
  removeById
}
<|endoftext|>


<commit_before>/*
Widget complements Autocomplete by enabling autocompletes to be used as
value holders. It looks very much like Autocomplete in its design. Thus, it
is recommended to read the source of Autocomplete first.

Widget behaves like the autocomplete in facebook profile page, which all
users should be able to use.

Behind the scenes, Widget maintains a normal hidden select which makes it
simple to play with on the server side like on the client side. If a value
is added and selected in the select element, then it is added to the deck,
and vice-versa.

It needs some elements, and established vocabulary:

- ".autocomplete-light-widget" element wraps all the HTML necessary for the
 widget,
- ".deck" contains the list of selected choice(s) as HTML,
- "input" should be the text input that has the Autocomplete,
- "select" a (optionnaly multiple) select
- ".remove" a (preferabely hidden) element that contains a value removal
 indicator, like an "X" sign or a trashcan icon, it is used to prefix every
 children of the deck
- ".choice-template" a (preferabely hidden) element that contains the template
 for choices which are added directly in the select, as they should be
 copied in the deck,

To avoid complexity, this script relies on extra HTML attributes, and
particularely one called 'data-value'. Learn more about data attributes:
http://dev.w3.org/html5/spec/global-attributes.html#embedding-custom-non-visible-data-with-the-data-attributes

When a choice is selected from the Autocomplete, its element is cloned
and appended to the deck - "deck" contains "choices". It is important that the
choice elements of the autocomplete all contain a data-value attribute.
The value of data-value is used to fill the selected options in the hidden
select field.

If choices may not all have a data-value attribute, then you can
override Widget.getValue() to implement your own logic.
*/

// Our class will live in the yourlabs global namespace.
if (window.yourlabs == undefined) window.yourlabs = {};

/*
Instanciate a Widget.
*/
yourlabs.Widget = function(widget) {
    // These attributes where described above.
    this.widget = widget;
    this.input = this.widget.find('input');
    this.select = this.widget.find('select');
    this.deck = this.widget.find('.deck');
    this.choiceTemplate = this.widget.find('.choice-template .choice');

    // The number of choices that the user may select with this widget. Set 0
    // for no limit. In the case of a foreign key you want to set it to 1.
    this.maxValues = 0;

    // When a choice is selected from the autocomplete of this widget,
    // getValue() is called to add and select the option in the select.
    this.getValue = function(choice) {
        return choice.attr('data-value');
    };

    // The widget is in charge of managing its Autocomplete.
    this.initializeAutocomplete = function() {
        this.autocomplete = this.input.yourlabsAutocomplete(
            this.autocompleteOptions);

        // Add a class to ease css selection of autocompletes for widgets
        this.autocomplete.outerContainer.addClass(
            'autocomplete-light-widget');
    };

    // Bind Autocomplete.selectChoice signal to Widget.selectChoice()
    this.bindSelectChoice = function() {
        this.input.bind('selectChoice', function(e, choice) {
            if (!choice.length)
                return // placeholder: create choice here

            var widget = $(this).parents('.autocomplete-light-widget'
                ).yourlabsWidget();

            widget.selectChoice(choice);
        });
    };

    // Called when a choice is selected from the Autocomplete.
    this.selectChoice = function(choice) {
        // Get the value for this choice.
        var value = this.getValue(choice);

        if (!value) {
            if (window.console) console.log('yourlabs.Widget.getValue failed');
            return;
        }

        this.freeDeck();
        this.addToDeck(choice, value);
        this.addToSelect(choice, value);
        this.resetDisplay();

        this.input.val('');
    }

    // Unselect a value if the maximum number of selected values has been
    // reached.
    this.freeDeck = function() {
        var slots = this.maxValues - this.deck.children().length;

        if (this.maxValues && slots < 1) {
            // We'll remove the first choice which is supposed to be the oldest
            var choice = $(this.deck.children()[0]);

            this.deselectChoice(choice);
        }
    }

    // Empty the search input and hide it if maxValues has been reached.
    this.resetDisplay = function() {
        var selected = this.select.find('option:selected').length;

        if (this.maxValues && selected == this.maxValues) {
            this.input.hide();
        } else {
            this.input.show();
        }

        this.deck.show();
    }

    // Add a selected choice of a given value to the deck.
    this.addToDeck = function(choice, value) {
        var existing_choice = this.deck.find('[data-value="'+value+'"]');

        // Avoid duplicating choices in the deck.
        if (!existing_choice.length) {
            var choice = choice.clone();

            // In case getValue() actually **created** the value, for example
            // with a post request.
            choice.attr('data-value', value);

            this.deck.append(choice);

            // Append a clone of the .remove element.
            choice.prepend(this.widget.find('.remove:not(:visible)').clone().show());
        }
    }

    // Add a selected choice of a given value to the deck.
    this.addToSelect = function(choice, value) {
        var option = this.select.find('option[value="'+value+'"]');

        if (! option.length) {
            this.select.append(
                '<option selected="selected" value="'+ value +'"></option>');
            option = this.select.find('option[value="'+value+'"]');
        }

        option.attr('selected', 'selected');

        this.select.trigger('change');
    }

    // Called when the user clicks .remove in a deck choice.
    this.deselectChoice = function(choice) {
        var value = this.getValue(choice);

        this.select.find('option[value="'+value+'"]').remove();
        this.select.trigger('change');

        choice.remove();

        if (this.deck.children().length == 0) {
            this.deck.hide();
        }

        this.resetDisplay();
    };

    this.initialize = function() {
        this.initializeAutocomplete();

        // Working around firefox tempering form values after reload
        var widget = this;
        this.deck.find(this.autocomplete.choiceSelector).each(function() {
            var value = widget.getValue($(this));
            var option = widget.select.find('option[value="'+value+'"]');
            if (!option.attr('selected')) option.attr('selected', true);
        });

        var choices = this.deck.find(
            this.input.yourlabsAutocomplete().choiceSelector);

        // Add the remove icon to each choice
        choices.prepend(this.widget.find('.remove:last').clone().show());
        this.resetDisplay();

        this.bindSelectChoice();
    }
}

$.fn.yourlabsWidget = function(overrides) {
    var overrides = overrides ? overrides : {};

    if (this.data('widget') == undefined) {
        // Instanciate the widget
        var widget = new yourlabs.Widget(this);

        // Pares data-*
        var data = this.data();
        var dataOverrides = {autocompleteOptions: {}};
        for (var key in data) {
            if (!key) continue;

            if (key.substr(0, 12) == 'autocomplete') {
                var newKey = key.replace('autocomplete', '');
                newKey = newKey.replace(newKey[0], newKey[0].toLowerCase())
                dataOverrides['autocompleteOptions'][newKey] = data[key];
            } else {
                dataOverrides[key] = data[key];
            }
        }

        // Allow attribute overrides
        widget = $.extend(widget, dataOverrides);

        // Allow javascript object overrides
        widget = $.extend(widget, overrides);

        this.data('widget', widget);

        // Setup for usage
        widget.initialize();

        // Widget is ready
        widget.widget.attr('data-widget-ready', 1);
        widget.widget.trigger('widget-ready');
    }

    return this.data('widget');
}

$(document).ready(function() {
    $('.autocomplete-light-widget[data-bootstrap=normal]').live('initialize', function() {
        /*
        Only setup widgets which have data-bootstrap=normal, if you want to
        initialize some Widgets with custom code, then set
        data-boostrap=yourbootstrap or something like that.
        */
        $(this).yourlabsWidget();
    });

    // Call Widget.deselectChoice when .remove is clicked
    $('.autocomplete-light-widget .deck .remove').live('click', function() {
        var widget = $(this).parents('.autocomplete-light-widget'
            ).yourlabsWidget();

        var selector = widget.input.yourlabsAutocomplete().choiceSelector;
        var choice = $(this).parents(selector);

        widget.deselectChoice(choice);
    });

    /*
    Support values added directly in the select via js (ie. choices created in
    modal or popup).

    For this, we make one timer that regularely checks for values in the select
    that are not in the deck. The reason for that is that change is not triggered
    when options are added like this:

        $('select#id-dependencies').append(
            '<option value="9999" selected="selected">blabla</option>')

    Sorry for the hack but I see no other way, this is HTML's fault.
    */
    function updateWidgets() {
        $('.autocomplete-light-widget[data-widget-watch=1][data-widget-ready=1]').each(function() {
            var widget = $(this).yourlabsWidget();
            var value = widget.select.val();

            if (!value) return;

            function updateWidgetValue(value) {
                // is this necessary ?
                // if (!value) return;

                var choice = widget.deck.find('[data-value="'+value+'"]');

                if (!choice.length) {
                    var choice = widget.choiceTemplate.clone();
                    var html = widget.select.find('option[value="'+value+'"]').html();

                    choice.html(html);
                    choice.attr('data-value', value);

                    widget.selectChoice(choice);
                }
            }

            if (value instanceof Array) {
                for(var i=0; i<value.length; i++) {
                    updateWidgetValue(value[i]);
                }
            } else {
                updateWidgetValue(value);
            }
        });
        setTimeout(updateWidgets, 2000);
    }
    setTimeout(updateWidgets, 1000);

    // Solid initialization, usage:
    //
    //      $(document).bind('yourlabsWidgetReady', function() {
    //          $('.your.autocomplete-light-widget').live('initialize', function() {
    //              $(this).yourlabsWidget({
    //                  yourCustomArgs: // ...
    //              })
    //          });
    //      });
    $(document).trigger('yourlabsWidgetReady');

    $('.autocomplete-light-widget:not([id*="__prefix__"])').each(function() {
        $(this).trigger('initialize');
    });

    $(document).bind('DOMNodeInserted', function(e) {
        var widget = $(e.target).find('.autocomplete-light-widget');

        if (!widget.length) {
            widget = $(e.target).is('.autocomplete-light-widget') ? $(e.target) : false;

            if (!widget) {
                return;
            }
        }

        widget.trigger('initialize');
    });
});
<commit_msg>Bugfix: typo in updateWidgets<commit_after>/*
Widget complements Autocomplete by enabling autocompletes to be used as
value holders. It looks very much like Autocomplete in its design. Thus, it
is recommended to read the source of Autocomplete first.

Widget behaves like the autocomplete in facebook profile page, which all
users should be able to use.

Behind the scenes, Widget maintains a normal hidden select which makes it
simple to play with on the server side like on the client side. If a value
is added and selected in the select element, then it is added to the deck,
and vice-versa.

It needs some elements, and established vocabulary:

- ".autocomplete-light-widget" element wraps all the HTML necessary for the
 widget,
- ".deck" contains the list of selected choice(s) as HTML,
- "input" should be the text input that has the Autocomplete,
- "select" a (optionnaly multiple) select
- ".remove" a (preferabely hidden) element that contains a value removal
 indicator, like an "X" sign or a trashcan icon, it is used to prefix every
 children of the deck
- ".choice-template" a (preferabely hidden) element that contains the template
 for choices which are added directly in the select, as they should be
 copied in the deck,

To avoid complexity, this script relies on extra HTML attributes, and
particularely one called 'data-value'. Learn more about data attributes:
http://dev.w3.org/html5/spec/global-attributes.html#embedding-custom-non-visible-data-with-the-data-attributes

When a choice is selected from the Autocomplete, its element is cloned
and appended to the deck - "deck" contains "choices". It is important that the
choice elements of the autocomplete all contain a data-value attribute.
The value of data-value is used to fill the selected options in the hidden
select field.

If choices may not all have a data-value attribute, then you can
override Widget.getValue() to implement your own logic.
*/

// Our class will live in the yourlabs global namespace.
if (window.yourlabs == undefined) window.yourlabs = {};

/*
Instanciate a Widget.
*/
yourlabs.Widget = function(widget) {
    // These attributes where described above.
    this.widget = widget;
    this.input = this.widget.find('input');
    this.select = this.widget.find('select');
    this.deck = this.widget.find('.deck');
    this.choiceTemplate = this.widget.find('.choice-template .choice');

    // The number of choices that the user may select with this widget. Set 0
    // for no limit. In the case of a foreign key you want to set it to 1.
    this.maxValues = 0;

    // When a choice is selected from the autocomplete of this widget,
    // getValue() is called to add and select the option in the select.
    this.getValue = function(choice) {
        return choice.attr('data-value');
    };

    // The widget is in charge of managing its Autocomplete.
    this.initializeAutocomplete = function() {
        this.autocomplete = this.input.yourlabsAutocomplete(
            this.autocompleteOptions);

        // Add a class to ease css selection of autocompletes for widgets
        this.autocomplete.outerContainer.addClass(
            'autocomplete-light-widget');
    };

    // Bind Autocomplete.selectChoice signal to Widget.selectChoice()
    this.bindSelectChoice = function() {
        this.input.bind('selectChoice', function(e, choice) {
            if (!choice.length)
                return // placeholder: create choice here

            var widget = $(this).parents('.autocomplete-light-widget'
                ).yourlabsWidget();

            widget.selectChoice(choice);
        });
    };

    // Called when a choice is selected from the Autocomplete.
    this.selectChoice = function(choice) {
        // Get the value for this choice.
        var value = this.getValue(choice);

        if (!value) {
            if (window.console) console.log('yourlabs.Widget.getValue failed');
            return;
        }

        this.freeDeck();
        this.addToDeck(choice, value);
        this.addToSelect(choice, value);
        this.resetDisplay();

        this.input.val('');
    }

    // Unselect a value if the maximum number of selected values has been
    // reached.
    this.freeDeck = function() {
        var slots = this.maxValues - this.deck.children().length;

        if (this.maxValues && slots < 1) {
            // We'll remove the first choice which is supposed to be the oldest
            var choice = $(this.deck.children()[0]);

            this.deselectChoice(choice);
        }
    }

    // Empty the search input and hide it if maxValues has been reached.
    this.resetDisplay = function() {
        var selected = this.select.find('option:selected').length;

        if (this.maxValues && selected == this.maxValues) {
            this.input.hide();
        } else {
            this.input.show();
        }

        this.deck.show();
    }

    // Add a selected choice of a given value to the deck.
    this.addToDeck = function(choice, value) {
        var existing_choice = this.deck.find('[data-value="'+value+'"]');

        // Avoid duplicating choices in the deck.
        if (!existing_choice.length) {
            var choice = choice.clone();

            // In case getValue() actually **created** the value, for example
            // with a post request.
            choice.attr('data-value', value);

            this.deck.append(choice);

            // Append a clone of the .remove element.
            choice.prepend(this.widget.find('.remove:not(:visible)').clone().show());
        }
    }

    // Add a selected choice of a given value to the deck.
    this.addToSelect = function(choice, value) {
        var option = this.select.find('option[value="'+value+'"]');

        if (! option.length) {
            this.select.append(
                '<option selected="selected" value="'+ value +'"></option>');
            option = this.select.find('option[value="'+value+'"]');
        }

        option.attr('selected', 'selected');

        this.select.trigger('change');
    }

    // Called when the user clicks .remove in a deck choice.
    this.deselectChoice = function(choice) {
        var value = this.getValue(choice);

        this.select.find('option[value="'+value+'"]').remove();
        this.select.trigger('change');

        choice.remove();

        if (this.deck.children().length == 0) {
            this.deck.hide();
        }

        this.resetDisplay();
    };

    this.initialize = function() {
        this.initializeAutocomplete();

        // Working around firefox tempering form values after reload
        var widget = this;
        this.deck.find(this.autocomplete.choiceSelector).each(function() {
            var value = widget.getValue($(this));
            var option = widget.select.find('option[value="'+value+'"]');
            if (!option.attr('selected')) option.attr('selected', true);
        });

        var choices = this.deck.find(
            this.input.yourlabsAutocomplete().choiceSelector);

        // Add the remove icon to each choice
        choices.prepend(this.widget.find('.remove:last').clone().show());
        this.resetDisplay();

        this.bindSelectChoice();
    }
}

$.fn.yourlabsWidget = function(overrides) {
    var overrides = overrides ? overrides : {};

    if (this.data('widget') == undefined) {
        // Instanciate the widget
        var widget = new yourlabs.Widget(this);

        // Pares data-*
        var data = this.data();
        var dataOverrides = {autocompleteOptions: {}};
        for (var key in data) {
            if (!key) continue;

            if (key.substr(0, 12) == 'autocomplete') {
                var newKey = key.replace('autocomplete', '');
                newKey = newKey.replace(newKey[0], newKey[0].toLowerCase())
                dataOverrides['autocompleteOptions'][newKey] = data[key];
            } else {
                dataOverrides[key] = data[key];
            }
        }

        // Allow attribute overrides
        widget = $.extend(widget, dataOverrides);

        // Allow javascript object overrides
        widget = $.extend(widget, overrides);

        this.data('widget', widget);

        // Setup for usage
        widget.initialize();

        // Widget is ready
        widget.widget.attr('data-widget-ready', 1);
        widget.widget.trigger('widget-ready');
    }

    return this.data('widget');
}

$(document).ready(function() {
    $('.autocomplete-light-widget[data-bootstrap=normal]').live('initialize', function() {
        /*
        Only setup widgets which have data-bootstrap=normal, if you want to
        initialize some Widgets with custom code, then set
        data-boostrap=yourbootstrap or something like that.
        */
        $(this).yourlabsWidget();
    });

    // Call Widget.deselectChoice when .remove is clicked
    $('.autocomplete-light-widget .deck .remove').live('click', function() {
        var widget = $(this).parents('.autocomplete-light-widget'
            ).yourlabsWidget();

        var selector = widget.input.yourlabsAutocomplete().choiceSelector;
        var choice = $(this).parents(selector);

        widget.deselectChoice(choice);
    });

    /*
    Support values added directly in the select via js (ie. choices created in
    modal or popup).

    For this, we make one timer that regularely checks for values in the select
    that are not in the deck. The reason for that is that change is not triggered
    when options are added like this:

        $('select#id-dependencies').append(
            '<option value="9999" selected="selected">blabla</option>')

    Sorry for the hack but I see no other way, this is HTML's fault.
    */
    function updateWidgets() {
        $('.autocomplete-light-widget[data-watch=1][data-widget-ready=1]').each(function() {
            var widget = $(this).yourlabsWidget();
            var value = widget.select.val();

            if (!value) return;

            function updateWidgetValue(value) {
                // is this necessary ?
                // if (!value) return;

                var choice = widget.deck.find('[data-value="'+value+'"]');

                if (!choice.length) {
                    var choice = widget.choiceTemplate.clone();
                    var html = widget.select.find('option[value="'+value+'"]').html();

                    choice.html(html);
                    choice.attr('data-value', value);

                    widget.selectChoice(choice);
                }
            }

            if (value instanceof Array) {
                for(var i=0; i<value.length; i++) {
                    updateWidgetValue(value[i]);
                }
            } else {
                updateWidgetValue(value);
            }
        });
        setTimeout(updateWidgets, 2000);
    }
    setTimeout(updateWidgets, 1000);

    // Solid initialization, usage:
    //
    //      $(document).bind('yourlabsWidgetReady', function() {
    //          $('.your.autocomplete-light-widget').live('initialize', function() {
    //              $(this).yourlabsWidget({
    //                  yourCustomArgs: // ...
    //              })
    //          });
    //      });
    $(document).trigger('yourlabsWidgetReady');

    $('.autocomplete-light-widget:not([id*="__prefix__"])').each(function() {
        $(this).trigger('initialize');
    });

    $(document).bind('DOMNodeInserted', function(e) {
        var widget = $(e.target).find('.autocomplete-light-widget');

        if (!widget.length) {
            widget = $(e.target).is('.autocomplete-light-widget') ? $(e.target) : false;

            if (!widget) {
                return;
            }
        }

        widget.trigger('initialize');
    });
});
<|endoftext|>


<commit_before>'use babel'

import {toggleQuotes} from '../lib/toggle-quotes'
import {raw as r} from '../lib/string-helper'

describe('ToggleQuotes', () => {
  beforeEach(() => {
    atom.config.set('toggle-quotes.quoteCharacters', '\'"')
  })

  describe('toggleQuotes(editor) js', () => {
    let editor = null

    beforeEach(() => {
      waitsForPromise(() => {
        return Promise.all([
          atom.packages.activatePackage('language-javascript'),
          atom.packages.activatePackage('language-json'),
          atom.packages.activatePackage('language-python'),
          atom.workspace.open()
        ])
      })

      runs(() => {
        editor = atom.workspace.getActiveTextEditor()
        editor.setText(
          r`console.log("Hello World")
          console.log('Hello World')
          console.log("Hello 'World'")
          console.log('Hello "World"')
          console.log('')
          console.log("boom")`
        )
        editor.setGrammar(atom.grammars.selectGrammar('test.js'))
      })
    })

    describe('when the cursor is not inside a quoted string', () => {
      it('does nothing', () => {
        expect(() => toggleQuotes(editor)).not.toThrow()
      })
    })

    describe('when the cursor is inside an empty single quoted string', () => {
      it('switches the quotes to double', () => {
        editor.setCursorBufferPosition([4, 13])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(4)).toBe('console.log("")')
        expect(editor.getCursorBufferPosition()).toEqual([4, 13])
      })
    })

    describe('when the cursor is inside a double quoted string', () => {
      describe('when using default config', () => {
        it('switches the double quotes to single quotes', () => {
          editor.setCursorBufferPosition([0, 16])
          toggleQuotes(editor)
          expect(editor.lineTextForBufferRow(0)).toBe("console.log('Hello World')")
          expect(editor.getCursorBufferPosition()).toEqual([0, 16])
        })
      })
    })

    describe('when the cursor is barely inside a double quoted string', () => {
      describe('when using default config', () => {
        it('switches the double quotes to single quotes', () => {
          editor.setCursorBufferPosition([5, 13])
          toggleQuotes(editor)
          expect(editor.lineTextForBufferRow(5)).toBe('console.log("boom")')
          expect(editor.getCursorBufferPosition()).toEqual([5, 13])
        })
      })
    })

    describe('when using custom config of backticks', () => {
      it('switches the double quotes to backticks', () => {
        atom.config.set('toggle-quotes.quoteCharacters', '\'"`')
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe('console.log(`Hello World`)')
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
      })
    })

    describe('when using a scope-specific config override', () => {
      it('prefers the scope-specific setting', () => {
        atom.config.set('toggle-quotes.quoteCharacters', '\'"~', { scopeSelector: '.source.js' })
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe('console.log(~Hello World~)')
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
        atom.config.unset('toggle-quotes.quoteCharacters', { scope: '.source.js' })
      })

      it('does not bleed into the wrong scope', () => {
        atom.config.set('toggle-quotes.quoteCharacters', '\'"~', { scopeSelector: '.source.js' })
        editor.setGrammar(atom.grammars.selectGrammar('test.py'))
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe('console.log(\'Hello World\')')
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
        atom.config.unset('toggle-quotes.quoteCharacters', { scope: '.source.js' })
      })
    })

    describe('when the cursor is inside a single quoted string', () => {
      it('switches the quotes to double', () => {
        editor.setCursorBufferPosition([1, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(1)).toBe('console.log("Hello World")')
        expect(editor.getCursorBufferPosition()).toEqual([1, 16])
      })
    })

    describe('when the cursor is inside a single-quoted string that is nested within a double quoted string', () => {
      it('switches the outer quotes to single and escapes the inner quotes', () => {
        editor.setCursorBufferPosition([2, 22])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(2)).toBe("console.log('Hello \\'World\\'')")
        expect(editor.getCursorBufferPosition()).toEqual([2, 22])

        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(2)).toBe('console.log("Hello \'World\'")')
      })
    })

    describe('when the cursor is inside a double-quoted string that is nested within a single quoted string', () => {
      it('switches the outer quotes to double and escapes the inner quotes', () => {
        editor.setCursorBufferPosition([3, 22])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(3)).toBe('console.log("Hello \\"World\\"")')
        expect(editor.getCursorBufferPosition()).toEqual([3, 22])

        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(3)).toBe("console.log('Hello \"World\"')")
      })
    })

    describe('when the cursor is inside multiple quoted strings', () => {
      it('switches the quotes of both quoted strings separately and leaves the cursors where they were, and does so atomically', () => {
        editor.setCursorBufferPosition([0, 16])
        editor.addCursorAtBufferPosition([1, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe("console.log('Hello World')")
        expect(editor.lineTextForBufferRow(1)).toBe('console.log("Hello World")')
        expect(editor.getCursors()[0].getBufferPosition()).toEqual([0, 16])
        expect(editor.getCursors()[1].getBufferPosition()).toEqual([1, 16])

        editor.undo()
        expect(editor.lineTextForBufferRow(0)).toBe('console.log("Hello World")')
        expect(editor.lineTextForBufferRow(1)).toBe("console.log('Hello World')")
        expect(editor.getCursors()[0].getBufferPosition()).toEqual([0, 16])
        expect(editor.getCursors()[1].getBufferPosition()).toEqual([1, 16])
      })
    })

    describe('when the cursor is on an invalid region', () => {
      describe('when it is quoted', () => {
        it('toggles the quotes', () => {
          editor.setGrammar(atom.grammars.selectGrammar('test.json'))
          editor.setText("{'invalid': true}")
          editor.setCursorBufferPosition([0, 4])
          toggleQuotes(editor)
          expect(editor.getText()).toBe('{"invalid": true}')
        })
      })

      describe('when it is not quoted', () => {
        it('does not toggle the quotes', () => {
          editor.setGrammar(atom.grammars.selectGrammar('test.json'))
          editor.setText('{invalid: true}')
          editor.setCursorBufferPosition([0, 4])
          toggleQuotes(editor)
          expect(editor.getText()).toBe('{invalid: true}')
        })
      })
    })
  })

  describe('toggleQuotes(editor) python', () => {
    let editor = null

    beforeEach(() => {
      waitsForPromise(() => {
        return atom.packages.activatePackage('language-python')
      })

      waitsForPromise(() => {
        return atom.workspace.open()
      })

      runs(() => {
        editor = atom.workspace.getActiveTextEditor()
        editor.setText(
          r`print(u"Hello World")
          print(r'')`
        )
        editor.setGrammar(atom.grammars.selectGrammar('test.py'))
      })
    })

    describe('when cursor is inside a double quoted unicode string', () => {
      it('switches quotes to single excluding unicode character', () => {
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe("print(u'Hello World')")
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
      })
    })

    describe('when cursor is inside an empty single quoted raw string', () => {
      it('switches quotes to double', () => {
        editor.setCursorBufferPosition([1, 8])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(1)).toBe('print(r"")')
        expect(editor.getCursorBufferPosition()).toEqual([1, 8])
      })
    })
  })

  it('activates when a command is triggered', () => {
    let activatePromise = atom.packages.activatePackage('toggle-quotes')

    waitsForPromise(() => {
      return atom.workspace.open()
    })

    runs(() => {
      let editor = atom.workspace.getActiveTextEditor()
      atom.commands.dispatch(atom.views.getView(editor), 'toggle-quotes:toggle')
    })

    waitsForPromise(() => { return activatePromise })
  })
})
<commit_msg>Fix spec<commit_after>'use babel'

import {toggleQuotes} from '../lib/toggle-quotes'
import {raw as r} from '../lib/string-helper'

describe('ToggleQuotes', () => {
  beforeEach(() => {
    atom.config.set('toggle-quotes.quoteCharacters', '\'"')
  })

  describe('toggleQuotes(editor) js', () => {
    let editor = null

    beforeEach(() => {
      waitsForPromise(() => {
        return Promise.all([
          atom.packages.activatePackage('language-javascript'),
          atom.packages.activatePackage('language-json'),
          atom.packages.activatePackage('language-python'),
          atom.workspace.open()
        ])
      })

      runs(() => {
        editor = atom.workspace.getActiveTextEditor()
        editor.setText(
          r`console.log("Hello World")
          console.log('Hello World')
          console.log("Hello 'World'")
          console.log('Hello "World"')
          console.log('')
          console.log("boom")`
        )
        editor.setGrammar(atom.grammars.selectGrammar('test.js'))
      })
    })

    describe('when the cursor is not inside a quoted string', () => {
      it('does nothing', () => {
        expect(() => toggleQuotes(editor)).not.toThrow()
      })
    })

    describe('when the cursor is inside an empty single quoted string', () => {
      it('switches the quotes to double', () => {
        editor.setCursorBufferPosition([4, 13])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(4)).toBe('console.log("")')
        expect(editor.getCursorBufferPosition()).toEqual([4, 13])
      })
    })

    describe('when the cursor is inside a double quoted string', () => {
      describe('when using default config', () => {
        it('switches the double quotes to single quotes', () => {
          editor.setCursorBufferPosition([0, 16])
          toggleQuotes(editor)
          expect(editor.lineTextForBufferRow(0)).toBe("console.log('Hello World')")
          expect(editor.getCursorBufferPosition()).toEqual([0, 16])
        })
      })
    })

    describe('when the cursor is barely inside a double quoted string', () => {
      describe('when using default config', () => {
        it('switches the double quotes to single quotes', () => {
          editor.setCursorBufferPosition([5, 13])
          toggleQuotes(editor)
          expect(editor.lineTextForBufferRow(5)).toBe(`console.log('boom')`)
          expect(editor.getCursorBufferPosition()).toEqual([5, 13])
        })
      })
    })

    describe('when using custom config of backticks', () => {
      it('switches the double quotes to backticks', () => {
        atom.config.set('toggle-quotes.quoteCharacters', '\'"`')
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe('console.log(`Hello World`)')
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
      })
    })

    describe('when using a scope-specific config override', () => {
      it('prefers the scope-specific setting', () => {
        atom.config.set('toggle-quotes.quoteCharacters', '\'"~', { scopeSelector: '.source.js' })
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe('console.log(~Hello World~)')
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
        atom.config.unset('toggle-quotes.quoteCharacters', { scope: '.source.js' })
      })

      it('does not bleed into the wrong scope', () => {
        atom.config.set('toggle-quotes.quoteCharacters', '\'"~', { scopeSelector: '.source.js' })
        editor.setGrammar(atom.grammars.selectGrammar('test.py'))
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe('console.log(\'Hello World\')')
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
        atom.config.unset('toggle-quotes.quoteCharacters', { scope: '.source.js' })
      })
    })

    describe('when the cursor is inside a single quoted string', () => {
      it('switches the quotes to double', () => {
        editor.setCursorBufferPosition([1, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(1)).toBe('console.log("Hello World")')
        expect(editor.getCursorBufferPosition()).toEqual([1, 16])
      })
    })

    describe('when the cursor is inside a single-quoted string that is nested within a double quoted string', () => {
      it('switches the outer quotes to single and escapes the inner quotes', () => {
        editor.setCursorBufferPosition([2, 22])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(2)).toBe("console.log('Hello \\'World\\'')")
        expect(editor.getCursorBufferPosition()).toEqual([2, 22])

        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(2)).toBe('console.log("Hello \'World\'")')
      })
    })

    describe('when the cursor is inside a double-quoted string that is nested within a single quoted string', () => {
      it('switches the outer quotes to double and escapes the inner quotes', () => {
        editor.setCursorBufferPosition([3, 22])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(3)).toBe('console.log("Hello \\"World\\"")')
        expect(editor.getCursorBufferPosition()).toEqual([3, 22])

        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(3)).toBe("console.log('Hello \"World\"')")
      })
    })

    describe('when the cursor is inside multiple quoted strings', () => {
      it('switches the quotes of both quoted strings separately and leaves the cursors where they were, and does so atomically', () => {
        editor.setCursorBufferPosition([0, 16])
        editor.addCursorAtBufferPosition([1, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe("console.log('Hello World')")
        expect(editor.lineTextForBufferRow(1)).toBe('console.log("Hello World")')
        expect(editor.getCursors()[0].getBufferPosition()).toEqual([0, 16])
        expect(editor.getCursors()[1].getBufferPosition()).toEqual([1, 16])

        editor.undo()
        expect(editor.lineTextForBufferRow(0)).toBe('console.log("Hello World")')
        expect(editor.lineTextForBufferRow(1)).toBe("console.log('Hello World')")
        expect(editor.getCursors()[0].getBufferPosition()).toEqual([0, 16])
        expect(editor.getCursors()[1].getBufferPosition()).toEqual([1, 16])
      })
    })

    describe('when the cursor is on an invalid region', () => {
      describe('when it is quoted', () => {
        it('toggles the quotes', () => {
          editor.setGrammar(atom.grammars.selectGrammar('test.json'))
          editor.setText("{'invalid': true}")
          editor.setCursorBufferPosition([0, 4])
          toggleQuotes(editor)
          expect(editor.getText()).toBe('{"invalid": true}')
        })
      })

      describe('when it is not quoted', () => {
        it('does not toggle the quotes', () => {
          editor.setGrammar(atom.grammars.selectGrammar('test.json'))
          editor.setText('{invalid: true}')
          editor.setCursorBufferPosition([0, 4])
          toggleQuotes(editor)
          expect(editor.getText()).toBe('{invalid: true}')
        })
      })
    })
  })

  describe('toggleQuotes(editor) python', () => {
    let editor = null

    beforeEach(() => {
      waitsForPromise(() => {
        return atom.packages.activatePackage('language-python')
      })

      waitsForPromise(() => {
        return atom.workspace.open()
      })

      runs(() => {
        editor = atom.workspace.getActiveTextEditor()
        editor.setText(
          r`print(u"Hello World")
          print(r'')`
        )
        editor.setGrammar(atom.grammars.selectGrammar('test.py'))
      })
    })

    describe('when cursor is inside a double quoted unicode string', () => {
      it('switches quotes to single excluding unicode character', () => {
        editor.setCursorBufferPosition([0, 16])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(0)).toBe("print(u'Hello World')")
        expect(editor.getCursorBufferPosition()).toEqual([0, 16])
      })
    })

    describe('when cursor is inside an empty single quoted raw string', () => {
      it('switches quotes to double', () => {
        editor.setCursorBufferPosition([1, 8])
        toggleQuotes(editor)
        expect(editor.lineTextForBufferRow(1)).toBe('print(r"")')
        expect(editor.getCursorBufferPosition()).toEqual([1, 8])
      })
    })
  })

  it('activates when a command is triggered', () => {
    let activatePromise = atom.packages.activatePackage('toggle-quotes')

    waitsForPromise(() => {
      return atom.workspace.open()
    })

    runs(() => {
      let editor = atom.workspace.getActiveTextEditor()
      atom.commands.dispatch(atom.views.getView(editor), 'toggle-quotes:toggle')
    })

    waitsForPromise(() => { return activatePromise })
  })
})
<|endoftext|>


<commit_before>$(function() {
  if ($('.greeting-category').size() === 0) {
    return;
  }

  $(window).on('hashchange', function() {
    var hash = location.hash;
    var isTimetable = (hash.indexOf('#timetable/') === 0);
    var isCharacter = (hash.indexOf('#character/') === 0);

    if (!isTimetable && !isCharacter) {
      isTimetable = true;
    }

    $('#timetable').toggle(isTimetable);
    $('#timetable-tab').toggleClass('active', isTimetable);
    $('#character').toggle(isCharacter);
    $('#character-tab').toggleClass('active', isCharacter);

    var target = $('*[name="' + hash.substring(1) + '"]');
    if (target.size() > 0) {
      $.scrollTo(target, 100);
    }

    return false;
  }).triggerHandler('hashchange');

  var time = Math.floor(+new Date() / 60000) * 60000;

  var update = function() {
    $('.greeting-category').each(function() {
      var category = $(this);
      if (category.hasClass('greeting-category-deleted')) {
        return true; // continue
      }
      category.find('.greeting-group').each(function() {
        var element = $(this);
        var start = new Date(element.data('start-at'));
        var end = new Date(element.data('end-at'));
        if (time < start && !category.hasClass('greeting-category-before-the-start')) {
          $('.greeting-category-before-the-start .greetings').append(this);
          element.find('.panel').attr('class', 'panel panel-info');
        }
        else if (time >= start && time < end && !category.hasClass('greeting-category-in-session')) {
          $('.greeting-category-in-session .greetings').append(this);
          element.find('.panel').attr('class', 'panel panel-primary');
        }
        else if (time > end && !category.hasClass('greeting-category-after-the-end')) {
          $('.greeting-category-after-the-end .greetings').append(this);
          element.find('.panel').attr('class', 'panel panel-success');
        }
      });
    });

    $('.greeting-category').each(function() {
      var element = $(this);
      var greetings = element.find('.greetings');
      if (greetings.children().size() > 0) {
        element.removeClass('greeting-category-empty');
      }
      else {
        element.addClass('greeting-category-empty');
      }
    });
  };

  update();

  setInterval(function() {
    var next = +new Date();
    if (next - time >= 60000) {
      time = Math.floor(next / 60000) * 60000;
      update();
    }
  }, 1000);
});
<commit_msg>WebKit向けにlocation.hashのURIデコードを行うよう変更<commit_after>$(function() {
  if ($('.greeting-category').size() === 0) {
    return;
  }

  $(window).on('hashchange', function() {
    var hash = location.hash;
    var isTimetable = (hash.indexOf('#timetable/') === 0);
    var isCharacter = (hash.indexOf('#character/') === 0);

    if (!isTimetable && !isCharacter) {
      isTimetable = true;
    }

    $('#timetable').toggle(isTimetable);
    $('#timetable-tab').toggleClass('active', isTimetable);
    $('#character').toggle(isCharacter);
    $('#character-tab').toggleClass('active', isCharacter);

    var target = $('*[name="' + decodeURI(hash.substring(1)) + '"]');
    if (target.size() > 0) {
      $.scrollTo(target, 100);
    }

    return false;
  }).triggerHandler('hashchange');

  var time = Math.floor(+new Date() / 60000) * 60000;

  var update = function() {
    $('.greeting-category').each(function() {
      var category = $(this);
      if (category.hasClass('greeting-category-deleted')) {
        return true; // continue
      }
      category.find('.greeting-group').each(function() {
        var element = $(this);
        var start = new Date(element.data('start-at'));
        var end = new Date(element.data('end-at'));
        if (time < start && !category.hasClass('greeting-category-before-the-start')) {
          $('.greeting-category-before-the-start .greetings').append(this);
          element.find('.panel').attr('class', 'panel panel-info');
        }
        else if (time >= start && time < end && !category.hasClass('greeting-category-in-session')) {
          $('.greeting-category-in-session .greetings').append(this);
          element.find('.panel').attr('class', 'panel panel-primary');
        }
        else if (time > end && !category.hasClass('greeting-category-after-the-end')) {
          $('.greeting-category-after-the-end .greetings').append(this);
          element.find('.panel').attr('class', 'panel panel-success');
        }
      });
    });

    $('.greeting-category').each(function() {
      var element = $(this);
      var greetings = element.find('.greetings');
      if (greetings.children().size() > 0) {
        element.removeClass('greeting-category-empty');
      }
      else {
        element.addClass('greeting-category-empty');
      }
    });
  };

  update();

  setInterval(function() {
    var next = +new Date();
    if (next - time >= 60000) {
      time = Math.floor(next / 60000) * 60000;
      update();
    }
  }, 1000);
});
<|endoftext|>