<commit_before>angular.module('rifiuti.controllers.profilo', [])

.controller('ProfiliCtrl', function ($scope, $rootScope) {})

.controller('ModificaProfiloCtrl', function ($scope, $rootScope, $ionicNavBarDelegate, $filter, DataManager, $stateParams, $ionicPopup, $ionicModal, Profili, Raccolta) {
    $scope.aree = [];

    $scope.id = $stateParams.id;

    $scope.profilo = {
        name: '',
        utenza: {},
        area: {}
    };

    $scope.updateLocations = function () {
        Raccolta.areeForTipoUtenza($scope.profilo.utenza.tipologiaUtenza).then(function (data) {
            $scope.aree = [];

            for (var i = 0; i < data.length; i++) {
                $scope.aree.push(data[i]);
                if ($scope.profilo.area && data[i].nome == $scope.profilo.area.nome) {
                    $scope.profilo.area = data[i];
                }
            }
        });
    };

    // popola tipi di utenza e relative locations
    Profili.tipidiutenza().then(function (tipi) {
        tipi = tipi.sort(function (a, b) {
            return a.nome.localeCompare(b.nome);
        });
        $scope.tipologiaUtenza = tipi;

        // new profile
        if (!$scope.id) {
            $scope.profilo.utenza = tipi[0];
            $scope.updateLocations();
        } else {
            // get profile
            var p = Profili.byId($scope.id);
            if (!!p) {
                $scope.profilo = angular.copy(p);
                $scope.updateLocations();
            }
        }
    });

    $scope.isCurrentProfile = true;
    $scope.editMode = !$scope.id;

    $scope.edit = function () {
        if (!$scope.editMode) {
            // edit
            $scope.editMode = true;

            for (var i = 0; i < $scope.tipologiaUtenza.length; i++) {
                if ($scope.tipologiaUtenza[i].nome === $scope.profilo.utenza.nome) {
                    $scope.profilo.utenza = $scope.tipologiaUtenza[i];
                }
            }
        } else {
            // save
            if (!!$scope.profilo.name && !!$scope.profilo.area) {
                var newProfile = null;

                if (!!$scope.id) {
                    // update
                    newProfile = Profili.update($scope.id, $scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                } else {
                    // create
                    newProfile = Profili.add($scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                    $scope.back();
                    return;
                }

                if (newProfile == null) {
                    // error: already exists
                    var popup = $ionicPopup.show({
                        title: '<b class="popup-title">Attenzione !<b/>',
                        template: 'Il nome del profilo è già in uso!',
                        buttons: [
                            {
                                text: 'OK'
                            }
                        ]
                    });
                } else {
                    $scope.editMode = false;
                }
            } else {
                // not complete
                $ionicPopup.show({
                    title: '<b class="popup-title">Attenzione !<b/>',
                    template: 'Per completare il tuo profilo devi scegliere un nome e una località!',
                    scope: $scope,
                    buttons: [
                        {
                            text: 'OK'
                        }
                    ]
                });
            }
        }
    };

    $scope.helpTipi = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Info<b/>',
            templateUrl: 'templates/profiloHelp.html',
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.help = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">' + area.etichetta + '<b/>',
            //templateUrl: 'templates/profiloHelp.html',
            template: area.descrizione,
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.click = function () {
        if ($scope.isCurrentProfile) {
            var popup = $ionicPopup.show({
                title: '<b class="popup-title">Avviso<b/>',
                template: 'Non è possibile cancellare il profilo in uso.',
                scope: $scope,
                buttons: [
                    {
                        text: 'OK'
                    }
                ]
            });
            return;
        }

        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Avviso<b/>',
            template: 'Premendo OK cancellerai definitivamente questo profilo. Confermi?',
            //TODO: le note dovrebbero essere legate al profilo??? ora non lo sono!
            //      template: 'Premendo OK cancellerai definitivamente questo profilo, incluse tutte le eventuali note personali. Confermi?',
            scope: $scope,
            buttons: [
                {
                    text: $filter('translate')('cancel')
                },
                {
                    text: 'OK',
                    onTap: function (e) {
                        return true;
                    }
                }
            ]
        }).then(function (res) {
            if (!!res) {
                Profili.remove($scope.id);
                $scope.back();
            }
        });
    };

    if (!!$rootScope.selectedProfile && $rootScope.selectedProfile.name == $scope.profilo.name) {
        $scope.isCurrentProfile = true;
    } else {
        $scope.isCurrentProfile = false;
    }

    /* LOCALITA SELECTOR */
    $ionicModal.fromTemplateUrl('templates/localitaModal.html', {
        scope: $scope,
        animation: 'slide-in-up'
    }).then(function (modal) {
        $scope.localitaModal = modal;
    });

    $scope.openLocalitaSelector = function () {
        $scope.localitaModal.show();
    };

    $scope.closeLocalitaSelector = function () {
        $scope.localitaModal.hide();
    };

    $scope.localitaSelected = function (item) {
        $scope.profilo.area = item;
        $scope.closeLocalitaSelector();
    };

    //Cleanup the modal when we're done with it!
    $scope.$on('$destroy', function () {
        $scope.localitaModal.remove();
    });

    // Execute action on hide modal
    $scope.$on('modal.hidden', function () {
        // Execute action
    });

    // Execute action on remove modal
    $scope.$on('modal.removed', function () {
        // Execute action
    });
});
<commit_msg>fix for profile cancellation<commit_after>angular.module('rifiuti.controllers.profilo', [])

.controller('ProfiliCtrl', function ($scope, $rootScope) {})

.controller('ModificaProfiloCtrl', function ($scope, $rootScope, $ionicNavBarDelegate, $filter, DataManager, $stateParams, $ionicPopup, $ionicModal, Profili, Raccolta) {
    $scope.aree = [];

    $scope.id = $stateParams.id;

    $scope.profilo = {
        name: '',
        utenza: {},
        area: {}
    };

    $scope.updateLocations = function () {
        Raccolta.areeForTipoUtenza($scope.profilo.utenza.tipologiaUtenza).then(function (data) {
            $scope.aree = [];

            for (var i = 0; i < data.length; i++) {
                $scope.aree.push(data[i]);
                if ($scope.profilo.area && data[i].nome == $scope.profilo.area.nome) {
                    $scope.profilo.area = data[i];
                }
            }
        });
    };

    // popola tipi di utenza e relative locations
    Profili.tipidiutenza().then(function (tipi) {
        tipi = tipi.sort(function (a, b) {
            return a.nome.localeCompare(b.nome);
        });
        $scope.tipologiaUtenza = tipi;

        // new profile
        if (!$scope.id) {
            $scope.profilo.utenza = tipi[0];
            $scope.updateLocations();
        } else {
            // get profile
            var p = Profili.byId($scope.id);
            if (!!p) {
                $scope.profilo = angular.copy(p);
                $scope.updateLocations();
            }
        }
        if (!!$rootScope.selectedProfile && $rootScope.selectedProfile.name == $scope.profilo.name) {
            $scope.isCurrentProfile = true;
        } else {
            $scope.isCurrentProfile = false;
        }

    });

    $scope.isCurrentProfile = true;
    $scope.editMode = !$scope.id;

    $scope.edit = function () {
        if (!$scope.editMode) {
            // edit
            $scope.editMode = true;

            for (var i = 0; i < $scope.tipologiaUtenza.length; i++) {
                if ($scope.tipologiaUtenza[i].nome === $scope.profilo.utenza.nome) {
                    $scope.profilo.utenza = $scope.tipologiaUtenza[i];
                }
            }
        } else {
            // save
            if (!!$scope.profilo.name && !!$scope.profilo.area) {
                var newProfile = null;

                if (!!$scope.id) {
                    // update
                    newProfile = Profili.update($scope.id, $scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                } else {
                    // create
                    newProfile = Profili.add($scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                    $scope.back();
                    return;
                }

                if (newProfile == null) {
                    // error: already exists
                    var popup = $ionicPopup.show({
                        title: '<b class="popup-title">Attenzione !<b/>',
                        template: 'Il nome del profilo è già in uso!',
                        buttons: [
                            {
                                text: 'OK'
                            }
                        ]
                    });
                } else {
                    $scope.editMode = false;
                }
            } else {
                // not complete
                $ionicPopup.show({
                    title: '<b class="popup-title">Attenzione !<b/>',
                    template: 'Per completare il tuo profilo devi scegliere un nome e una località!',
                    scope: $scope,
                    buttons: [
                        {
                            text: 'OK'
                        }
                    ]
                });
            }
        }
    };

    $scope.helpTipi = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Info<b/>',
            templateUrl: 'templates/profiloHelp.html',
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.help = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">' + area.etichetta + '<b/>',
            //templateUrl: 'templates/profiloHelp.html',
            template: area.descrizione,
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.click = function () {
        if ($scope.isCurrentProfile) {
            var popup = $ionicPopup.show({
                title: '<b class="popup-title">Avviso<b/>',
                template: 'Non è possibile cancellare il profilo in uso.',
                scope: $scope,
                buttons: [
                    {
                        text: 'OK'
                    }
                ]
            });
            return;
        }

        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Avviso<b/>',
            template: 'Premendo OK cancellerai definitivamente questo profilo. Confermi?',
            //TODO: le note dovrebbero essere legate al profilo??? ora non lo sono!
            //      template: 'Premendo OK cancellerai definitivamente questo profilo, incluse tutte le eventuali note personali. Confermi?',
            scope: $scope,
            buttons: [
                {
                    text: $filter('translate')('cancel')
                },
                {
                    text: 'OK',
                    onTap: function (e) {
                        return true;
                    }
                }
            ]
        }).then(function (res) {
            if (!!res) {
                Profili.remove($scope.id);
                $scope.back();
            }
        });
    };

    /* LOCALITA SELECTOR */
    $ionicModal.fromTemplateUrl('templates/localitaModal.html', {
        scope: $scope,
        animation: 'slide-in-up'
    }).then(function (modal) {
        $scope.localitaModal = modal;
    });

    $scope.openLocalitaSelector = function () {
        $scope.localitaModal.show();
    };

    $scope.closeLocalitaSelector = function () {
        $scope.localitaModal.hide();
    };

    $scope.localitaSelected = function (item) {
        $scope.profilo.area = item;
        $scope.closeLocalitaSelector();
    };

    //Cleanup the modal when we're done with it!
    $scope.$on('$destroy', function () {
        $scope.localitaModal.remove();
    });

    // Execute action on hide modal
    $scope.$on('modal.hidden', function () {
        // Execute action
    });

    // Execute action on remove modal
    $scope.$on('modal.removed', function () {
        // Execute action
    });
});
<|endoftext|>


<commit_before>'use strict';

var test = 0;

(function() {
  var masterPage = angular.module('myApp.masterPage', ['ngRoute', 'blockExplorerServices']);

  masterPage.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/', {
      templateUrl: 'masterPage/masterPage.html',
      controller: 'MasterPageCtrl'
    });
  }]);

  masterPage.controller('MasterPageCtrl', ['$http', '$scope', 'BlockService', function($http, $scope, BlockService) {
    var self = this;

    var retryError = 'Error! Could not load blocks.';

    self.oldestBlock = '';
    self.errorMessage = '';

    this.previousTenFromLatest = function () {
      BlockService.getLatestHash().then(
        function(latestHash) {
          self.errorMessage = '';

          self.previousTenBlocks(latestHash);
        },
        function(error) {
          self.errorMessage = retryError;
          $scope.$apply();

        });
    }

    this.previousTenBlocks = function (hash) {
      BlockService.getBlocks(hash, 10).then(
        function(blocksArray) {
          self.errorMessage = '';

          self.rawBlocks = blocksArray;

          self.oldestBlock = self.rawBlocks[self.rawBlocks.length-1].hash;
        },
        function(error) {
          self.errorMessage = retryError;
          $scope.$apply();
        });

    }

    this.previousTen = function () {
      self.previousTenBlocks(self.oldestBlock);
    }

    this.convertHexToDecimal = function(hex) {
      return parseInt(hex, 16);
    }

    this.previousTenFromLatest();

    if (test === 0) {
      test++;

      BlockService.getTransactions('8dd171d6f04ba0f5df0c7d0491ae8455134c70ebdedc798bb4c9441d5ee03158', 3)
      .then(function (response) {
        console.log(response);
        console.log('eeep');
      });
    }

  }]);

  masterPage.filter('blockHashFilter', function() {
    return function(input, filterText) {
      // return false;
      if (!input || !filterText) {
        return input;
      }

      var newArray = input.filter(function(element, index, array) {
        var result = (element.hash.indexOf(filterText) > -1);
        return result;
      });

      console.log(newArray);

      return newArray;
    };
  });

  masterPage.directive('blockCard', function() {
    return {
      restrict: 'E',
      template: '

{{ rawBlock.hash | removeLeadingZeros }}

# Transactions: {{ rawBlock.tx.length }}

',
      scope: {
        rawBlock: "=rawBlock",
      }
    };
  });

  masterPage.filter('removeLeadingZeros', function () {
    return function (input) {

      var indexOfLastConsequtiveZero = 0;
      for (var i = 0, len = input.length; i < len; i++) {
        if (input[i] != '0') {
          indexOfLastConsequtiveZero = i;
          break;
        }
      }

      var remainder = input.length - indexOfLastConsequtiveZero;

      return input.slice(indexOfLastConsequtiveZero, indexOfLastConsequtiveZero + Math.min(remainder, 5));
    };
  });

})();
<commit_msg>Removes various logs.<commit_after>'use strict';

var test = 0;

(function() {
  var masterPage = angular.module('myApp.masterPage', ['ngRoute', 'blockExplorerServices']);

  masterPage.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/', {
      templateUrl: 'masterPage/masterPage.html',
      controller: 'MasterPageCtrl'
    });
  }]);

  masterPage.controller('MasterPageCtrl', ['$http', '$scope', 'BlockService', function($http, $scope, BlockService) {
    var self = this;

    var retryError = 'Error! Could not load blocks.';

    self.oldestBlock = '';
    self.errorMessage = '';

    this.previousTenFromLatest = function () {
      BlockService.getLatestHash().then(
        function(latestHash) {
          self.errorMessage = '';

          self.previousTenBlocks(latestHash);
        },
        function(error) {
          self.errorMessage = retryError;
          $scope.$apply();

        });
    }

    this.previousTenBlocks = function (hash) {
      BlockService.getBlocks(hash, 10).then(
        function(blocksArray) {
          self.errorMessage = '';

          self.rawBlocks = blocksArray;

          self.oldestBlock = self.rawBlocks[self.rawBlocks.length-1].hash;
        },
        function(error) {
          self.errorMessage = retryError;
          $scope.$apply();
        });

    }

    this.previousTen = function () {
      self.previousTenBlocks(self.oldestBlock);
    }

    this.convertHexToDecimal = function(hex) {
      return parseInt(hex, 16);
    }

    this.previousTenFromLatest();

    if (test === 0) {
      test++;

      BlockService.getTransactions('8dd171d6f04ba0f5df0c7d0491ae8455134c70ebdedc798bb4c9441d5ee03158', 3)
      .then(function (response) {
      });
    }

  }]);

  masterPage.filter('blockHashFilter', function() {
    return function(input, filterText) {
      // return false;
      if (!input || !filterText) {
        return input;
      }

      var newArray = input.filter(function(element, index, array) {
        var result = (element.hash.indexOf(filterText) > -1);
        return result;
      });

      return newArray;
    };
  });

  masterPage.directive('blockCard', function() {
    return {
      restrict: 'E',
      template: '

{{ rawBlock.hash | removeLeadingZeros }}

# Transactions: {{ rawBlock.tx.length }}

',
      scope: {
        rawBlock: "=rawBlock",
      }
    };
  });

  masterPage.filter('removeLeadingZeros', function () {
    return function (input) {

      var indexOfLastConsequtiveZero = 0;
      for (var i = 0, len = input.length; i < len; i++) {
        if (input[i] != '0') {
          indexOfLastConsequtiveZero = i;
          break;
        }
      }

      var remainder = input.length - indexOfLastConsequtiveZero;

      return input.slice(indexOfLastConsequtiveZero, indexOfLastConsequtiveZero + Math.min(remainder, 5));
    };
  });

})();
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
// gyp-builder - Server Side
//////////////////////////////////////////////////////////////////////////
//
// Main module for gyp-builder
//
/* ----------------------------------------------------------------------
                                                    Object Structures
-------------------------------------------------------------------------

*/
//////////////////////////////////////////////////////////////////////////
// Node.js Exports
exports.createMaker = function( separationString ) { return new Maker(separationString); }

//////////////////////////////////////////////////////////////////////////
// Namespace (lol)
var DEBUG = true;

var log = function( text, isImportant ) {
	if(DEBUG && isImportant) {
		console.log("\n******************************************")
		console.log("* " + text)
		console.log("******************************************\n")
	} else if(DEBUG) {
		console.log(text);
	}
};

var wrench = require("wrench"),
	basename = require("path").basename,
	fs = require("fs");

var templateFileExtension = ".tpl";

//////////////////////////////////////////////////////////////////////////
// Constructor
function Maker( separationString ) {
	this.separationString = separationString || "~~";
	this.templates = require("./templates/templates");
} // end Maker()

//////////////////////////////////////////////////////////////////////////
// Returns a template object loaded from a file
Maker.prototype.template = function( templateString, contents ) {
	var templateObj = parseTemplate( templateString, this.separationString );

	for( var property in contents ) {
		if( contents.hasOwnProperty(property) ) {

			templateObj[property] = contents[property] || {};
		}
	}

	return templateObj;
} // end template()

//////////////////////////////////////////////////////////////////////////
// Loads all templates inside of a given directory
Maker.prototype.loadTemplateDir = function( templateDir, callback ) {
	var templates = {};

	// Walk the folder tree recursively
	wrench.readdirRecursive( templateDir, function(error, files) {
		if( files == null )
			return callback( templates );

		for( var iFile=0; iFile<files.length; ++iFile ) {
			if( files[iFile].indexOf(".tpl") == -1 )
				continue;

			var path = templateDir + "/" + files[iFile],
				file = fs.readFileSync( path, "utf8" );

			var templateName = basename( path );

			// Trim off the extension
			templateName = templateName.substring( 0, templateName.length - templateFileExtension.length );

			templates[templateName] = file;
		}
	});
} // end loadTemplateDir()

//////////////////////////////////////////////////////////////////////////
// Parses a template string and returns an object of its contents
function parseTemplate( templateString, separationString ) {
	var iPosition = 0,
		matches = [],
		templateObj = {};

	iPosition = templateString.indexOf( separationString, iPosition );

	while( iPosition > 0 ) {
		matches.push( iPosition + separationString.length );

		iPosition = templateString.indexOf( separationString, iPosition+1 );
	}

	if( matches.length % 2 != 0 ) {
		log( "Error while parsing template: Mismatched separation string" );
	}

	for( var iItem = 0; iItem < matches.length; iItem += 2 ) {
		var strItem = templateString.substring( matches[iItem] + separationString.length, matches[iItem+1] );

		templateObj[strItem] = {};
	}

	return templateObj;
} // end parseTemplate()<commit_msg>First working version<commit_after>//////////////////////////////////////////////////////////////////////////
// maker - Server Side
//////////////////////////////////////////////////////////////////////////
//
// Main module for gyp-builder
//
/* ----------------------------------------------------------------------
                                                    Object Structures
-------------------------------------------------------------------------

*/
//////////////////////////////////////////////////////////////////////////
// Node.js Exports
exports.createMaker = function( separationString ) { return new Maker(separationString); }

//////////////////////////////////////////////////////////////////////////
// Namespace (lol)
var DEBUG = true;

var log = function( text, isImportant ) {
	if(DEBUG && isImportant) {
		console.log("\n******************************************")
		console.log("* " + text)
		console.log("******************************************\n")
	} else if(DEBUG) {
		console.log(text);
	}
};

var wrench = require("wrench"),
	basename = require("path").basename,
	fs = require("fs"),
	traverse = require("traverse");

var templateFileExtension = ".tpl";

//////////////////////////////////////////////////////////////////////////
// Constructor
function Maker( separationString ) {
	this.separationString = separationString || "~~";
	this.templates = {};
} // end Maker()

//////////////////////////////////////////////////////////////////////////
// Returns a template object loaded from a file
Maker.prototype.template = function( templateString, contents ) {
	var templateObj = parseTemplate( templateString, this.separationString );

	for( var property in contents ) {
		if( contents.hasOwnProperty(property) ) {

			templateObj[property] = contents[property] || {};
		}
	}

	return templateObj;
} // end template()

//////////////////////////////////////////////////////////////////////////
// Creates a file on disk composed of the given templates
Maker.prototype.makeFile = function( path, templates ) {
	// Convert any templates that are still objects into strings
	for( var iTemplate=0; iTemplate<templates.length; ++iTemplate ) {
		if( typeof(templates[iTemplate]) === "object" ) {
			templates[iTemplate] = this.renderTemplateToString( templates[iTemplate] );
		}
	}

	var fileContents = "";

	// Concatenate all template strings into one big string
	for( var iTemplate=0; iTemplate<templates.length; ++iTemplate ) {
		fileContents += templates[iTemplate];
	}

	// Write the file to disk
	fs.writeFile( path, fileContents, function(err) {
	    if(err) {
	        console.log(err);
	    } else {
	        console.log("The file was saved!");
	    }
	});
} // end makeFile()

//////////////////////////////////////////////////////////////////////////
// Renders a template and its contents back into a string
Maker.prototype.renderTemplateToString = function( template ) {
	if( typeof(template) === "string" )
		template = this.templates[template];

	// Start with the original template string
	var renderedTemplate = template.__fullTemplateString__,
		matches = template.__templateMatches__;

	for( var iItem in template ) {
		if( iItem == "__fullTemplateString__" || iItem == "__templateMatches__" )
			continue;

		if( typeof template[iItem] === "object" ) {
			console.log( "Parameter '" + iItem + "' has no value set" );
		}

		var stringToReplace = this.separationString + iItem + this.separationString;
		renderedTemplate = renderedTemplate.replace( new RegExp(stringToReplace, "g"), template[iItem] );
	}

	return renderedTemplate;
} // end renderTemplate()

//////////////////////////////////////////////////////////////////////////
// Loads all templates inside of a given directory
Maker.prototype.loadTemplateDir = function( templateDir, callback ) {
	var _this = this;
	var templates = {};

	// Walk the folder tree recursively
	wrench.readdirRecursive( templateDir, function(error, files) {
		if( files == null ) {
			log( "Templates loaded from directory " + templateDir );
			_this.templates = templates;
			return callback( templates );
		}

		for( var iFile=0; iFile<files.length; ++iFile ) {
			if( files[iFile].indexOf(".tpl") == -1 )
				continue;

			var path = templateDir + "/" + files[iFile],
				file = fs.readFileSync( path, "utf8" );

			var templateName = basename( path );

			// Trim off the extension
			templateName = templateName.substring( 0, templateName.length - templateFileExtension.length );

			templates[templateName] = _this.template( file );
		}
	});
} // end loadTemplateDir()

//////////////////////////////////////////////////////////////////////////
// Parses a template string and returns an object of its contents
function parseTemplate( templateString, separationString ) {
	var iPosition = 0,
		matches = [],
		templateObj = {};

	iPosition = templateString.indexOf( separationString, iPosition );

	while( iPosition > 0 ) {
		matches.push( iPosition );

		iPosition = templateString.indexOf( separationString, iPosition+1 );
	}

	if( matches.length % 2 != 0 ) {
		log( "Error while parsing template: Mismatched separation string" );
	}

	for( var iItem = 0; iItem < matches.length; iItem += 2 ) {
		var strItem = templateString.substring( matches[iItem] + separationString.length, matches[iItem+1] );

		templateObj[strItem] = {};
	}

	// Attach the original template string onto the parsed template object, so that
	// we can reconstruct it later
	templateObj.__fullTemplateString__= templateString;
	templateObj.__templateMatches__ = matches;

	return templateObj;
} // end parseTemplate()<|endoftext|>


<commit_before>'use strict';

(function () {
    angular.module("medCheckApp");
    var app = angular.module("medCheckApp");

    app.controller("MainCtrl", ["$rootScope", "$scope", "$http", "openFDA", "$q", "$timeout", "quagga", "$location", "$anchorScroll", "Auth", "User", function ($rootScope, $scope, $http, openFDA, $q, $timeout, quagga, $location, $anchorScroll, Auth, User) {
            // Display a warning toast, with no title
            try {
                toastr.warning('Prototype demonstration, not for actual medical use.', 'MedCheck Prototype', {
                    timeOut: 5000
                });
            } catch (e) { /* I'm so sorry */ }

            $scope.SearchValue = "";  //0075609000935, 0840986023781
            //$scope.MedicationName = "Advil";

            $scope.allergens = [{ name: "" }];
            $scope.showAllergen = false;
            $scope.showAge = false;
            $scope.showPregnant = false;
            $scope.ingredientNamesChecked = {};
            $scope.ageChoices = [{ minAge: 0, maxAge: 1, label: "12 months and under" }, { minAge: 1, maxAge: 5, label: "13 months - 5 years" }, { minAge: 5, maxAge: 12, label: "5 years - 12 years" }, { minAge: 13, maxAge: 100, label: "Over 12" }];
            $scope.selectedAge = {};
            $scope.nursingOrPregnant = false;
            $scope.cameraVisible = false;

            //Profile Scopes
            $scope.isLoggedIn = Auth.isLoggedIn;
            $scope.user = Auth.getCurrentUser();
            $scope.user.profiles =  $scope.user.profiles;

            $scope.startCamera = function () {
                quagga.start();
                $scope.cameraVisible = true;
                quagga.onDetected(function (result) {

                    var code = result.codeResult.code;
                    try {
                        $scope.stopCamera();
                    } catch (e) { } //seems to be a bug in quaggaJS when you start and stop

                    $scope.SearchValue = code;

                    toastr.success('Found barcode: ' + code, 'Scanned UPC code successfully', {
                        timeOut: 3000
                    });

                    $timeout(function () {
                        //make sure apply gets called
                    }, 0);

                });
            };

            $scope.stopCamera = function () {
                $scope.cameraVisible = false;
                quagga.stop();
            };

            function resetFields() {
                $scope.ShowBrandNotFoundErrorMessage = false;
                $scope.ShowNotFoundErrorMessage = false;
                $scope.ProductModel = null;
                $scope.BrandProductModels = null;
            }

            function verifyIngredients() {
                var ingredientCalls = [];
                angular.forEach($scope.allergens, function (item) {
                    if (item.name !== "") {
                        if (!$scope.ingredientNamesChecked.hasOwnProperty(item.name)) {
                            ingredientCalls.push(openFDA.findIngredient(item.name));
                        }
                    }
                });

                function processResults(data) {
                    for (var i = 0; i < data.length; i++) {
                        $scope.ingredientNamesChecked[data[i].ingredient] = true;
                        for (var j = 0; j < $scope.allergens.length; j++) {
                            if (data[i].ingredient === $scope.allergens[j].name) {
                                $scope.allergens[j].invalidIngredient = data[i].not_found;
                                break;
                            }
                        }
                    }
                    $('[data-toggle="tooltip"]').tooltip();
                }

                $q.allSettled(ingredientCalls).then(processResults, processResults);
            }

            $scope.SearchChanged = function () {
                resetFields();
            };

            $scope.BrandChanged = function () {
                resetFields();
            };

            $scope.removeAllergen = function (allergen) {
                console.log(allergen);
                $scope.allergens.splice($scope.allergens.indexOf(allergen), 1);
                if ($scope.allergens.length === 0) {
                    $scope.addAllergen();
                }
            };

            $scope.addAllergen = function () {
                $("#allergyFocusElement").removeAttr("id");
                $scope.allergens.push({ name: "" });
                $timeout(function () {
                    $("#allergyFocusElement").focus();
                }, 0);

                verifyIngredients();
            };

            $scope.findBrand = function () {

                openFDA.findByBrandName($scope.SearchValue).then(
                    function (products) {
                        $scope.BrandProductModels = products;
                        $location.hash('productSearchList');
                        $anchorScroll();
                    },

                    function (err) {
                        if (err.not_found) {
                            $scope.ShowBrandNotFoundErrorMessage = true;
                        } else {
                            console.log(err.resp);
                            toastr.error('Error when trying to find products by brand', 'Ah, Snap!');
                        }
                    });
            };

            $scope.performSearch = function (isValid) {
                if (isValid) {
                    verifyIngredients();

                    if ($scope.SearchValue.match(/^\d+$/)) {
                        $scope.scanBarCode();
                    }
                    else {
                        $scope.findBrand();
                    }
                }
            };

            $scope.selectProduct = function (product) {
                $scope.BrandProductModels = null;

                if($scope.isLoggedIn()){

                    console.log($scope.user);
                    console.log($scope.user.profiles);

                    //Prints User Profiles
                    for (var profile in $scope.user.profiles) {
                        if ($scope.user.profiles.hasOwnProperty(profile)) {

                            //Profiles
                            //console.log($scope.user.profiles[profile].profilename);
                           // console.log($scope.user.profiles[profile].age);
                           // console.log($scope.user.profiles[profile].avatar);
                           // console.log($scope.user.profiles[profile].gender);
                           // console.log($scope.user.profiles[profile].pregnant);
                           // console.log($scope.user.profiles[profile]._id);
                           // console.log($scope.user.profiles[profile].createdAt);

                            //Allergens
                            for (var allergen in $scope.user.profiles[profile].allergens) {
                               if ($scope.user.profiles[profile].allergens.hasOwnProperty(allergen)) {
                                 //  console.log($scope.user.profiles[profile].allergens[allergen].name);
                               }
                            };
                        }
                    };

                   //Temp code to perform test with oAuth - TO BE REMOVED
                   console.log($rootScope.AmIPrego);
                   $rootScope.AmIPrego = "No you are not Pregnant";
                   console.log($rootScope.AmIPrego);

                } else {

                    console.log('User Not Logged In');
                }

                var allergenNames = _.map($scope.allergens, function (x) { return x.name.toLowerCase().trim(); });
                var ingredientNames = _.map(product.Ingredients, function (x) { return x.Name.toLowerCase().trim(); });

                product.BadIngredients = _.filter(ingredientNames, function (ingredient) {
                    return _.find(allergenNames, function (allergen) {
                        return ingredient.indexOf(allergen) > -1 && allergen !== "";
                    });
                });

                if (!$scope.selectedAge.selected) {
                    product.ShowAgeWarning = false;
                }
                else {
                    product.ShowAgeWarning = product.minimumAge >= $scope.selectedAge.selected.maxAge || (product.minimumAge <= $scope.selectedAge.selected.maxAge && product.minimumAge >= $scope.selectedAge.selected.minAge);
                }

                $scope.ProductModel = product;
            };

            $scope.scanBarCode = function () {
                return openFDA.findByUPC($scope.SearchValue).then(
                    function (product) {
                        $scope.selectProduct(product);
                    },
                    function (err) {
                        if (err.not_found) {
                            $scope.ShowNotFoundErrorMessage = true;
                        } else {
                            console.log(err.resp);
                            toastr.error('Error when trying to find a UPC code', 'Ah, Snap!');
                        }
                    });
            };
        }
    ]);

})();
<commit_msg>Testing scope change<commit_after>'use strict';

(function () {
    angular.module("medCheckApp");
    var app = angular.module("medCheckApp");

    app.controller("MainCtrl", ["$rootScope", "$scope", "$http", "openFDA", "$q", "$timeout", "quagga", "$location", "$anchorScroll", "Auth", "User", function ($rootScope, $scope, $http, openFDA, $q, $timeout, quagga, $location, $anchorScroll, Auth, User) {
            // Display a warning toast, with no title
            try {
                toastr.warning('Prototype demonstration, not for actual medical use.', 'MedCheck Prototype', {
                    timeOut: 5000
                });
            } catch (e) { /* I'm so sorry */ }

            $scope.SearchValue = "";  //0075609000935, 0840986023781
            //$scope.MedicationName = "Advil";

            $scope.allergens = [{ name: "" }];
            $scope.showAllergen = false;
            $scope.showAge = false;
            $scope.showPregnant = false;
            $scope.ingredientNamesChecked = {};
            $scope.ageChoices = [{ minAge: 0, maxAge: 1, label: "12 months and under" }, { minAge: 1, maxAge: 5, label: "13 months - 5 years" }, { minAge: 5, maxAge: 12, label: "5 years - 12 years" }, { minAge: 13, maxAge: 100, label: "Over 12" }];
            $scope.selectedAge = {};
            $scope.nursingOrPregnant = false;
            $scope.cameraVisible = false;

            //Profile Scopes
            $scope.isLoggedIn = Auth.isLoggedIn;
            $scope.user = Auth.getCurrentUser();
            $scope.user.profiles =  $scope.user.profiles;

            $scope.startCamera = function () {
                quagga.start();
                $scope.cameraVisible = true;
                quagga.onDetected(function (result) {

                    var code = result.codeResult.code;
                    try {
                        $scope.stopCamera();
                    } catch (e) { } //seems to be a bug in quaggaJS when you start and stop

                    $scope.SearchValue = code;

                    toastr.success('Found barcode: ' + code, 'Scanned UPC code successfully', {
                        timeOut: 3000
                    });

                    $timeout(function () {
                        //make sure apply gets called
                    }, 0);

                });
            };

            $scope.stopCamera = function () {
                $scope.cameraVisible = false;
                quagga.stop();
            };

            function resetFields() {
                $scope.ShowBrandNotFoundErrorMessage = false;
                $scope.ShowNotFoundErrorMessage = false;
                $scope.ProductModel = null;
                $scope.BrandProductModels = null;
            }

            function verifyIngredients() {
                var ingredientCalls = [];
                angular.forEach($scope.allergens, function (item) {
                    if (item.name !== "") {
                        if (!$scope.ingredientNamesChecked.hasOwnProperty(item.name)) {
                            ingredientCalls.push(openFDA.findIngredient(item.name));
                        }
                    }
                });

                function processResults(data) {
                    for (var i = 0; i < data.length; i++) {
                        $scope.ingredientNamesChecked[data[i].ingredient] = true;
                        for (var j = 0; j < $scope.allergens.length; j++) {
                            if (data[i].ingredient === $scope.allergens[j].name) {
                                $scope.allergens[j].invalidIngredient = data[i].not_found;
                                break;
                            }
                        }
                    }
                    $('[data-toggle="tooltip"]').tooltip();
                }

                $q.allSettled(ingredientCalls).then(processResults, processResults);
            }

            $scope.SearchChanged = function () {
                resetFields();
            };

            $scope.BrandChanged = function () {
                resetFields();
            };

            $scope.removeAllergen = function (allergen) {
                console.log(allergen);
                $scope.allergens.splice($scope.allergens.indexOf(allergen), 1);
                if ($scope.allergens.length === 0) {
                    $scope.addAllergen();
                }
            };

            $scope.addAllergen = function () {
                $("#allergyFocusElement").removeAttr("id");
                $scope.allergens.push({ name: "" });
                $timeout(function () {
                    $("#allergyFocusElement").focus();
                }, 0);

                verifyIngredients();
            };

            $scope.findBrand = function () {

                openFDA.findByBrandName($scope.SearchValue).then(
                    function (products) {
                        $scope.BrandProductModels = products;
                        $location.hash('productSearchList');
                        $anchorScroll();
                    },

                    function (err) {
                        if (err.not_found) {
                            $scope.ShowBrandNotFoundErrorMessage = true;
                        } else {
                            console.log(err.resp);
                            toastr.error('Error when trying to find products by brand', 'Ah, Snap!');
                        }
                    });
            };

            $scope.performSearch = function (isValid) {
                if (isValid) {
                    verifyIngredients();

                    if ($scope.SearchValue.match(/^\d+$/)) {
                        $scope.scanBarCode();
                    }
                    else {
                        $scope.findBrand();
                    }
                }
            };

            $scope.selectProduct = function (product) {
                $scope.BrandProductModels = null;

                //Temp code to perform test with oAuth - TO BE REMOVED
                   console.log($rootScope.AmIPrego);
                   $rootScope.AmIPrego = "No you are not Pregnant";
                   console.log($rootScope.AmIPrego);

                if($scope.isLoggedIn()){

                    console.log($scope.user);
                    console.log($scope.user.profiles);

                    //Prints User Profiles
                    for (var profile in $scope.user.profiles) {
                        if ($scope.user.profiles.hasOwnProperty(profile)) {

                            //Profiles
                            //console.log($scope.user.profiles[profile].profilename);
                           // console.log($scope.user.profiles[profile].age);
                           // console.log($scope.user.profiles[profile].avatar);
                           // console.log($scope.user.profiles[profile].gender);
                           // console.log($scope.user.profiles[profile].pregnant);
                           // console.log($scope.user.profiles[profile]._id);
                           // console.log($scope.user.profiles[profile].createdAt);

                            //Allergens
                            for (var allergen in $scope.user.profiles[profile].allergens) {
                               if ($scope.user.profiles[profile].allergens.hasOwnProperty(allergen)) {
                                 //  console.log($scope.user.profiles[profile].allergens[allergen].name);
                               }
                            };
                        }
                    };

                } else {

                    console.log('User Not Logged In');
                }

                var allergenNames = _.map($scope.allergens, function (x) { return x.name.toLowerCase().trim(); });
                var ingredientNames = _.map(product.Ingredients, function (x) { return x.Name.toLowerCase().trim(); });

                product.BadIngredients = _.filter(ingredientNames, function (ingredient) {
                    return _.find(allergenNames, function (allergen) {
                        return ingredient.indexOf(allergen) > -1 && allergen !== "";
                    });
                });

                if (!$scope.selectedAge.selected) {
                    product.ShowAgeWarning = false;
                }
                else {
                    product.ShowAgeWarning = product.minimumAge >= $scope.selectedAge.selected.maxAge || (product.minimumAge <= $scope.selectedAge.selected.maxAge && product.minimumAge >= $scope.selectedAge.selected.minAge);
                }

                $scope.ProductModel = product;
            };

            $scope.scanBarCode = function () {
                return openFDA.findByUPC($scope.SearchValue).then(
                    function (product) {
                        $scope.selectProduct(product);
                    },
                    function (err) {
                        if (err.not_found) {
                            $scope.ShowNotFoundErrorMessage = true;
                        } else {
                            console.log(err.resp);
                            toastr.error('Error when trying to find a UPC code', 'Ah, Snap!');
                        }
                    });
            };
        }
    ]);

})();
<|endoftext|>


<commit_before>//	smsneaky_client.js
//
var convDiv = "div#convDiv";
var contactInput = "input#contactInput";
var messageInput = "textarea#messageInput";
var optionsLink  = "a#optionsLink";

$(document).ready(function() {
	$.ajaxSetup({contentType: "application/json; charset=utf-8"});
	populateConversationList();

	$(contactInput).on({
		input:		selectConversation,
		select:		selectConversation,
		change:		selectConversation,
		keydown:	handleContactKeyPress
	});
	$(messageInput).keydown(handleMessageKeyPress);

	function tog(v) {
		return v ? 'addClass' : 'removeClass';
	}
	$(document).on('input', '.clearable', function() {
		$(this)[tog(this.value)]('x');
	}).on('mousemove', '.x', function( e ){
		$(this)[tog(this.offsetWidth-18 < e.clientX-this.getBoundingClientRect().left)]('onX');
	}).on('touchstart click', '.onX', function( ev ){
		ev.preventDefault();
		$(this).removeClass('x onX').val('').change();
	});

	$(optionsLink).click(openOptionsDialog);

	var socket = io();
	socket.on('incoming', routeIncomingText);
});

function openOptionsDialog() {

}

function routeIncomingText(txtData) {

}

//	do stuff when key is pressed at [contact] input
function handleContactKeyPress(e) {
	switch(e.keyCode) {
		case 27:
			$(contactInput).val('');
			$(convDiv).empty();
			break;

		case 9:
		case 13:
			selectConversation();
			break;
	}
}

//	do stuff when key is pressed from [message]
function handleMessageKeyPress(e) {
	switch(e.which) {
		case 9:
			$(contactInput).focus();
			break;

		//	user pressed 'enter' key, check for alt/ctrl modifier
		case 13:
			if(e.altKey)
			sendMessage();
			break;

		//	user pressed 'esc' key, clear out message entry text
		case 27:
			$(messageInput).val('');
			break;
	}
}

function selectConversation() {
	$(convDiv).empty();

	var selectedConversation = $(contactInput).val();
	if(!selectedConversation || !selectedConversation.length)
		return;

	var conversationUrl = '/conversation/' + selectedConversation;

	$.getJSON(conversationUrl, function(conversation) {
		$(messageInput).val('');

		//	[conversation] should be a timestamp-ordered list of message objects.
		loadConversation(conversation);
	});
}

function clearConversation() {
	var convMesssages = $(convDiv).children();
	$('div[id=convDiv] > p').empty();
}

function loadConversation(msgArray) {
	clearConversation();

	for(var i=0;i<msgArray.length;i++)
		appendMessageToConversation(msgArray[i]);

	scrollToEnd();
}

function appendMessageToConversation(msgObj) {
	if(!msgObj || !msgObj.type) {
		console.log('msgObj:');
		console.log(msgObj);
		return;
	}

	var msgID = 'msg_' + msgObj._id;
	var pClass = msgObj.type.startsWith('outbound') ? "fromMe" : "toMe";
	var newDiv = $("
").addClass("msgRowDiv").attr({id: msgID});
	var p = $("

").addClass(pClass);

	var time = $("").addClass('timeLabel').text(msgObj.dateTime);
	var br   = $("
");
	var data;

	var invalid = false;
	switch(msgObj.type) {
		case 'inboundText':
		case 'outboundText':
			data = $("").text(msgObj.data);
			break;

		case 'inboundMedia':
			var img_Blurred = $('')
				.addClass('blurImage')
				.attr({
					src:	msgObj.data,
					id:		'img_'+msgObj._id+'_blurred'
				});
			var img_Clear = $('')
				.addClass('clearImage')
				.attr({
					src:	msgObj.data,
					id:		'img_'+msgObj._id+'_clear'
				})

			data = $('

').addClass('imgContainer').append(img_Blurred);

			break;

		case 'voiceMail':
			data = $('<audio controls></audio>').addClass('mmsAudio');
			data.attr({src: msgObj.data});
			data.html($("").attr({href: msgObj.data}).text('Download '));
			break;
		default:
			console.log('Unknown message type: "'+msgObj.type+'"');
			invalid = true;
			break;
	}

	if(!invalid) {
		p.append(time, br, data);
		newDiv.append(p).hide();
		$(convDiv).append(newDiv);
		newDiv.fadeIn({queue: false});
	}
}

function scrollToEnd() {
	$(convDiv).animate({ scrollTop: $(convDiv).prop("scrollHeight")}, 250);
}

function recvMessage() {}

function sendMessage() {
	var msg = $(messageInput).val();
	var rec = $(contactInput).val();

	if(!msg)
		return;

	if(!rec)
		return alert('Please select a contact');

	var msgBlob = {
		contact:	rec,
		message:	msg
	};

	$.post("/outgoing", JSON.stringify(msgBlob))
	.done(function(data) {
		appendMessageToConversation(data);
		scrollToEnd();
		$(messageInput).val('');
	}).fail(function(err) {
		console.log('Error:   ' + err);
		alert('Error sending message: ' + err);
	});
}

function populateConversationList() {
	$.getJSON('/conversation', function(convList) {
		var contactDataList = $("datalist#contacts");
		contactDataList.empty();
		convList.map(function(item) {
			var newOptionElement = $('<option></option>').text(item.name || '?').attr({value: item.number});
			contactDataList.append(newOptionElement);
		});
	});
}

function embiggenPicture(imgID) {
	//	...
	var docWidth = $("div#mainDiv").width();
	var docHeight = $("div#mainDiv").height();
}

<commit_msg>fixed no show conversation bug<commit_after>//	smsneaky_client.js
//
var convDiv = "div#convDiv";
var contactInput = "input#contact";
var messageInput = "textarea#messageInput";
var optionsLink  = "a#optionsLink";

$(document).ready(function() {
	$.ajaxSetup({contentType: "application/json; charset=utf-8"});
	populateConversationList();

	$(contactInput).on({
		input:		selectConversation,
		select:		selectConversation,
		change:		selectConversation,
		keydown:	handleContactKeyPress
	});
	$(messageInput).keydown(handleMessageKeyPress);

	function tog(v) {
		return v ? 'addClass' : 'removeClass';
	}
	$(document).on('input', '.clearable', function() {
		$(this)[tog(this.value)]('x');
	}).on('mousemove', '.x', function( e ){
		$(this)[tog(this.offsetWidth-18 < e.clientX-this.getBoundingClientRect().left)]('onX');
	}).on('touchstart click', '.onX', function( ev ){
		ev.preventDefault();
		$(this).removeClass('x onX').val('').change();
	});

	$(optionsLink).click(openOptionsDialog);

	var socket = io();
	socket.on('incoming', routeIncomingText);
});

function openOptionsDialog() {

}

function routeIncomingText(txtData) {

}

//	do stuff when key is pressed at [contact] input
function handleContactKeyPress(e) {
	switch(e.keyCode) {
		case 27:
			$(contactInput).val('');
			$(convDiv).empty();
			break;

		case 9:
		case 13:
			selectConversation();
			break;
	}
}

//	do stuff when key is pressed from [message]
function handleMessageKeyPress(e) {
	switch(e.which) {
		case 9:
			$(contactInput).focus();
			break;

		//	user pressed 'enter' key, check for alt/ctrl modifier
		case 13:
			if(e.altKey)
			sendMessage();
			break;

		//	user pressed 'esc' key, clear out message entry text
		case 27:
			$(messageInput).val('');
			break;
	}
}

function selectConversation() {
	$(convDiv).empty();

	var selectedConversation = $(contactInput).val();
	if(!selectedConversation || !selectedConversation.length)
		return;

	var conversationUrl = '/conversation/' + selectedConversation;

	$.getJSON(conversationUrl, function(conversation) {
		$(messageInput).val('');

		//	[conversation] should be a timestamp-ordered list of message objects.
		loadConversation(conversation);
	});
}

function clearConversation() {
	var convMesssages = $(convDiv).children();
	$('div[id=convDiv] > p').empty();
}

function loadConversation(msgArray) {
	clearConversation();

	for(var i=0;i<msgArray.length;i++)
		appendMessageToConversation(msgArray[i]);

	scrollToEnd();
}

function appendMessageToConversation(msgObj) {
	if(!msgObj || !msgObj.type) {
		console.log('msgObj:');
		console.log(msgObj);
		return;
	}

	var msgID = 'msg_' + msgObj._id;
	var pClass = msgObj.type.startsWith('outbound') ? "fromMe" : "toMe";
	var newDiv = $("
").addClass("msgRowDiv").attr({id: msgID});
	var p = $("

").addClass(pClass);

	var time = $("").addClass('timeLabel').text(msgObj.dateTime);
	var br   = $("
");
	var data;

	var invalid = false;
	switch(msgObj.type) {
		case 'inboundText':
		case 'outboundText':
			data = $("").text(msgObj.data);
			break;

		case 'inboundMedia':
			var img_Blurred = $('')
				.addClass('blurImage')
				.attr({
					src:	msgObj.data,
					id:		'img_'+msgObj._id+'_blurred'
				});
			var img_Clear = $('')
				.addClass('clearImage')
				.attr({
					src:	msgObj.data,
					id:		'img_'+msgObj._id+'_clear'
				})

			data = $('

').addClass('imgContainer').append(img_Blurred);

			break;

		case 'voiceMail':
			data = $('<audio controls></audio>').addClass('mmsAudio');
			data.attr({src: msgObj.data});
			data.html($("").attr({href: msgObj.data}).text('Download '));
			break;
		default:
			console.log('Unknown message type: "'+msgObj.type+'"');
			invalid = true;
			break;
	}

	if(!invalid) {
		p.append(time, br, data);
		newDiv.append(p).hide();
		$(convDiv).append(newDiv);
		newDiv.fadeIn({queue: false});
	}
}

function scrollToEnd() {
	$(convDiv).animate({ scrollTop: $(convDiv).prop("scrollHeight")}, 250);
}

function recvMessage() {}

function sendMessage() {
	var msg = $(messageInput).val();
	var rec = $(contactInput).val();

	if(!msg)
		return;

	if(!rec)
		return alert('Please select a contact');

	var msgBlob = {
		contact:	rec,
		message:	msg
	};

	$.post("/outgoing", JSON.stringify(msgBlob))
	.done(function(data) {
		appendMessageToConversation(data);
		scrollToEnd();
		$(messageInput).val('');
	}).fail(function(err) {
		console.log('Error:   ' + err);
		alert('Error sending message: ' + err);
	});
}

function populateConversationList() {
	$.getJSON('/conversation', function(convList) {
		var contactDataList = $("datalist#contacts");
		contactDataList.empty();
		convList.map(function(item) {
			var newOptionElement = $('<option></option>').text(item.name || '?').attr({value: item.number});
			contactDataList.append(newOptionElement);
		});
	});
}

function embiggenPicture(imgID) {
	//	...
	var docWidth = $("div#mainDiv").width();
	var docHeight = $("div#mainDiv").height();
}

<|endoftext|>


<commit_before>const service = require('feathers-mongoose');
const { Forbidden, NotFound } = require('@feathersjs/errors');
const logger = require('winston');
const { newsModel, newsHistoryModel } = require('./model');
const hooks = require('./hooks');
const newsModelHooks = require('./hooks/model');
const { flatten, paginate, sort } = require('../../utils/array');

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

	/**
	 * Checks scoped permission for a user.
	 * @param {BsonId|String} userId
	 * @param {String} permission
	 * @param {BsonId|String} targetId (optional) news target (scope) id. Only valid with targetModel.
	 * @param {String} targetModel (optional) news target (scope) model. Only valid with target.
	 * @returns {Promise<Boolean>} Promise that resolves to true/false
	 * @example
	 * await hasPermission(user._id, 'NEWS_VIEW') => true
	 * await hasPermission(user._id, 'NEWS_CREATE', team._id, 'teams') => false
	 * @memberof NewsService
	 */
	async hasPermission(userId, permission, targetId, targetModel) {
		if (targetId && targetModel) {
			const scope = this.app.service(`${targetModel}/:scopeId/userPermissions/`);
			const params = { route: { scopeId: targetId.toString() } };
			const scopePermissions = await scope.get(userId, params);
			return scopePermissions.includes(permission);
		}
		const user = await this.app.service('users').get(userId);
		return user.permissions.includes(permission);
	}

	/**
	 * Throw an error if the user is not allowed to perform the given operation
	 * @param {News} news news item (required: {schoolId}, optional: {target, targetModel})
	 * @param {Object} { userId, schoolId }
	 * @param {String} permission permision to check
	 * @returns undefined
	 * @example
	 * await authorize(news, params.account, 'NEWS_VIEW') => undefined
	 * await authorize(news, params.account, 'NEWS_CREATE') => (throws Forbidden)
	 * @memberof NewsService
	 */
	async authorize(news = {}, { userId, schoolId } = {}, permission) {
		const authorized = await this.hasPermission(userId, permission, news.target, news.targetModel);
		const sameSchool = news.schoolId.toString() === schoolId.toString();
		if (!authorized || !sameSchool) {
			throw new Forbidden('Not authorized.');
		}
	}

	async getPermissions(news, { userId, schoolId } = {}, permissions) {
		const retValue = [];
		for (const key of Object.keys(permissions)) {
			try {
				await this.authorize(news, { userId, schoolId }, key);
				if (!retValue.includes(permissions[key])) {
					retValue.push(permissions[key]);
				}
			} catch (err) {
				// ignore
			}
		}
		news.permissions = retValue;
	}

	checkExistence(news, query) {
		if (!news) {
			logger.error(`Cannot find news item with query "${query}" => "${news}"`);
			throw new NotFound('News item does not exist.');
		}
	}

	/**
	 * Returns all school news the user is allowed to see.
	 * @param {Object} { userId, schoolId } -- The user's Id and schoolId
	 * @returns Array<News Document>
	 * @memberof NewsService
	 */
	async findSchoolNews({ userId, schoolId }) {
		if (!this.hasPermission(userId, 'NEWS_VIEW')) {
			throw new Forbidden('Mising permissions to view school news.');
		}
		const query = { schoolId, target: { $exists: false } };
		return this.app.service('newsModel').find({ query, paginate: false });
	}

	/**
	 * Returns scoped news the user is allowed to see
	 *
	 * @param {BsonId|String} userId the user's Id
	 * @param {BsonId|String} target (optional) Id of the news target (course, team, etc.)
	 * @returns Array<News Document>
	 * @memberof NewsService
	 */
	async findScopedNews(userId, target) {
		const scopes = await newsModel.distinct('targetModel');
		const ops = scopes.map(async (scope) => {
			// For each possible target model, find all targets the user has NEWS_VIEW permissions in.
			const scopeListService = this.app.service(`/users/:scopeId/${scope}`);
			if (scopeListService === undefined) {
				throw new Error(`Missing ScopeListService for scope "${scope}".`);
			}
			let scopeItems = await scopeListService.find({
				route: { scopeId: userId.toString() },
				query: { permissions: ['NEWS_VIEW'] },
			});
			if (target) {
				// if a target id is given, only return news from this target
				scopeItems = scopeItems.filter(i => i._id.toString() === target.toString());
			}
			return Promise.all(scopeItems.map(async (item) => {
				const query = {
					targetModel: scope,
					target: item._id,
					$populate: target,
				};
				const news = await this.app.service('newsModel').find({ query, paginate: false });
				// Manually populate the target (current API requires this):
				return Promise.all(news.map(async n => ({
					...n,
					target: await this.app.service(scope).get(n.target),
				})));
			}));
		});
		const results = await Promise.all(ops);
		return flatten(results);
	}

	/**
	 * Create a copy of the original news if it is edited
	 * @param {News} oldItem
	 * @returns {Promise<NewsHistory>} the created news history document
	 * @memberof NewsService
	 * @static
	 */
	static createHistoryEntry(oldItem) {
		const historyEntry = {
			title: oldItem.title,
			content: oldItem.content,
			displayAt: oldItem.displayAt,
			creatorId: oldItem.updaterId ? oldItem.updaterId : oldItem.creatorId,
			parentId: oldItem._id,
		};
		return newsHistoryModel.create(historyEntry);
	}

	/**
	 * GET /news/{id}
	 * Returns the news item specified by id
	 * @param {BsonId|String} id
	 * @param {Object} params
	 * @returns one news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async get(id, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_VIEW');
		await this.getPermissions(news, params.account, {
			NEWS_VIEW: 'view',
			NEWS_EDIT: 'edit',
		});
		return news;
	}

	/**
	 * GET /news/
	 * Returns all news the user can see.
	 * @param {Object} params
	 * @returns paginated array of news items
	 * @memberof NewsService
	 */
	async find(params) {
		let news = [];
		const scoped = params.query && params.query.target;
		if (scoped) {
			news = news.concat(await this.findScopedNews(params.account.userId, params.query.target));
		} else {
			news = news.concat(await this.findSchoolNews(params.account));
			news = news.concat(await this.findScopedNews(params.account.userId));
		}
		if (params.query) {
			news = sort(news, params.query.$sort);
		}
		// paginate by default, but let $paginate=false through
		news = paginate(news, { $paginate: true, ...params.query });
		return Promise.resolve(news);
	}

	/**
	 * POST /news/
	 * Creates a news item
	 * @param {Object} data @see NewsModel
	 * @param {Object} params
	 * @returns {News} the created news object
	 * @throws {Forbidden} if not authorized
	 * @memberof NewsService
	 */
	async create(data, params) {
		await this.authorize(data, params.account, 'NEWS_CREATE');
		return this.app.service('newsModel').create(data);
	}

	/**
	 * DELETE /news/{id}
	 * Deletes a single news item.
	 * @param {BsonId|String} id The news item's Id
	 * @param {Object} params Note that params.query won't work here
	 * @returns {News} the deleted news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async remove(id, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_CREATE');
		await this.app.service('newsModel').remove(id);
		return news;
	}

	/**
	 * PUT /news/{id}
	 * Replaces a single news item
	 * @param {BsonId|String} id The news item's Id
	 * @param {News} data updated news item
	 * @param {Object} params Feathers request params (note that using params.query won't work here)
	 * @returns {News} updated news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async update(id, data, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_EDIT');
		const updatedNews = await this.app.service('newsModel').update(id, data);
		await NewsService.createHistoryEntry(news);
		return updatedNews;
	}

	/**
	 * PATCH /news/{id}
	 * Patches a single news item
	 * @param {BsonId|String} id The news item's Id
	 * @param {Object} data object containing updated news item attributes
	 * @param {Object} params Feathers request params (note that using params.query won't work here)
	 * @returns {News} patched news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async patch(id, data, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_EDIT');
		const patchedNews = await this.app.service('newsModel').patch(id, data);
		await NewsService.createHistoryEntry(news);
		return patchedNews;
	}
}

module.exports = function news() {
	const app = this;

	// use /news to access a user's news
	app.use('/news', new NewsService());
	app.service('news').hooks(hooks);

	// use /newsModel to directly access the model from other services
	// (external requests are blocked)
	app.use('/newsModel', service({
		Model: newsModel,
		lean: true,
		paginate: {
			default: 25,
		},
	}));
	app.service('/newsModel').hooks(newsModelHooks);
};
<commit_msg>add permissions to other news lists exported from server<commit_after>const service = require('feathers-mongoose');
const { Forbidden, NotFound } = require('@feathersjs/errors');
const logger = require('winston');
const { newsModel, newsHistoryModel } = require('./model');
const hooks = require('./hooks');
const newsModelHooks = require('./hooks/model');
const { flatten, paginate, sort } = require('../../utils/array');

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

	/**
	 * Checks scoped permission for a user.
	 * @param {BsonId|String} userId
	 * @param {String} permission
	 * @param {BsonId|String} targetId (optional) news target (scope) id. Only valid with targetModel.
	 * @param {String} targetModel (optional) news target (scope) model. Only valid with target.
	 * @returns {Promise<Boolean>} Promise that resolves to true/false
	 * @example
	 * await hasPermission(user._id, 'NEWS_VIEW') => true
	 * await hasPermission(user._id, 'NEWS_CREATE', team._id, 'teams') => false
	 * @memberof NewsService
	 */
	async hasPermission(userId, permission, targetId, targetModel) {
		if (targetId && targetModel) {
			const scope = this.app.service(`${targetModel}/:scopeId/userPermissions/`);
			const params = { route: { scopeId: targetId.toString() } };
			const scopePermissions = await scope.get(userId, params);
			return scopePermissions.includes(permission);
		}
		const user = await this.app.service('users').get(userId);
		return user.permissions.includes(permission);
	}

	/**
	 * Throw an error if the user is not allowed to perform the given operation
	 * @param {News} news news item (required: {schoolId}, optional: {target, targetModel})
	 * @param {Object} { userId, schoolId }
	 * @param {String} permission permision to check
	 * @returns undefined
	 * @example
	 * await authorize(news, params.account, 'NEWS_VIEW') => undefined
	 * await authorize(news, params.account, 'NEWS_CREATE') => (throws Forbidden)
	 * @memberof NewsService
	 */
	async authorize(news = {}, { userId, schoolId } = {}, permission) {
		const authorized = await this.hasPermission(userId, permission, news.target, news.targetModel);
		const sameSchool = news.schoolId.toString() === schoolId.toString();
		if (!authorized || !sameSchool) {
			throw new Forbidden('Not authorized.');
		}
	}

	async getPermissions(news, { userId, schoolId } = {}, permissions) {
		const retValue = [];
		for (const key of Object.keys(permissions)) {
			try {
				await this.authorize(news, { userId, schoolId }, key);
				if (!retValue.includes(permissions[key])) {
					retValue.push(permissions[key]);
				}
			} catch (err) {
				// ignore
			}
		}
		return retValue;
	}

	checkExistence(news, query) {
		if (!news) {
			logger.error(`Cannot find news item with query "${query}" => "${news}"`);
			throw new NotFound('News item does not exist.');
		}
	}

	/**
	 * Returns all school news the user is allowed to see.
	 * @param {Object} { userId, schoolId } -- The user's Id and schoolId
	 * @returns Array<News Document>
	 * @memberof NewsService
	 */
	async findSchoolNews({ userId, schoolId }) {
		if (!this.hasPermission(userId, 'NEWS_VIEW')) {
			throw new Forbidden('Mising permissions to view school news.');
		}
		const query = { schoolId, target: { $exists: false } };
		return this.app.service('newsModel').find({ query, paginate: false });
	}

	/**
	 * Returns scoped news the user is allowed to see
	 *
	 * @param {BsonId|String} userId the user's Id
	 * @param {BsonId|String} target (optional) Id of the news target (course, team, etc.)
	 * @returns Array<News Document>
	 * @memberof NewsService
	 */
	async findScopedNews({ userId, schoolId }, target) {
		const scopes = await newsModel.distinct('targetModel');
		const ops = scopes.map(async (scope) => {
			// For each possible target model, find all targets the user has NEWS_VIEW permissions in.
			const scopeListService = this.app.service(`/users/:scopeId/${scope}`);
			if (scopeListService === undefined) {
				throw new Error(`Missing ScopeListService for scope "${scope}".`);
			}
			let scopeItems = await scopeListService.find({
				route: { scopeId: userId.toString() },
				query: { permissions: ['NEWS_VIEW'] },
			});
			if (target) {
				// if a target id is given, only return news from this target
				scopeItems = scopeItems.filter(i => i._id.toString() === target.toString());
			}
			return Promise.all(scopeItems.map(async (item) => {
				const query = {
					targetModel: scope,
					target: item._id,
					$populate: target,
				};
				const news = await this.app.service('newsModel').find({ query, paginate: false });
				// Manually populate the target (current API requires this):
				return Promise.all(news.map(async n => ({
					...n,
					target: await this.app.service(scope).get(n.target),
					permissions: await this.getPermissions(n, { userId, schoolId }, {
						NEWS_VIEW: 'view',
						NEWS_EDIT: 'edit',
					}),
				})));
			}));
		});
		const results = await Promise.all(ops);
		return flatten(results);
	}

	/**
	 * Create a copy of the original news if it is edited
	 * @param {News} oldItem
	 * @returns {Promise<NewsHistory>} the created news history document
	 * @memberof NewsService
	 * @static
	 */
	static createHistoryEntry(oldItem) {
		const historyEntry = {
			title: oldItem.title,
			content: oldItem.content,
			displayAt: oldItem.displayAt,
			creatorId: oldItem.updaterId ? oldItem.updaterId : oldItem.creatorId,
			parentId: oldItem._id,
		};
		return newsHistoryModel.create(historyEntry);
	}

	/**
	 * GET /news/{id}
	 * Returns the news item specified by id
	 * @param {BsonId|String} id
	 * @param {Object} params
	 * @returns one news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async get(id, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_VIEW');
		news.permissions = await this.getPermissions(news, params.account, {
			NEWS_VIEW: 'view',
			NEWS_EDIT: 'edit',
		});
		return news;
	}

	/**
	 * GET /news/
	 * Returns all news the user can see.
	 * @param {Object} params
	 * @returns paginated array of news items
	 * @memberof NewsService
	 */
	async find(params) {
		let news = [];
		const scoped = params.query && params.query.target;
		if (scoped) {
			news = news.concat(await this.findScopedNews(params.account, params.query.target));
		} else {
			news = news.concat(await this.findSchoolNews(params.account));
			news = news.concat(await this.findScopedNews(params.account));
		}
		if (params.query) {
			news = sort(news, params.query.$sort);
		}
		// paginate by default, but let $paginate=false through
		news = paginate(news, { $paginate: true, ...params.query });
		return Promise.resolve(news);
	}

	/**
	 * POST /news/
	 * Creates a news item
	 * @param {Object} data @see NewsModel
	 * @param {Object} params
	 * @returns {News} the created news object
	 * @throws {Forbidden} if not authorized
	 * @memberof NewsService
	 */
	async create(data, params) {
		await this.authorize(data, params.account, 'NEWS_CREATE');
		return this.app.service('newsModel').create(data);
	}

	/**
	 * DELETE /news/{id}
	 * Deletes a single news item.
	 * @param {BsonId|String} id The news item's Id
	 * @param {Object} params Note that params.query won't work here
	 * @returns {News} the deleted news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async remove(id, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_CREATE');
		await this.app.service('newsModel').remove(id);
		return news;
	}

	/**
	 * PUT /news/{id}
	 * Replaces a single news item
	 * @param {BsonId|String} id The news item's Id
	 * @param {News} data updated news item
	 * @param {Object} params Feathers request params (note that using params.query won't work here)
	 * @returns {News} updated news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async update(id, data, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_EDIT');
		const updatedNews = await this.app.service('newsModel').update(id, data);
		await NewsService.createHistoryEntry(news);
		return updatedNews;
	}

	/**
	 * PATCH /news/{id}
	 * Patches a single news item
	 * @param {BsonId|String} id The news item's Id
	 * @param {Object} data object containing updated news item attributes
	 * @param {Object} params Feathers request params (note that using params.query won't work here)
	 * @returns {News} patched news item
	 * @throws {Forbidden} if not authorized
	 * @throws {NotFound} if the id does not belong to a news object
	 * @memberof NewsService
	 */
	async patch(id, data, params) {
		const news = await this.app.service('newsModel').get(id);
		this.checkExistence(news, id);
		await this.authorize(news, params.account, 'NEWS_EDIT');
		const patchedNews = await this.app.service('newsModel').patch(id, data);
		await NewsService.createHistoryEntry(news);
		return patchedNews;
	}
}

module.exports = function news() {
	const app = this;

	// use /news to access a user's news
	app.use('/news', new NewsService());
	app.service('news').hooks(hooks);

	// use /newsModel to directly access the model from other services
	// (external requests are blocked)
	app.use('/newsModel', service({
		Model: newsModel,
		lean: true,
		paginate: {
			default: 25,
		},
	}));
	app.service('/newsModel').hooks(newsModelHooks);
};
<|endoftext|>