<commit_before>/*
 * jquery.mousehover
 * https://github.com/prantlf/jquery.mousehover
 *
 * Copyright (c) 2017 Ferdinand Prantl
 * Licensed under the MIT license.
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    factory(require('jquery'));
  } else {
    factory(jQuery);
  }
}(function ($) {
  'use strict';

  // Remember the existing mousehover plugin, if there is any, to be able
  // to restore it by calling noConflict.
  var oldMousehover = $.fn.mousehover,
      eventTimeProperty;

  // Convert any combination of input parametrs to the parameters object,
  // which has the same structure and all values available.
  // Arguments:
  // .mousehover(handlerIn)
  // .mousehover(handlerIn, handlerOut)
  // .mousehover(handlerIn, options)
  // .mousehover(handlerIn, handlerOut, options)
  // .mousehover({handlerIn, handlerOut, options})
  // .mousehover('off')
  // .mousehover('off', options)
  // Result:
  // .handlerIn:  function
  // .handlerOut: function
  // .namespace:  string (empty or starting with '.')
  function normalizeParameters(handlerIn, handlerOut, options) {
    var namespace;
    if (typeof handlerIn === 'object') {
      return handlerIn;
    }
    // The first parameter has to be always present. Function handler,
    // string method name, or an object literal.
    if (!handlerIn) {
      throw new Error('Missing event handler or method.');
    }
    if (!options) {
      options = typeof handlerOut === 'object' ? handlerOut : {};
    }
    // Prepend '.' to allow simple concatenation of the namespace.
    namespace = options.namespace;
    namespace = namespace ? '.' + namespace : '';
    // There is just one method supported right now - "off". It will be
    // detected by the missing "handlerIn"" parameter.
    if (typeof handlerIn === 'string') {
      if (handlerIn !== 'off') {
        throw new Error('Unsupported method.')
      }
      return {
        namespace: namespace
      };
    }
    return {
      handlerIn: handlerIn,
      handlerOut: typeof handlerOut === 'function' ? handlerOut : handlerIn,
      namespace: namespace
    };
  }

  // If the browser supports pointer events, we can detect mouse reliably.
  if ('onpointerenter' in window) {
    $.fn.mousehover = function (handlerIn, handlerOut, options) {
      var parameters = normalizeParameters(handlerIn, handlerOut, options),
          namespace = parameters.namespace;
      handlerIn = parameters.handlerIn;
      // Missing "handlerIn" parameter means, that existing event handlers
      // should be unregistered.
      if (!handlerIn) {
        return this.off('pointerenter' + namespace +
                        ' pointerleave' + namespace);
      }
      handlerOut = parameters.handlerOut;
      return this.on('pointerenter' + namespace, function (event) {
                   if (event.pointerType === 'mouse') {
                     handlerIn.call(this, event);
                   }
                 })
                 .on('pointerleave' + namespace, function (event) {
                   if (event.pointerType === 'mouse') {
                     handlerOut.call(this, event);
                   }
                 });
    };

  // If the browser has support for touch events, the mouseenter and
  // mouseleave events can be emulated on tapping the display.
  } else if ('ontouchstart' in window) {
    eventTimeProperty = 'mousehover-start';
    $.fn.mousehover = function (handlerIn, handlerOut, options) {
      var parameters = normalizeParameters(handlerIn, handlerOut, options),
          namespace = parameters.namespace;
      handlerIn = parameters.handlerIn;
      // Missing "handlerIn" parameter means, that existing event handlers
      // should be unregistered.
      if (!handlerIn) {
        return this.off('touchend' + namespace +
                        ' mouseenter' + namespace +
                        ' mouseleave' + namespace);
      }
      handlerOut = parameters.handlerOut;
      // Store the time of the event, which would shortly preceed the
      // mouseenter event on touch-capable devices, if it were an emulated
      // mouse event caused by tapping the display.
      return this.on('touchend' + namespace, function() {
                   $(this).data(eventTimeProperty, new Date().getTime());
                 })
                 // If the first event handler remembered its time and the
                 // mouseenter event comes too soon, it was triggered by
                 // tapping and should be ignored.
                 .on('mouseenter' + namespace, function (event) {
                   var $this = $(this),
                       once = $this.data(eventTimeProperty),
                       now;
                   if (once) {
                     now = new Date().getTime();
                     // The time interval between the touchend event, which
                     // can identify, that the mouseenter event was emulated,
                     // and the mouseenter event itself can vary.
                     if (now - once < 50) {
                       return $(this).removeData(eventTimeProperty);
                     }
                   }
                   // Enable handling of the complementary mouseleave event.
                   $(this).data(eventTimeProperty, true);
                   handlerIn.call(this, event);
                 })
                 // The mouseleave event should call the hover event handler
                 // only if it was triggered by the mouseenter event earlier.
                 .on('mouseleave' + namespace, function (event) {
                   var $this = $(this);
                   if ($this.data(eventTimeProperty)) {
                     $this.removeData(eventTimeProperty);
                     handlerOut.call(this, event);
                   }
                 });
    };

  // If the browser has no support for touch events, we can assume, that
  // the only device, which can trigger the mouseenter eveny, is the mouse.
  } else {
    // Default to jQuery.hover behaviour on devices without touch capability.
    $.fn.mousehover = function (handlerIn, handlerOut, options) {
      var parameters = normalizeParameters(handlerIn, handlerOut, options),
          namespace = parameters.namespace;
      handlerIn = parameters.handlerIn;
      // Missing "handlerIn" parameter means, that existing event handlers
      // should be unregistered.
      if (!handlerIn) {
        return this.off('mouseenter' + namespace +
                        ' mouseleave' + namespace);
      }
      handlerOut = parameters.handlerOut;
      return this.on('mouseenter' + namespace, handlerIn)
                 .on('mouseleave' + namespace, handlerOut);
    };
  }

  // Restores the earlier mousehover plugin, which had been registered in
  // jQuery before this one. This plugin is returned for explicit usage.
  $.fn.mousehover.noConflict = function () {
    $.fn.mousehover = oldMousehover;
    return this;
  };

  return $;
}));
<commit_msg>Fix checking the pointer event type<commit_after>/*
 * jquery.mousehover 0.2.1
 * https://github.com/prantlf/jquery.mousehover
 *
 * Copyright (c) 2017 Ferdinand Prantl
 * Licensed under the MIT license.
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    factory(require('jquery'));
  } else {
    factory(jQuery);
  }
}(function ($) {
  'use strict';

  // Remember the existing mousehover plugin, if there is any, to be able
  // to restore it by calling noConflict.
  var oldMousehover = $.fn.mousehover,
      eventTimeProperty;

  // Convert any combination of input parametrs to the parameters object,
  // which has the same structure and all values available.
  // Arguments:
  // .mousehover(handlerIn)
  // .mousehover(handlerIn, handlerOut)
  // .mousehover(handlerIn, options)
  // .mousehover(handlerIn, handlerOut, options)
  // .mousehover({handlerIn, handlerOut, options})
  // .mousehover('off')
  // .mousehover('off', options)
  // Result:
  // .handlerIn:  function
  // .handlerOut: function
  // .namespace:  string (empty or starting with '.')
  function normalizeParameters(handlerIn, handlerOut, options) {
    var namespace;
    if (typeof handlerIn === 'object') {
      return handlerIn;
    }
    // The first parameter has to be always present. Function handler,
    // string method name, or an object literal.
    if (!handlerIn) {
      throw new Error('Missing event handler or method.');
    }
    if (!options) {
      options = typeof handlerOut === 'object' ? handlerOut : {};
    }
    // Prepend '.' to allow simple concatenation of the namespace.
    namespace = options.namespace;
    namespace = namespace ? '.' + namespace : '';
    // There is just one method supported right now - "off". It will be
    // detected by the missing "handlerIn"" parameter.
    if (typeof handlerIn === 'string') {
      if (handlerIn !== 'off') {
        throw new Error('Unsupported method.')
      }
      return {
        namespace: namespace
      };
    }
    return {
      handlerIn: handlerIn,
      handlerOut: typeof handlerOut === 'function' ? handlerOut : handlerIn,
      namespace: namespace
    };
  }

  // If the browser supports pointer events, we can detect mouse reliably.
  if ('onpointerenter' in window) {
    $.fn.mousehover = function (handlerIn, handlerOut, options) {
      var parameters = normalizeParameters(handlerIn, handlerOut, options),
          namespace = parameters.namespace;
      handlerIn = parameters.handlerIn;
      // Missing "handlerIn" parameter means, that existing event handlers
      // should be unregistered.
      if (!handlerIn) {
        return this.off('pointerenter' + namespace +
                        ' pointerleave' + namespace);
      }
      handlerOut = parameters.handlerOut;
      return this.on('pointerenter' + namespace, function (event) {
                   if (event.originalEvent.pointerType === 'mouse') {
                     handlerIn.call(this, event);
                   }
                 })
                 .on('pointerleave' + namespace, function (event) {
                   if (event.originalEvent.pointerType === 'mouse') {
                     handlerOut.call(this, event);
                   }
                 });
    };

  // If the browser has support for touch events, the mouseenter and
  // mouseleave events can be emulated on tapping the display.
  } else if ('ontouchstart' in window) {
    eventTimeProperty = 'mousehover-start';
    $.fn.mousehover = function (handlerIn, handlerOut, options) {
      var parameters = normalizeParameters(handlerIn, handlerOut, options),
          namespace = parameters.namespace;
      handlerIn = parameters.handlerIn;
      // Missing "handlerIn" parameter means, that existing event handlers
      // should be unregistered.
      if (!handlerIn) {
        return this.off('touchend' + namespace +
                        ' mouseenter' + namespace +
                        ' mouseleave' + namespace);
      }
      handlerOut = parameters.handlerOut;
      // Store the time of the event, which would shortly preceed the
      // mouseenter event on touch-capable devices, if it were an emulated
      // mouse event caused by tapping the display.
      return this.on('touchend' + namespace, function () {
                   $(this).data(eventTimeProperty, new Date().getTime());
                 })
                 // If the first event handler remembered its time and the
                 // mouseenter event comes too soon, it was triggered by
                 // tapping and should be ignored.
                 .on('mouseenter' + namespace, function (event) {
                   var $this = $(this),
                       once = $this.data(eventTimeProperty),
                       now;
                   if (once) {
                     now = new Date().getTime();
                     // The time interval between the touchend event, which
                     // can identify, that the mouseenter event was emulated,
                     // and the mouseenter event itself can vary.
                     if (now - once < 50) {
                       return $(this).removeData(eventTimeProperty);
                     }
                   }
                   // Enable handling of the complementary mouseleave event.
                   $(this).data(eventTimeProperty, true);
                   handlerIn.call(this, event);
                 })
                 // The mouseleave event should call the hover event handler
                 // only if it was triggered by the mouseenter event earlier.
                 .on('mouseleave' + namespace, function (event) {
                   var $this = $(this);
                   if ($this.data(eventTimeProperty)) {
                     $this.removeData(eventTimeProperty);
                     handlerOut.call(this, event);
                   }
                 });
    };

  // If the browser has no support for touch events, we can assume, that
  // the only device, which can trigger the mouseenter eveny, is the mouse.
  } else {
    // Default to jQuery.hover behaviour on devices without touch capability.
    $.fn.mousehover = function (handlerIn, handlerOut, options) {
      var parameters = normalizeParameters(handlerIn, handlerOut, options),
          namespace = parameters.namespace;
      handlerIn = parameters.handlerIn;
      // Missing "handlerIn" parameter means, that existing event handlers
      // should be unregistered.
      if (!handlerIn) {
        return this.off('mouseenter' + namespace +
                        ' mouseleave' + namespace);
      }
      handlerOut = parameters.handlerOut;
      return this.on('mouseenter' + namespace, handlerIn)
                 .on('mouseleave' + namespace, handlerOut);
    };
  }

  // Restores the earlier mousehover plugin, which had been registered in
  // jQuery before this one. This plugin is returned for explicit usage.
  $.fn.mousehover.noConflict = function () {
    $.fn.mousehover = oldMousehover;
    return this;
  };

  return $;
}));
<|endoftext|>


<commit_before>"use strict";

// Important Definitions
// Syntax Parser: A program that reads your code and determins what it does and if its grammer is valid.
// Lexical Enviroment: Where something sits physically in the code you write.
// Execution Context: A wrapper to help manage the code that is currently running.
// Creation Phase: when the browser sets up memory space for variable and function which is called "Hoisting".
// Execution Phase: when it executed the code line by line how it was written.
// Name/Value Pairs: A name which maps to a unique value.
// Object: a collection of name/value pairs.
// Single Threaded Behavior: One command at a time.
// Synchronous Execution: One line at a time.
// Function Invocation: Running a function is invocing a function.
// variable Enviorment: Where the variables live.
// Scope: Where a variable is available in your code.
// Asynchronous: More than one at a time.
// Dynamic Typing: You dont tell the engine what type of data a variable holds, if figures it out while your code is running.
// Primitive Type: A type of Data that represents a single value.
// Operator Precedence: which operator function gets called first.
// Operator Associativity: what order operator functions get called in: left-to-right or right-to-left.
// Coercion: Converting a value from one type to another.
// Namespace: A container/holder for variables and functions.
// First Class Functions: Everything you can do with other types you can do with functions.
// Expression: A unit of code that results in a value.
// By value: Copy of a value and pasing it to it.
// By Reference: values set to an Objects will point to the same address in memory.
// Mutate: to change something.
// Immutable: means it can't be changed.
// Argumanets: The parameters you pass to a function.
// Inheritance: One object gets access to the properties and methods of another object.
// Reflection: An object can look at iself, listing and changing its properties and methods.
// Function constructor: A normal function used to construct object, which creates a new this variable tht points to the new object.

// global variable
var v = 'Global variable';
console.log(window.v);

// Associotivity Examnple
var a1 = 2, a2 = 3, a3 = 4;

a1 = a2 = a3;
console.log(a1);
console.log(a2);
console.log(a3); // all are the same value, and since = operator's associotivity is right to left the result is then explained.

// Coercion Example
var c1 = 1 + '00';
console.log(c1);

console.log(3 < 2 < 1); // the < associotivity is left to right and gets performed one operator at a time.

// Hoisting tricky example
 var salary = "$1000";
 (function () {
     console.log("Original salary was " + salary);
     var salary = "$5000";
     console.log("My New Salary " + salary);
 })();

// The 'this' variable example
var c = {
    name: 'Amir',
    log: function() {
        this.name = 'changed name';
        console.log(this);

        var changeName = function(newName) {
            this.name = 'changed name again';
        }.call(this); // call invoces the function and keeps the current context by passing the this variable in to the function.
    }
}

c.log();

// function clousure example
function greets(hi) {
    return function(name) {
        console.log(hi + ' ' + name);
    }
}

greets('Hello')('Amir');
var sayHi = greets('Hola');
sayHi('Jose');

// without a clousure
function buildFunctions() {
    var arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push( function() {
                return console.log(i);
            }
        );
    }
    console.log(arr);
    return arr;
}

var fs = buildFunctions();
fs[0]();
fs[1]();
fs[2]();

// with a clousure now and then the code works now as expected.
function buildFunctions1() {
    var arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push(
            (function(j) {
                return function() {
                    console.log(j);
                }
            }(i));
        );
    }
    return arr;
}

var fs = buildFunctions1();
fs[0]();
fs[1]();
fs[2]();

// function factory example
function makeGreeting(lang) {
    return function (firstname, lastname) {
        if (lang === 'en') {
            console.log('Hello ' + firstname + ' ' + lastname );
        }

        if (lang === 'es') {
            console.log('Hola ' + firstname + ' ' + lastname );
        }
    }
}

var greetEnglish = makeGreeting('en');
var greetSpanish = makeGreeting('es');
greetEnglish('Amir', 'Arafat');
greetSpanish('Amir', 'Arafat');

// closures and callbacks
function sayHiLater() {
    var greeting = 'Hi!';

    setTimeout(function() {
        console.log(greeting);
    }, 3000);
}

sayHiLater();

function callBackExample(callback) {
    var l = 0;
    var t = "Some String";

    callback(l, t);
}

callBackExample(function(l, t) {
   console.log('all done! Here is l: ' + l + ' and t: ' + t);
});

//Apply, Call, Bind examples
var person = {
    firstname: 'Amir',
    lastname: 'Arafat',

    getFullName: function() {
        var fullname = this.firstname + ' ' + this.lastname;

        return fullname;
    }
}

var logName = function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('-------------------------------------------');
};
var logPersonName = logName.bind(person);
logPersonName('en', 'es');
logName.call(person, 'en', 'es');
logName.apply(person, ['en', 'es']);

(function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('********************************');
}).apply(person, ['Ar', 'es']);

// function borrowing
var person2 = {
    firstname: 'John',
    lastname: 'Doe'
}

console.log(person.getFullName.apply(person2));

// function currying
function multiply(a, b) {
    return a * b;
}

var multiplyByTwo = multiply.bind(this, 2);
console.log(multiplyByTwo(10));

// Functional Programming
function mapForEach(arr, fn) {
    var newArr = [];
    for (var i = 0; i < arr.length; i++) {
        newArr.push(fn(arr[i]))
    };
    return newArr;
}

var arr1 = [1,2,3];
console.log(arr1);

var arr2 = mapForEach(arr1, function(item) {
   return item * 2;
});

console.log(arr2);

var arr3 = mapForEach(arr1, function(item) {
   return item > 2;
});
console.log(arr3);

var checkPastLimit = function(limiter, item) {
    return item > limiter;
}

var arr4 = mapForEach(arr1, checkPastLimit.bind(this, 1));
console.log(arr4);

var checkPastLimitSimple = function(limiter) {
    return function(limiter, item) {
        return item > limiter;
    }.bind(this, limiter);
}

var arr5 = mapForEach(arr1, checkPastLimitSimple(3));
console.log(arr5);

//Underscore example of functional programming
var arr6 = _.map(arr1, function(item){ return item * 3 });
console.log(arr6);

var arr7 = _.filter([1,2,3,4,5,6,7,8,9,10,11,12,13,14], function(item){ return item % 2 === 0 })
console.log(arr7);

// Prototypal Inheritance
var contact = {
    firstname: 'default',
    lastname: 'default',
    getFullName: function() {
        return this.firstname + ' ' + this.lastname;
    }
}

var john = {
    firstname: 'John',
    lastname: 'Doe'
}

john.__proto__ = contact; // this is bad practice but shows the prototype object and how we can add to it.
console.log(john.getFullName());

for (var prop in john) {
    if (john.hasOwnProperty(prop)){ // hasOwnProperty will only return the object props not the prototype ones as well.
        console.log(prop + ': ' + john[prop]);
    }
}

var jane = {
    address: '111 main st.',
    getFormalFullName: function() {
        return this.lastname + ', ' + this.firstname;
    }
}

var jim = {
    getFirstName: function() {
        return firstname;
    }
}

// reflection example from undersore using extend
_.extend(john, jane, jim);
console.log(john);

// Building Objects and Function constructors and 'new'.
// Use Capital name when using function constructors to know that you need to use the new key word.
function Animals(name1, name2) {
    this.dog = name1;
    this.cat = name2;
}

Animals.prototype.getAllPets = function() {
    return this.dog + ', ' + this.cat;
}

var pets = new Animals('sam', 'buttons'); // changes the execution context to a new object and then this changes to the object not the window.
var pets2 = new Animals('bingo', 'spider');
console.log(pets);
console.log(pets2);

// Using prototypes instead of including functions directly in the function constructor saves lots of space because it creates the function or method once
// instead of having it coppied everywhere the object gets created.

//Built in function constructors in JS
var fc1 = new Number(5);
var fc2 = new String("test");
var fc3 = new Date('1/1/1992');
console.log(fc1, fc2, fc3);

// adding additional feature to the string Function Constructor but bad for comparisons and math.
String.prototype.isLengthGreaterThan = String.prototype.isLengthGreaterThan || function(limit) {
    return this.length > limit;
}

String.prototype.repeatify = String.prototype.repeatify || function(times) {
    var str = "";
    for (var i = 0; i < times; i++) {
        str += this;
    }

    return str;
}

console.log("John Doe".isLengthGreaterThan(30));
console.log("Hello".repeatify(3));

//Arrays and for in don't use together instead use for loop.
Array.prototype.myCustomFeature = 'cool!'
var arr = ['John', 'Jane', 'Jim'];

for (var prop in arr) {
    console.log(prop + ': ' + arr[prop]);
}

// Pure prototypal inheritance and Object.create in modern browsers ie9+, ff4.0+, Chrome & Safari 5+
//Object.create Pollyfill
if (typeof Object.create != 'function') {
  Object.create = (function() {
    var Temp = function() {};
    return function (prototype) {
      if (arguments.length > 1) {
        throw Error('Second argument not supported');
      }
      if(prototype !== Object(prototype) && prototype !== null) {
        throw TypeError('Argument must be an object or null');
     }
     if (prototype === null) {
        throw Error('null [[Prototype]] not supported');
      }
      Temp.prototype = prototype;
      var result = new Temp();
      Temp.prototype = null;
      return result;
    };
  })();
}

var lunchMeal = {
    sandwich: 'Philly Cheese Steak',
    drink: 'Coke',
    createMeal: function() {
        return 'I am eating a ' + this.sandwich + ' with a ' + this.drink;
    }
};

var meal = Object.create(lunchMeal);
meal.sandwich = "Turkey Sandwich";
meal.drink = "Sprite";
console.log(meal);

// ES6 Class and how it creates Objects
class Weekend {
    constructor(day1, day2) {
        this.day1 = day1;
        this.day2 = day2;
    }

    getWeekend() {
        return 'The weekend is ' + this.day1 + ' and ' + this.day2;
    }
}

var party = new Weekend('Saturday', 'Sunday');
console.log(party.getWeekend());
// Use Extends to set the prototype to another object

// typeof and instanceof and the different ways they work
var a = 3;
console.log(typeof a);

var b = "Hello";
console.log(typeof b);

var c = {};
console.log(typeof c);

var d = [];
console.log(typeof d); // weird!
console.log(Object.prototype.toString.call(d)); // better!

function Person(name) {
    this.name = name;
}

var e = new Person('Jane');
console.log(typeof e);
console.log(e instanceof Person);

console.log(typeof undefined); // makes sense
console.log(typeof null); // a bug since, forever...

var z = function() { };
console.log(typeof z);

<commit_msg>a few more logging for clearer examples<commit_after>"use strict";

// Important Definitions
// Syntax Parser: A program that reads your code and determins what it does and if its grammer is valid.
// Lexical Enviroment: Where something sits physically in the code you write.
// Execution Context: A wrapper to help manage the code that is currently running.
// Creation Phase: when the browser sets up memory space for variable and function which is called "Hoisting".
// Execution Phase: when it executed the code line by line how it was written.
// Name/Value Pairs: A name which maps to a unique value.
// Object: a collection of name/value pairs.
// Single Threaded Behavior: One command at a time.
// Synchronous Execution: One line at a time.
// Function Invocation: Running a function is invocing a function.
// variable Enviorment: Where the variables live.
// Scope: Where a variable is available in your code.
// Asynchronous: More than one at a time.
// Dynamic Typing: You dont tell the engine what type of data a variable holds, if figures it out while your code is running.
// Primitive Type: A type of Data that represents a single value.
// Operator Precedence: which operator function gets called first.
// Operator Associativity: what order operator functions get called in: left-to-right or right-to-left.
// Coercion: Converting a value from one type to another.
// Namespace: A container/holder for variables and functions.
// First Class Functions: Everything you can do with other types you can do with functions.
// Expression: A unit of code that results in a value.
// By value: Copy of a value and pasing it to it.
// By Reference: values set to an Objects will point to the same address in memory.
// Mutate: to change something.
// Immutable: means it can't be changed.
// Argumanets: The parameters you pass to a function.
// Inheritance: One object gets access to the properties and methods of another object.
// Reflection: An object can look at iself, listing and changing its properties and methods.
// Function constructor: A normal function used to construct object, which creates a new this variable tht points to the new object.

// global variable
var v = 'Global variable';
console.log(window.v);

// Associotivity Examnple
var a1 = 2, a2 = 3, a3 = 4;

a1 = a2 = a3;
console.log(a1);
console.log(a2);
console.log(a3); // all are the same value, and since = operator's associotivity is right to left the result is then explained.

// Coercion Example
var c1 = 1 + '00';
console.log(c1);

console.log(3 < 2 < 1); // the < associotivity is left to right and gets performed one operator at a time.

// Hoisting tricky example
 var salary = "$1000";
 (function () {
     console.log("Original salary was " + salary);
     var salary = "$5000";
     console.log("My New Salary " + salary);
 })();

// The 'this' variable example
var c = {
    name: 'Amir',
    log: function() {
        this.name = 'changed name';
        console.log(this);

        var changeName = function(newName) {
            this.name = 'changed name again';
        }.call(this); // call invoces the function and keeps the current context by passing the this variable in to the function.
    }
}

c.log();

// function clousure example
function greets(hi) {
    return function(name) {
        console.log(hi + ' ' + name);
    }
}

greets('Hello')('Amir');
var sayHi = greets('Hola');
sayHi('Jose');

// without a clousure
function buildFunctions() {
    var arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push( function() {
                return console.log(i);
            }
        );
    }
    console.log(arr);
    return arr;
}

var fs = buildFunctions();
fs[0]();
fs[1]();
fs[2]();

// with a clousure now and then the code works now as expected.
function buildFunctions1() {
    var arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push(
            (function(j) {
                return function() {
                    console.log(j);
                }
            }(i))
        );
    }
    return arr;
}

var fs = buildFunctions1();
fs[0]();
fs[1]();
fs[2]();

// function factory example
function makeGreeting(lang) {
    return function (firstname, lastname) {
        if (lang === 'en') {
            console.log('Hello ' + firstname + ' ' + lastname );
        }

        if (lang === 'es') {
            console.log('Hola ' + firstname + ' ' + lastname );
        }
    }
}

var greetEnglish = makeGreeting('en');
var greetSpanish = makeGreeting('es');
greetEnglish('Amir', 'Arafat');
greetSpanish('Amir', 'Arafat');

// closures and callbacks
function sayHiLater() {
    var greeting = 'Hi!';

    setTimeout(function() {
        console.log(greeting);
    }, 3000);
}

sayHiLater();

function callBackExample(callback) {
    var l = 0;
    var t = "Some String";

    callback(l, t);
}

callBackExample(function(l, t) {
   console.log('all done! Here is l: ' + l + ' and t: ' + t);
});

//Apply, Call, Bind examples
var person = {
    firstname: 'Amir',
    lastname: 'Arafat',

    getFullName: function() {
        var fullname = this.firstname + ' ' + this.lastname;

        return fullname;
    }
}

var logName = function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('-------------------------------------------');
};
var logPersonName = logName.bind(person);
logPersonName('en', 'es');
logName.call(person, 'en', 'es');
logName.apply(person, ['en', 'es']);

(function(lang1, lang2) {
    console.log('Logged: ' + this.getFullName());
    console.log('Arguments: ' + lang1 + ' ' + lang2);
    console.log('-------------------------------------------');
}).apply(person, ['Ar', 'es']);

// function borrowing
var person2 = {
    firstname: 'John',
    lastname: 'Doe'
}

console.log(person.getFullName.apply(person2));

// function currying
function multiply(a, b) {
    return a * b;
}

var multiplyByTwo = multiply.bind(this, 2);
console.log(multiplyByTwo(10));

// Functional Programming
function mapForEach(arr, fn) {
    var newArr = [];
    for (var i = 0; i < arr.length; i++) {
        newArr.push(fn(arr[i]))
    };
    return newArr;
}

var arr1 = [1,2,3];
console.log(arr1);

var arr2 = mapForEach(arr1, function(item) {
   return item * 2;
});

console.log(arr2);

var arr3 = mapForEach(arr1, function(item) {
   return item > 2;
});
console.log(arr3);

var checkPastLimit = function(limiter, item) {
    console.log(limiter, item);
    return item > limiter;
}

var arr4 = mapForEach(arr1, checkPastLimit.bind(this, 1));
console.log(arr4);

var checkPastLimitSimple = function(limiter) {
    return function(limiter, item) {
        return item > limiter;
    }.bind(this, limiter);
}

var arr5 = mapForEach(arr1, checkPastLimitSimple(2));
console.log(arr5);

//Underscore example of functional programming
var arr6 = _.map(arr1, function(item){ return item * 3 });
console.log(arr6);

var arr7 = _.filter([1,2,3,4,5,6,7,8,9,10,11,12,13,14], function(item){ return item % 2 === 0 })
console.log(arr7);

// Prototypal Inheritance
var contact = {
    firstname: 'default',
    lastname: 'default',
    getFullName: function() {
        return this.firstname + ' ' + this.lastname;
    }
}

var john = {
    firstname: 'John',
    lastname: 'Doe'
}

john.__proto__ = contact; // this is bad practice but shows the prototype object and how we can add to it.
console.log(john.getFullName());

for (var prop in john) {
    if (john.hasOwnProperty(prop)){ // hasOwnProperty will only return the object props not the prototype ones as well.
        console.log(prop + ': ' + john[prop]);
    }
}

var jane = {
    address: '111 main st.',
    getFormalFullName: function() {
        return this.lastname + ', ' + this.firstname;
    }
}

var jim = {
    getFirstName: function() {
        return firstname;
    }
}

// reflection example from undersore using extend
_.extend(john, jane, jim);
console.log(john);

// Building Objects and Function constructors and 'new'.
// Use Capital name when using function constructors to know that you need to use the new key word.
function Animals(name1, name2) {
    this.dog = name1;
    this.cat = name2;
}

Animals.prototype.getAllPets = function() {
    return this.dog + ', ' + this.cat;
}

var pets = new Animals('sam', 'buttons'); // changes the execution context to a new object and then this changes to the object not the window.
var pets2 = new Animals('bingo', 'spider');
console.log(pets);
console.log(pets2);

// Using prototypes instead of including functions directly in the function constructor saves lots of space because it creates the function or method once
// instead of having it coppied everywhere the object gets created.

//Built in function constructors in JS
var fc1 = new Number(5);
var fc2 = new String("test");
var fc3 = new Date('1/1/1992');
console.log(fc1, fc2, fc3);

// adding additional feature to the string Function Constructor but bad for comparisons and math.
String.prototype.isLengthGreaterThan = String.prototype.isLengthGreaterThan || function(limit) {
    return this.length > limit;
}

String.prototype.repeatify = String.prototype.repeatify || function(times) {
    var str = "";
    for (var i = 0; i < times; i++) {
        str += this;
    }

    return str;
}

console.log("John Doe".isLengthGreaterThan(30));
console.log("Hello".repeatify(3));

//Arrays and for in don't use together instead use for loop.
Array.prototype.myCustomFeature = 'cool!'
var arr = ['John', 'Jane', 'Jim'];

for (var prop in arr) {
    console.log(prop + ': ' + arr[prop]);
}

// Pure prototypal inheritance and Object.create in modern browsers ie9+, ff4.0+, Chrome & Safari 5+
//Object.create Pollyfill
if (typeof Object.create != 'function') {
  Object.create = (function() {
    var Temp = function() {};
    return function (prototype) {
      if (arguments.length > 1) {
        throw Error('Second argument not supported');
      }
      if(prototype !== Object(prototype) && prototype !== null) {
        throw TypeError('Argument must be an object or null');
     }
     if (prototype === null) {
        throw Error('null [[Prototype]] not supported');
      }
      Temp.prototype = prototype;
      var result = new Temp();
      Temp.prototype = null;
      return result;
    };
  })();
}

var lunchMeal = {
    sandwich: 'Philly Cheese Steak',
    drink: 'Coke',
    createMeal: function() {
        return 'I am eating a ' + this.sandwich + ' with a ' + this.drink;
    }
};

var meal = Object.create(lunchMeal);
meal.sandwich = "Turkey Sandwich";
meal.drink = "Sprite";
console.log(meal);

// ES6 Class and how it creates Objects
class Weekend {
    constructor(day1, day2) {
        this.day1 = day1;
        this.day2 = day2;
    }

    getWeekend() {
        return 'The weekend is ' + this.day1 + ' and ' + this.day2;
    }
}

var party = new Weekend('Saturday', 'Sunday');
console.log(party.getWeekend());
// Use Extends to set the prototype to another object

// typeof and instanceof and the different ways they work
var a = 3;
console.log(typeof a);

var b = "Hello";
console.log(typeof b);

var c = {};
console.log(typeof c);

var d = [];
console.log(typeof d); // weird!
console.log(Object.prototype.toString.call(d)); // better!

function Person(name) {
    this.name = name;
}

var e = new Person('Jane');
console.log(typeof e);
console.log(e instanceof Person);

console.log(typeof undefined); // makes sense
console.log(typeof null); // a bug since, forever...

var z = function() { };
console.log(typeof z);

<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes');

var app = module.exports = express.createServer();

var passport = require('passport'),
    users =  require('./server/controllers/users.js'),
    expressValidator = require('express-validator');

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.set('view options', {
    layout: false
  });
  app.use(express.static(__dirname + '/public'));

  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(expressValidator());
  app.use(express.methodOverride());
  app.use(express.session({ secret: 'keyboard cat' }));
  app.use(passport.initialize());
  app.use(passport.session()); // persistent login sessions
  app.use(app.router);

  require('./server/config/passport')(passport);

});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// permissions for third party rest methods

app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,DELETE');
    res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
    if ('OPTIONS' == req.method){
        return res.send(200);
    }
    next();
});

// Routes

app.get('/', routes.index);

// auth

  app
    .post( '/login' , passport.authenticate('local', {
      failureFlash: true
    }), users.doLogin);

 app.get("/loggedin",users.loggedin);
 app.post("/sociallogin",users.socialLogin);
 app.post("/signoutapp",users.signoutapp);
 app.get('/userById' , users.requiresToken,users.me);

 app.post('/register' , users.create);

app.listen(process.env.PORT || 3000, function(){
  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});
<commit_msg>space added<commit_after>
/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes');

var app = module.exports = express.createServer();

var passport = require('passport'),
    users =  require('./server/controllers/users.js'),
    expressValidator = require('express-validator');

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.set('view options', {
    layout: false
  });
  app.use(express.static(__dirname + '/public'));

  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(expressValidator());
  app.use(express.methodOverride());
  app.use(express.session({ secret: 'keyboard cat' }));
  app.use(passport.initialize());
  app.use(passport.session()); // persistent login sessions
  app.use(app.router);

  require('./server/config/passport')(passport);

});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// permissions for third party rest methods

app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,DELETE');
    res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
    if ('OPTIONS' == req.method){
        return res.send(200);
    }
    next();
});

// Routes

app.get('/', routes.index);

// auth

  app
    .post( '/login' , passport.authenticate('local', {
      failureFlash: true
    }), users.doLogin);

 app.get("/loggedin",users.loggedin);
 app.post("/sociallogin",users.socialLogin);
 app.post("/signoutapp",users.signoutapp);
 app.get('/userById' , users.requiresToken,users.me);

 app.post('/register' , users.create);

app.listen(process.env.PORT || 3000, function(){
  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});
<|endoftext|>


<commit_before>/* eslint-disable no-magic-numbers, max-len, camelcase */
define([
    'dojo/Deferred',
    'dojo/has',
    'dojo/request/xhr',
    'dojo/_base/array',
    'dojo/_base/Color',
    'dojo/_base/lang',

    'esri/config',
    'esri/SpatialReference',
    'esri/symbols/CartographicLineSymbol',
    'esri/symbols/SimpleFillSymbol',
    'esri/symbols/SimpleLineSymbol',
    'esri/symbols/SimpleMarkerSymbol',
    'esri/tasks/GeometryService'
], function (
    Deferred,
    has,
    xhr,
    array,
    Color,
    lang,

    esriConfig,
    SpatialReference,
    CartographicLineSymbol,
    SimpleFillSymbol,
    SimpleLineSymbol,
    SimpleMarkerSymbol,
    GeometryService
) {
    var agsDomain;
    var AGRC = {};
    if (has('agrc-build') === 'prod') {
        // *.utah.gov
        AGRC.apiKey = 'AGRC-D3CDE591211690';
        agsDomain = 'enviro.deq.utah.gov';
        // mapserv.utah.gov or enviro.deq.utah.gov
        AGRC.quadWord = 'result-table-secure-antenna';
    } else if (has('agrc-build') === 'stage') {
        // test.mapserv.utah.gov
        AGRC.apiKey = 'AGRC-AC122FA9671436';
        agsDomain = 'test.mapserv.utah.gov';
        esriConfig.defaults.io.corsEnabledServers.push(agsDomain);
        AGRC.quadWord = 'opera-event-little-pinball';
    } else {
        // localhost
        xhr(require.baseUrl + 'secrets.json', {
            handleAs: 'json',
            sync: true
        }).then(function (secrets) {
            AGRC.quadWord = secrets.quadWord;
            AGRC.apiKey = secrets.apiKey;
        }, function () {
            throw 'Error getting secrets!';
        });
        agsDomain = 'localhost';
    }

    // force api to use CORS on mapserv thus removing the test request on app load
    // e.g. http://mapserv.utah.gov/ArcGIS/rest/info?f=json
    esriConfig.defaults.io.corsEnabledServers.push('mapserv.utah.gov');
    esriConfig.defaults.io.corsEnabledServers.push('api.mapserv.utah.gov');
    esriConfig.defaults.io.corsEnabledServers.push('gis.trustlands.utah.gov');

    var zoomColor = new Color([255, 255, 0]);
    var zoomFillColor = new Color(zoomColor.toRgb().concat([0.15]));
    var selectionColor = new Color([240, 18, 190]);
    var selectionFillColor = new Color(selectionColor.toRgb().concat([0.35]));

    var baseUrl = (agsDomain === '') ? '' : window.location.protocol + '//' + agsDomain;
    esriConfig.defaults.geometryService = new GeometryService(baseUrl + '/arcgis/rest/services/Geometry/GeometryServer');
    var deqServiceFolder = baseUrl + '/arcgis/rest/services/DEQEnviro';
    var secureUrl = deqServiceFolder + '/Secure/MapServer';
    window.AGRC = lang.mixin(AGRC, {
        // app: app.App
        //      global reference to App
        app: null,

        // appName: String
        //      name of the app used in permissionsproxy
        appName: 'deq',

        // user: Object
        //      set in App.js
        user: null,

        // version.: String
        //      The version number.
        version: '1.5.1',

        // popupDelay: Number
        //      The delay (in milliseconds) before a popup is shown on hover.
        popupDelay: 250,

        gridIdentifyHeight: 237,

        labelsMinScale: 250000,

        minBuffer: 0.1, // in miles

        defaultBaseMap: 'Lite',

        printMapTitle: 'Printed from the Utah DEQ Interactive Map',

        downloadDataPath: 'C:\\MapData\\deqquerylayers.gdb',

        // topics: Object
        //      The topic strings used in this app
        topics: {
            appMapReferenceLayerToggle: {
                addLayer: 'app/map/ReferenceLayerToggle.addLayer',
                toggleLayer: 'app/map/ReferenceLayerToggle.toggleLayer'
            },
            appQueryLayer: {
                addLayer: 'app/QueryLayer.addLayer',
                removeLayer: 'app/QueryLayer.removeLayer'
            },
            appMapMapController: {
                mapZoom: 'app/map/MapController.mapZoom',
                zoomToSearchGraphic: 'app/map/MapController.zoomToSearchGraphic',
                graphic: 'app/map/MapController.graphic',
                clearGraphics: 'app/map/MapController.clearGraphics',
                zoom: 'app/map/MapController.zoom',
                showHighlightedFeature: 'app/map/MapController.showHighlightedFeature'
            },
            appSearch: {
                featuresFound: 'app/search/Search.featuresFound',
                searchStarted: 'app/search/Search.searchStarted',
                searchError: 'app/search/Search.searchError',
                clear: 'app/search/Search.clear',
                identify: 'app/search/identify',
                onStreamSelect: 'app/search/onStreamSelect'
            },
            appResultLayer: {
                addLayer: 'app/search/ResultLayer.addLayer',
                removeLayer: 'app/search/ResultLayer.removeLayer',
                highlightFeature: 'app/search/ResultLayer.highlightFeature',
                clearSelection: 'app/search/ResultLayer.clearSelection',
                identifyFeature: 'app/search/ResultLayer.identifyFeature'
            },
            appSearchIdentifyPane: {
                backToResults: 'app/search/IdentifyPane.backToResults'
            },
            app: {
                hideGrid: 'app/App.hideGrid',
                showGrid: 'app/App.showGrid',

                // matches topic name in ijit/widgets/authentication/LoginRegister
                onSignInSuccess: 'LoginRegister/sign-in-success'
            },
            appSearchResultsGrid: {
                downloadFeaturesDefined: 'app/search/ResultsGrid.downloadFeaturesDefined'
            },
            appDownloadDownload: {
                clearSelection: 'app/download/Download.clearSelection'
            }
        },

        // urls: Object
        //      Urls for the project
        urls: {
            UtahPLSS: 'https://tiles.arcgis.com/tiles/99lidPhWCzftIe9K/arcgis/rest/services/UtahPLSS/VectorTileServer',
            DEQEnviro: deqServiceFolder + '/MapService/MapServer',
            json: 'webdata/DEQEnviro.json',
            secure: secureUrl,
            search: location.pathname.replace(/\/(src|dist)/, '') + 'api/search',
            download: deqServiceFolder + '/Toolbox/GPServer/Download',
            printProxy: 'https://us-central1-utahkoopserver.cloudfunctions.net/printproxy/14/arcgis/rest/services/GPServer/export',
            landOwnership: 'https://gis.trustlands.utah.gov/server/' +
                           'rest/services/Ownership/UT_SITLA_Ownership_LandOwnership_WM/MapServer'
        },

        // layerIndices: Object
        //      Indices of layers within map services.
        layerIndices: {
            streams: 0,
            environmentalCovenants: 1,
            huc: 2,
            indianTribal: 3,
            risk: {
                facilities: 4,
                waterPoints: 5,
                streams: 6,
                lakes: 7
            },
            searchStreams: 8,
            landOwnership: 0 // in the SITLA service
        },

        // fieldNames: {}
        fieldNames: {
            cities: {
                NAME: 'NAME'
            },
            counties: {
                NAME: 'NAME'
            },
            utah: {
                STATE: 'STATE'
            },
            queryLayers: {
                ADDRESS: 'ADDRESS',
                CITY: 'CITY',
                ID: 'ID',
                NAME: 'NAME',
                TYPE: 'TYPE',
                UNIQUE_ID: 'UNIQUE_ID',
                ENVIROAPPLABEL: 'ENVIROAPPLABEL',
                ENVIROAPPSYMBOL: 'ENVIROAPPSYMBOL',
                OBJECTID: 'OBJECTID'
            },
            searchStreams: {
                GNIS_Name: 'GNIS_Name',
                COUNTY: 'COUNTY'
            },
            nhd: {
                FCode: 'FCode',
                GNIS_Name: 'GNIS_Name'
            },
            zip: {
                ZIP5: 'ZIP5'
            }
        },

        // featureClassNames: {}
        featureClassNames: {
            counties: 'SGID10.BOUNDARIES.Counties',
            utah: 'SGID10.BOUNDARIES.Utah',
            city: 'SGID10.BOUNDARIES.Municipalities_Carto', // _Carto version to make sure that Draper is not split on county line
            zip: 'SGID10.BOUNDARIES.ZipCodes'
        },

        // TRSMinScaleLevel: Number
        //      The minimum scale level that the TRS Layer will draw.
        TRSMinScaleLevel: 10,

        // RiskLayersMinScaleLevel: Number
        //      The minimum scale level that the three risk layers draw.
        RiskLayersMinScaleLevel: 14,

        // NHDMinScaleLevel: Number
        //      The minimum scale level that the nhd layer will draw.
        NHDMinScaleLevel: 13,

        // appJson: Object
        //      Cache for data returned by getAppJson
        appJson: null,

        // queryLayerNames: Object
        //      Lookup for query layer name by layer index
        //      Populated in getAppJson below
        queryLayerNames: null,

        // spatialReference SpatialReference
        //      The spatial reference of the map
        spatialReference: new SpatialReference(3857),

        // symbols: Object
        //      Graphic symbols used in this app
        symbols: {
            zoom: {
                polygon: new SimpleFillSymbol(
                    SimpleFillSymbol.STYLE_SOLID,
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID,
                        zoomColor,
                        2
                    ),
                    zoomFillColor),
                point: new SimpleMarkerSymbol(
                    SimpleMarkerSymbol.STYLE_CIRCLE,
                    13,
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID,
                        zoomColor,
                        2),
                    zoomFillColor),
                polyline: new SimpleLineSymbol(
                    SimpleLineSymbol.STYLE_SOLID,
                    zoomColor,
                    4
                )
            },
            resultSymbolOpacity: 0.65,
            colors: [
                [31, 120, 180],
                [51, 160, 44],
                [227, 26, 28],
                [255, 127, 0],
                [106, 61, 154],
                [253, 191, 111],
                [251, 154, 153],
                [178, 223, 138],
                [166, 206, 227],
                [202, 178, 214],
                [255, 255, 153],
                [177, 89, 40]
            ],
            selection: {
                polygon: new SimpleFillSymbol(
                    SimpleFillSymbol.STYLE_SOLID,
                    new CartographicLineSymbol(
                        CartographicLineSymbol.STYLE_SOLID,
                        selectionColor,
                        3,
                        CartographicLineSymbol.CAP_ROUND,
                        CartographicLineSymbol.JOIN_ROUND),
                    selectionFillColor
                ),
                point: new SimpleMarkerSymbol(
                    SimpleMarkerSymbol.STYLE_CIRCLE,
                    12,
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID,
                        selectionColor,
                        2),
                    selectionFillColor
                )
            }
        },

        // messages: Object
        //      Messages and text used throughout the app
        messages: {
            noFeaturesFound: 'No results'
        },

        parameterNames: {
            output: 'output' // download service
        },

        getAppJson: function () {
            // summary:
            //      requests the DEQEnviro.json data and returns it, caches the results for future requests
            console.log('app.config::getAppJson', arguments);

            var def = new Deferred();

            if (this.appJson) {
                def.resolve(this.appJson);
            } else if (this.appJsonRequest) {
                // prevent simultanious requests
                this.appJsonRequest.then(() => {
                    def.resolve(this.appJson);
                });
            } else {
                // get a fresh copy of the json file on each load
                this.appJsonRequest = xhr(this.urls.json, {
                    handleAs: 'json'
                }).then((json) => {
                    this.queryLayerNames = {};
                    json.queryLayers.forEach((ql) => {
                        this.queryLayerNames[ql.index] = ql.name;
                    });
                    this.appJsonRequest = null;
                    def.resolve(this.appJson = json);
                });
            }

            return def.promise;
        },
        getQueryLayerByIndex: function (index) {
            // summary:
            //      description
            // index: String
            // console.log('app/config:getQueryLayerByIndex', arguments);

            return this.getDatasetByIndex(this.appJson.queryLayers, index);
        },
        getRelatedTableByIndex: function (index) {
            // summary:
            //      description
            // index: String
            // console.log('app/config:getRelatedTableByIndex', arguments);

            return this.getDatasetByIndex(this.appJson.relatedTables, index);
        },
        getDatasetByIndex: function (datasets, index) {
            // this could easily be done with one loop but I wanted to try
            // out memoization :)
            this._cached = this._cached || {};

            if (this._cached[index]) {
                return this._cached[index];
            }

            var returnLayer;
            array.some(datasets, function (ql) {
                if (ql.index === index) {
                    returnLayer = ql;

                    return true;
                }

                return false;
            });

            this._cached[index] = returnLayer;

            return returnLayer;
        }
    });

    return window.AGRC;
});
<commit_msg>build: support multiple map data locations for different environments<commit_after>/* eslint-disable no-magic-numbers, max-len, camelcase */
define([
    'dojo/Deferred',
    'dojo/has',
    'dojo/request/xhr',
    'dojo/_base/array',
    'dojo/_base/Color',
    'dojo/_base/lang',

    'esri/config',
    'esri/SpatialReference',
    'esri/symbols/CartographicLineSymbol',
    'esri/symbols/SimpleFillSymbol',
    'esri/symbols/SimpleLineSymbol',
    'esri/symbols/SimpleMarkerSymbol',
    'esri/tasks/GeometryService'
], function (
    Deferred,
    has,
    xhr,
    array,
    Color,
    lang,

    esriConfig,
    SpatialReference,
    CartographicLineSymbol,
    SimpleFillSymbol,
    SimpleLineSymbol,
    SimpleMarkerSymbol,
    GeometryService
) {
    var agsDomain;
    var AGRC = {};
    let mapDataLocation;
    if (has('agrc-build') === 'prod') {
        // *.utah.gov
        AGRC.apiKey = 'AGRC-D3CDE591211690';
        agsDomain = 'enviro.deq.utah.gov';
        // mapserv.utah.gov or enviro.deq.utah.gov
        AGRC.quadWord = 'result-table-secure-antenna';
        mapDataLocation = 'C:\\MapData';
    } else if (has('agrc-build') === 'stage') {
        // test.mapserv.utah.gov
        AGRC.apiKey = 'AGRC-AC122FA9671436';
        agsDomain = 'test.mapserv.utah.gov';
        esriConfig.defaults.io.corsEnabledServers.push(agsDomain);
        AGRC.quadWord = 'opera-event-little-pinball';
        mapDataLocation = 'C:\\forklift-stage\\data\\production';
    } else {
        // localhost
        xhr(require.baseUrl + 'secrets.json', {
            handleAs: 'json',
            sync: true
        }).then(function (secrets) {
            AGRC.quadWord = secrets.quadWord;
            AGRC.apiKey = secrets.apiKey;
        }, function () {
            throw 'Error getting secrets!';
        });
        agsDomain = 'localhost';
        mapDataLocation = 'C:\\forklift\\data\\production';
    }

    // force api to use CORS on mapserv thus removing the test request on app load
    // e.g. http://mapserv.utah.gov/ArcGIS/rest/info?f=json
    esriConfig.defaults.io.corsEnabledServers.push('mapserv.utah.gov');
    esriConfig.defaults.io.corsEnabledServers.push('api.mapserv.utah.gov');
    esriConfig.defaults.io.corsEnabledServers.push('gis.trustlands.utah.gov');

    var zoomColor = new Color([255, 255, 0]);
    var zoomFillColor = new Color(zoomColor.toRgb().concat([0.15]));
    var selectionColor = new Color([240, 18, 190]);
    var selectionFillColor = new Color(selectionColor.toRgb().concat([0.35]));

    var baseUrl = (agsDomain === '') ? '' : window.location.protocol + '//' + agsDomain;
    esriConfig.defaults.geometryService = new GeometryService(baseUrl + '/arcgis/rest/services/Geometry/GeometryServer');
    var deqServiceFolder = baseUrl + '/arcgis/rest/services/DEQEnviro';
    var secureUrl = deqServiceFolder + '/Secure/MapServer';
    window.AGRC = lang.mixin(AGRC, {
        // app: app.App
        //      global reference to App
        app: null,

        // appName: String
        //      name of the app used in permissionsproxy
        appName: 'deq',

        // user: Object
        //      set in App.js
        user: null,

        // version.: String
        //      The version number.
        version: '1.5.1',

        // popupDelay: Number
        //      The delay (in milliseconds) before a popup is shown on hover.
        popupDelay: 250,

        gridIdentifyHeight: 237,

        labelsMinScale: 250000,

        minBuffer: 0.1, // in miles

        defaultBaseMap: 'Lite',

        printMapTitle: 'Printed from the Utah DEQ Interactive Map',

        downloadDataPath: `${mapDataLocation}\\deqquerylayers.gdb`,

        // topics: Object
        //      The topic strings used in this app
        topics: {
            appMapReferenceLayerToggle: {
                addLayer: 'app/map/ReferenceLayerToggle.addLayer',
                toggleLayer: 'app/map/ReferenceLayerToggle.toggleLayer'
            },
            appQueryLayer: {
                addLayer: 'app/QueryLayer.addLayer',
                removeLayer: 'app/QueryLayer.removeLayer'
            },
            appMapMapController: {
                mapZoom: 'app/map/MapController.mapZoom',
                zoomToSearchGraphic: 'app/map/MapController.zoomToSearchGraphic',
                graphic: 'app/map/MapController.graphic',
                clearGraphics: 'app/map/MapController.clearGraphics',
                zoom: 'app/map/MapController.zoom',
                showHighlightedFeature: 'app/map/MapController.showHighlightedFeature'
            },
            appSearch: {
                featuresFound: 'app/search/Search.featuresFound',
                searchStarted: 'app/search/Search.searchStarted',
                searchError: 'app/search/Search.searchError',
                clear: 'app/search/Search.clear',
                identify: 'app/search/identify',
                onStreamSelect: 'app/search/onStreamSelect'
            },
            appResultLayer: {
                addLayer: 'app/search/ResultLayer.addLayer',
                removeLayer: 'app/search/ResultLayer.removeLayer',
                highlightFeature: 'app/search/ResultLayer.highlightFeature',
                clearSelection: 'app/search/ResultLayer.clearSelection',
                identifyFeature: 'app/search/ResultLayer.identifyFeature'
            },
            appSearchIdentifyPane: {
                backToResults: 'app/search/IdentifyPane.backToResults'
            },
            app: {
                hideGrid: 'app/App.hideGrid',
                showGrid: 'app/App.showGrid',

                // matches topic name in ijit/widgets/authentication/LoginRegister
                onSignInSuccess: 'LoginRegister/sign-in-success'
            },
            appSearchResultsGrid: {
                downloadFeaturesDefined: 'app/search/ResultsGrid.downloadFeaturesDefined'
            },
            appDownloadDownload: {
                clearSelection: 'app/download/Download.clearSelection'
            }
        },

        // urls: Object
        //      Urls for the project
        urls: {
            UtahPLSS: 'https://tiles.arcgis.com/tiles/99lidPhWCzftIe9K/arcgis/rest/services/UtahPLSS/VectorTileServer',
            DEQEnviro: deqServiceFolder + '/MapService/MapServer',
            json: 'webdata/DEQEnviro.json',
            secure: secureUrl,
            search: location.pathname.replace(/\/(src|dist)/, '') + 'api/search',
            download: deqServiceFolder + '/Toolbox/GPServer/Download',
            printProxy: 'https://us-central1-utahkoopserver.cloudfunctions.net/printproxy/14/arcgis/rest/services/GPServer/export',
            landOwnership: 'https://gis.trustlands.utah.gov/server/' +
                           'rest/services/Ownership/UT_SITLA_Ownership_LandOwnership_WM/MapServer'
        },

        // layerIndices: Object
        //      Indices of layers within map services.
        layerIndices: {
            streams: 0,
            environmentalCovenants: 1,
            huc: 2,
            indianTribal: 3,
            risk: {
                facilities: 4,
                waterPoints: 5,
                streams: 6,
                lakes: 7
            },
            searchStreams: 8,
            landOwnership: 0 // in the SITLA service
        },

        // fieldNames: {}
        fieldNames: {
            cities: {
                NAME: 'NAME'
            },
            counties: {
                NAME: 'NAME'
            },
            utah: {
                STATE: 'STATE'
            },
            queryLayers: {
                ADDRESS: 'ADDRESS',
                CITY: 'CITY',
                ID: 'ID',
                NAME: 'NAME',
                TYPE: 'TYPE',
                UNIQUE_ID: 'UNIQUE_ID',
                ENVIROAPPLABEL: 'ENVIROAPPLABEL',
                ENVIROAPPSYMBOL: 'ENVIROAPPSYMBOL',
                OBJECTID: 'OBJECTID'
            },
            searchStreams: {
                GNIS_Name: 'GNIS_Name',
                COUNTY: 'COUNTY'
            },
            nhd: {
                FCode: 'FCode',
                GNIS_Name: 'GNIS_Name'
            },
            zip: {
                ZIP5: 'ZIP5'
            }
        },

        // featureClassNames: {}
        featureClassNames: {
            counties: 'SGID10.BOUNDARIES.Counties',
            utah: 'SGID10.BOUNDARIES.Utah',
            city: 'SGID10.BOUNDARIES.Municipalities_Carto', // _Carto version to make sure that Draper is not split on county line
            zip: 'SGID10.BOUNDARIES.ZipCodes'
        },

        // TRSMinScaleLevel: Number
        //      The minimum scale level that the TRS Layer will draw.
        TRSMinScaleLevel: 10,

        // RiskLayersMinScaleLevel: Number
        //      The minimum scale level that the three risk layers draw.
        RiskLayersMinScaleLevel: 14,

        // NHDMinScaleLevel: Number
        //      The minimum scale level that the nhd layer will draw.
        NHDMinScaleLevel: 13,

        // appJson: Object
        //      Cache for data returned by getAppJson
        appJson: null,

        // queryLayerNames: Object
        //      Lookup for query layer name by layer index
        //      Populated in getAppJson below
        queryLayerNames: null,

        // spatialReference SpatialReference
        //      The spatial reference of the map
        spatialReference: new SpatialReference(3857),

        // symbols: Object
        //      Graphic symbols used in this app
        symbols: {
            zoom: {
                polygon: new SimpleFillSymbol(
                    SimpleFillSymbol.STYLE_SOLID,
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID,
                        zoomColor,
                        2
                    ),
                    zoomFillColor),
                point: new SimpleMarkerSymbol(
                    SimpleMarkerSymbol.STYLE_CIRCLE,
                    13,
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID,
                        zoomColor,
                        2),
                    zoomFillColor),
                polyline: new SimpleLineSymbol(
                    SimpleLineSymbol.STYLE_SOLID,
                    zoomColor,
                    4
                )
            },
            resultSymbolOpacity: 0.65,
            colors: [
                [31, 120, 180],
                [51, 160, 44],
                [227, 26, 28],
                [255, 127, 0],
                [106, 61, 154],
                [253, 191, 111],
                [251, 154, 153],
                [178, 223, 138],
                [166, 206, 227],
                [202, 178, 214],
                [255, 255, 153],
                [177, 89, 40]
            ],
            selection: {
                polygon: new SimpleFillSymbol(
                    SimpleFillSymbol.STYLE_SOLID,
                    new CartographicLineSymbol(
                        CartographicLineSymbol.STYLE_SOLID,
                        selectionColor,
                        3,
                        CartographicLineSymbol.CAP_ROUND,
                        CartographicLineSymbol.JOIN_ROUND),
                    selectionFillColor
                ),
                point: new SimpleMarkerSymbol(
                    SimpleMarkerSymbol.STYLE_CIRCLE,
                    12,
                    new SimpleLineSymbol(
                        SimpleLineSymbol.STYLE_SOLID,
                        selectionColor,
                        2),
                    selectionFillColor
                )
            }
        },

        // messages: Object
        //      Messages and text used throughout the app
        messages: {
            noFeaturesFound: 'No results'
        },

        parameterNames: {
            output: 'output' // download service
        },

        getAppJson: function () {
            // summary:
            //      requests the DEQEnviro.json data and returns it, caches the results for future requests
            console.log('app.config::getAppJson', arguments);

            var def = new Deferred();

            if (this.appJson) {
                def.resolve(this.appJson);
            } else if (this.appJsonRequest) {
                // prevent simultanious requests
                this.appJsonRequest.then(() => {
                    def.resolve(this.appJson);
                });
            } else {
                // get a fresh copy of the json file on each load
                this.appJsonRequest = xhr(this.urls.json, {
                    handleAs: 'json'
                }).then((json) => {
                    this.queryLayerNames = {};
                    json.queryLayers.forEach((ql) => {
                        this.queryLayerNames[ql.index] = ql.name;
                    });
                    this.appJsonRequest = null;
                    def.resolve(this.appJson = json);
                });
            }

            return def.promise;
        },
        getQueryLayerByIndex: function (index) {
            // summary:
            //      description
            // index: String
            // console.log('app/config:getQueryLayerByIndex', arguments);

            return this.getDatasetByIndex(this.appJson.queryLayers, index);
        },
        getRelatedTableByIndex: function (index) {
            // summary:
            //      description
            // index: String
            // console.log('app/config:getRelatedTableByIndex', arguments);

            return this.getDatasetByIndex(this.appJson.relatedTables, index);
        },
        getDatasetByIndex: function (datasets, index) {
            // this could easily be done with one loop but I wanted to try
            // out memoization :)
            this._cached = this._cached || {};

            if (this._cached[index]) {
                return this._cached[index];
            }

            var returnLayer;
            array.some(datasets, function (ql) {
                if (ql.index === index) {
                    returnLayer = ql;

                    return true;
                }

                return false;
            });

            this._cached[index] = returnLayer;

            return returnLayer;
        }
    });

    return window.AGRC;
});
<|endoftext|>


<commit_before>;(function($, window, document){

    var pluginName = "snapDragon";

    function SnapDragon(element, options){
        // Store stome references to the element on the instance
        this.el = element;
        this.$el = $(element);

        this.enabled = true;

        // Merge passed options with defaults
        this.options = $.extend({}, $.fn.snapDragon.defaults, options);

        this.init();
    }

    SnapDragon.prototype = {

        init: function(){
            var that = this;

            // get the hammer instance
            var hammertime = this.$el.data("hammer");

            hammertime.on("dragstart", function(e){
                if(that.enabled){
                    handleDragStart(e);
                }
            });

            hammertime.on("drag", function(e){
                if(that.enabled){
                    if(that.options.ignore_vertical_drags){
                        // only handle drag events on left/right drags
                        if(e.gesture.direction == "left" || e.gesture.direction == "right"){
                            handleTouchDrag(e);
                        }
                    } else {
                        handleTouchDrag(e);
                    }
                }
            });

            hammertime.on("dragend", function(e){
                if(that.enabled){
                    handleDragEnd(e);
                }
            });

            if(this.options.initDisabled){
                this.disable();
            }

        },

        destroy: function() {

            // Remove attached data
            this.$el.removeData(pluginName);
        },

        enable: function() {
            this.enabled = true;
            console.log("enabling");
        },

        disable: function(){
            this.enabled = false;
        },

        // Given a location, snap to it
        snapToLocation: function(location){
            var distanceToSnap = Math.abs(getXPos(this.$el) - location);
            if(distanceToSnap > 0){
                this.setPosition(location, true);
            }
        },

        // Given a snapPos, snap to it
        // If a location is passed isntead, attempt to find the snapPos at that
        // location
        snapToSnapPos: function(snapPos){
            if(typeof snapPos == "number"){
                // get snapPos at that number
            } else if (typeof snapPos == "object"){
                // we probably have a snapPos, snap to it
                var location = snapPos.location;
                var distanceToSnap = Math.abs(getXPos(this.$el) - location);
                if(distanceToSnap > 0){
                    // pass along this snapPosition's callback
                    this.setPosition(location, true, snapPos.callback);
                }
            } else {
                // throw error
            }

        },

        // Figures out whether the destination is a position or a snapPos and
        // calls the appropriate function
        snapTo: function(destination){
            if(typeof destination == "object"){
                this.snapToSnapPos(destination);
            } else {
                this.snapToLocation(destination);
            }

        },

        setPosition: function(position, withTransition, callback){
            var snapDragonInstance = this;

            // if this particular instance of snapDragon has defined a moveAlso,
            // it means we need to move something along with this element
            if(this.options.moveAlso){
                var otherElements = $(this.options.moveAlso.selector);
            }

            // if there are no other elements to move, just set the var to the
            // empty jquery object so that the jquery methods below don't
            // throw an error
            otherElements = otherElements ? otherElements : $();

            // call the moveCallback if there is one
            if(snapDragonInstance.options.moveCallback){
                snapDragonInstance.options.moveCallback(position, withTransition);
            }

            // if we're not using a transition (probably because were in the
            // middle of a drag), we can just straight up set the new position
            if(withTransition == false || withTransition == undefined){
                this.$el.css("-webkit-transform", "translateX("+position+"px)");
                if(otherElements.length != 0){
                    // WARNING, this will break if moveFn is not defined
                    // TODO: dont break if moveFn is not defined lols
                    otherPosition = this.options.moveAlso.moveFn(position);
                    otherElements.css("-webkit-transform", "translateX("+otherPosition+"px)");
                }
            // but if so, we probably need to snap to a location
            } else {
                // find and disable hammer during this transition
                var hammertime = this.$el.data("hammer");
                if(hammertime){
                    hammertime.enable(false);
                }

                // add transition class
                this.$el.addClass("snapDragonTransition");
                otherElements.addClass("snapDragonTransition");

                // set new positions
                this.$el.css("-webkit-transform", "translateX("+position+"px)");

                if(otherElements.length != 0){
                    otherPosition = this.options.moveAlso.moveFn(position);
                    otherElements.css("-webkit-transform", "translateX("+otherPosition+"px)");
                }

                // save reference for this next event handler function
                var that = this;

                // .one() runs and then unbinds itself
                this.$el.one("webkitTransitionEnd", function(){
                    // after transition is done, re-enable hammer
                    if(hammertime){
                        hammertime.enable(true);
                    }

                    // ...and remove the transition class
                    that.$el.removeClass("snapDragonTransition");
                    otherElements.removeClass("snapDragonTransition");

                    //...and call the callback, if there was one
                    if(callback !== undefined){
                        callback(snapDragonInstance);
                    }

                });
            }
        }

    }

    $.fn.snapDragon = function(options) {

        var args = arguments;

        // an object of options (or nothing) was passed in */
        if (options === undefined || typeof options === 'object') {

            // Create a new instance for each object in the selector and
            // store a reference to the instance in the element's data.
            // Returning the result of each so that chaining works.

            return this.each(function() {
                if (!$.data(this, pluginName)) {
                    $.data(this, pluginName, new SnapDragon(this, options));
                }
            });

        } else {
            // TODO
            // Call a public plugin method (not starting with an underscore) for each
            // selected element. (like destroy for example)
            //
            // args used down here if necessarys
        }

    };

    function handleDragStart(e){
        var target = $(e.delegateTarget);
        target.data(pluginName).dragStartLocation = getXPos(target);
    }

    function handleTouchDrag(e){
        var target = $(e.delegateTarget);

        var delta = deltaFromLastDrag(e, target);

        /* get the current X translate of the invoice */
        var currentXPos = getXPos(target);

        /* calculate the new X position using the current and the delta */
        var newXPos = currentXPos + delta;

        var boundaries = target.data(pluginName).options.boundaries;
        if(boundaries){
            if(boundaries.right != undefined){
                if(newXPos > boundaries.right){
                    newXPos = boundaries.right;
                }
            }
            if(boundaries.left != undefined){
                if(newXPos < boundaries.left){
                    newXPos = boundaries.left;
                }
            }
        }

        var snapDragon = target.data("snapDragon");
        snapDragon.setPosition(newXPos, false);

    }

    function handleDragEnd(e){
        var target = $(e.delegateTarget);

        /* get the current X translate of the invoice */
        //var currentXPos = getXPos(target);

        /* RESET the last drag position whenever we end a drag so it doesn't
         * pop to the wrong place when the next drag is started--this is VERY
         * IMPORTANT
         */
        target.removeData("last-drag-pos-x");

        var currentXPos = getXPos(target);

        // Find out what the location was at the beginning of this drag
        var dragStartLocation = target.data(pluginName).dragStartLocation;

        // See if that position was one of the defined snap positions
        var dragStartSnapPosition = getSnapPosition(target, dragStartLocation);

        if(dragStartSnapPosition !== undefined){
            if(brokeThreshold(dragStartSnapPosition, currentXPos)){
                var snapPos = getClosestSnapPos(target, [dragStartSnapPosition.location]);
                target.data(pluginName).snapTo(snapPos);
                // it broke out of it's threshold, find a new position to snap to (or don't, maybe)
            } else {
                target.data(pluginName).snapTo(dragStartSnapPosition);
            };
        }

    }

    function brokeThreshold(snapPosition, currentXPos){
        return (Math.abs(currentXPos - snapPosition.location) > snapPosition.threshold);
    }

    /* Given a location, finds if there is a snap position there */
    function getSnapPosition(target, location){
        var snapPositions = target.data(pluginName).options.snapPositions;

        for(var i=0; i < snapPositions.length; i++){
            var snapPosition = snapPositions[i];
            if(snapPosition.location == location){
                return snapPosition;
            }
        }

        return undefined;
    }

    function getClosestSnapPos(target, excludedLocations){

        var snapPositions = target.data(pluginName).options.snapPositions;
        var currentXPos = getXPos(target)

        var closest = -1;
        var minDistance = -1;
        for(var i=0; i < snapPositions.length; i++){
            var snapPosition = snapPositions[i];

            if(excludedLocations.indexOf(snapPosition.location) == -1){
                var distance = Math.abs(currentXPos-snapPosition.location);

                if((distance < minDistance) || (minDistance == -1)){
                    minDistance = distance;
                    closest = snapPosition;
                }
            }
        }

        return closest;

    }

    /* Also sets the the current drag pos as data for the next drag */
    function deltaFromLastDrag(e, element){
        /* get the X position of the current drag event */
        var currentDragPosX = e.gesture.center.pageX;
        /* get the X position of the last drag event on this element */
        var lastDragPosX = element.data("last-drag-pos-x");

        /* compute delta by using these two positions, if there was no
         * previous event, default to 0
         */
        if (lastDragPosX == undefined) {
            var delta = 0;
        } else {
            var delta = currentDragPosX - lastDragPosX;
        }

        /* finally set the last drag position for next time */
        element.data("last-drag-pos-x", currentDragPosX);

        return delta;
    }

    function getXPos(elem){
        var transformMatrix = new WebKitCSSMatrix(elem.css("-webkit-transform"));
        var currentXPos = transformMatrix.m41; /* matrix 4th row, 1st column */
        return currentXPos;
    }

    $.fn.snapDragon.defaults = {
        ignore_vertical_drags: true
    };

}(jQuery, window, document));<commit_msg>Pass snapDragon instance into event handling fns, make getSnapPos an instance fn, use it in snapToSnapPos to find snapPos at location<commit_after>;(function($, window, document){

    var pluginName = "snapDragon";

    function SnapDragon(element, options){
        // Store stome references to the element on the instance
        this.el = element;
        this.$el = $(element);

        this.enabled = true;

        // Merge passed options with defaults
        this.options = $.extend({}, $.fn.snapDragon.defaults, options);

        this.init();
    }

    SnapDragon.prototype = {

        init: function(){
            var that = this;

            // get the hammer instance
            var hammertime = this.$el.data("hammer");

            hammertime.on("dragstart", function(e){
                if(that.enabled){
                    handleDragStart(e, that);
                }
            });

            hammertime.on("drag", function(e){
                if(that.enabled){
                    if(that.options.ignore_vertical_drags){
                        // only handle drag events on left/right drags
                        if(e.gesture.direction == "left" || e.gesture.direction == "right"){
                            handleTouchDrag(e, that);
                        }
                    } else {
                        handleTouchDrag(e, that);
                    }
                }
            });

            hammertime.on("dragend", function(e){
                if(that.enabled){
                    handleDragEnd(e, that);
                }
            });

            // if the options dictate, immediately disable after init
            if(this.options.initDisabled){
                this.disable();
            }

        },

        destroy: function() {

            // Remove attached data
            this.$el.removeData(pluginName);
        },

        enable: function() {
            this.enabled = true;
            console.log("enabling");
        },

        disable: function(){
            this.enabled = false;
        },

        // Given a location, snap to it
        snapToLocation: function(location){
            var distanceToSnap = Math.abs(getXPos(this.$el) - location);
            if(distanceToSnap > 0){
                this.setPosition(location, true);
            }
        },

        // Given a snapPos, snap to it
        // If a location is passed isntead, attempt to find the snapPos at that
        // location
        snapToSnapPos: function(snapPos){
            if(typeof snapPos == "number"){
                var snapPos = this.getSnapPosition(snapPos);
                if(snapPos == undefined){
                    throw Error("No snap position at location: " + snapPos);
                } else {
                    this.snapToSnapPos(snapPos);
                }
            } else if (typeof snapPos == "object"){
                // we probably have a snapPos, snap to it
                var location = snapPos.location;
                var distanceToSnap = Math.abs(getXPos(this.$el) - location);
                if(distanceToSnap > 0){
                    // pass along this snapPosition's callback
                    this.setPosition(location, true, snapPos.callback);
                }
            } else {
                // throw error
            }

        },

        // Figures out whether the destination is a position or a snapPos and
        // calls the appropriate function
        snapTo: function(destination){
            if(typeof destination == "object"){
                this.snapToSnapPos(destination);
            } else {
                this.snapToLocation(destination);
            }

        },

        /* Given a location, finds if there is a snap position there */
        getSnapPosition: function(location){
            var snapPositions = this.options.snapPositions;

            for(var i=0; i < snapPositions.length; i++){
                var snapPosition = snapPositions[i];
                if(snapPosition.location == location){
                    return snapPosition;
                }
            }

            return undefined;
        },

        setPosition: function(position, withTransition, callback){
            var snapDragonInstance = this;

            // if this particular instance of snapDragon has defined a moveAlso,
            // it means we need to move something along with this element
            if(this.options.moveAlso){
                var otherElements = $(this.options.moveAlso.selector);
            }

            // if there are no other elements to move, just set the var to the
            // empty jquery object so that the jquery methods below don't
            // throw an error
            otherElements = otherElements ? otherElements : $();

            // call the moveCallback if there is one
            if(snapDragonInstance.options.moveCallback){
                snapDragonInstance.options.moveCallback(position, withTransition);
            }

            // if we're not using a transition (probably because were in the
            // middle of a drag), we can just straight up set the new position
            if(withTransition == false || withTransition == undefined){
                this.$el.css("-webkit-transform", "translateX("+position+"px)");
                if(otherElements.length != 0){
                    // WARNING, this will break if moveFn is not defined
                    // TODO: dont break if moveFn is not defined lols
                    otherPosition = this.options.moveAlso.moveFn(position);
                    otherElements.css("-webkit-transform", "translateX("+otherPosition+"px)");
                }
            // but if so, we probably need to snap to a location
            } else {
                // find and disable hammer during this transition
                var hammertime = this.$el.data("hammer");
                if(hammertime){
                    hammertime.enable(false);
                }

                // add transition class
                this.$el.addClass("snapDragonTransition");
                otherElements.addClass("snapDragonTransition");

                // set new positions
                this.$el.css("-webkit-transform", "translateX("+position+"px)");

                if(otherElements.length != 0){
                    otherPosition = this.options.moveAlso.moveFn(position);
                    otherElements.css("-webkit-transform", "translateX("+otherPosition+"px)");
                }

                // save reference for this next event handler function
                var that = this;

                // .one() runs and then unbinds itself
                this.$el.one("webkitTransitionEnd", function(){
                    // after transition is done, re-enable hammer
                    if(hammertime){
                        hammertime.enable(true);
                    }

                    // ...and remove the transition class
                    that.$el.removeClass("snapDragonTransition");
                    otherElements.removeClass("snapDragonTransition");

                    //...and call the callback, if there was one
                    if(callback !== undefined){
                        callback(snapDragonInstance);
                    }

                });
            }
        }

    }

    $.fn.snapDragon = function(options) {

        var args = arguments;

        // an object of options (or nothing) was passed in */
        if (options === undefined || typeof options === 'object') {

            // Create a new instance for each object in the selector and
            // store a reference to the instance in the element's data.
            // Returning the result of each so that chaining works.

            return this.each(function() {
                if (!$.data(this, pluginName)) {
                    $.data(this, pluginName, new SnapDragon(this, options));
                }
            });

        } else {
            // TODO
            // Call a public plugin method (not starting with an underscore) for each
            // selected element. (like destroy for example)
            //
            // args used down here if necessarys
        }

    };

    function handleDragStart(e, snapDragonInstance){
        var target = $(e.delegateTarget);
        snapDragonInstance.dragStartLocation = getXPos(target);
    }

    function handleTouchDrag(e, snapDragonInstance){
        var target = $(e.delegateTarget);

        var delta = deltaFromLastDrag(e, target);

        /* get the current X translate of the invoice */
        var currentXPos = getXPos(target);

        /* calculate the new X position using the current and the delta */
        var newXPos = currentXPos + delta;

        var boundaries = target.data(pluginName).options.boundaries;
        if(boundaries){
            if(boundaries.right != undefined){
                if(newXPos > boundaries.right){
                    newXPos = boundaries.right;
                }
            }
            if(boundaries.left != undefined){
                if(newXPos < boundaries.left){
                    newXPos = boundaries.left;
                }
            }
        }

        snapDragonInstance.setPosition(newXPos, false);

    }

    function handleDragEnd(e, snapDragonInstance){
        var target = $(e.delegateTarget);

        /* get the current X translate of the invoice */
        //var currentXPos = getXPos(target);

        /* RESET the last drag position whenever we end a drag so it doesn't
         * pop to the wrong place when the next drag is started--this is VERY
         * IMPORTANT
         */
        target.removeData("last-drag-pos-x");

        var currentXPos = getXPos(target);

        // Find out what the location was at the beginning of this drag
        var dragStartLocation = target.data(pluginName).dragStartLocation;

        // See if that position was one of the defined snap positions
        var dragStartSnapPosition = snapDragonInstance.getSnapPosition(dragStartLocation);

        if(dragStartSnapPosition !== undefined){
            if(brokeThreshold(dragStartSnapPosition, currentXPos)){
                var snapPos = getClosestSnapPos(target, [dragStartSnapPosition.location]);
                target.data(pluginName).snapTo(snapPos);
                // it broke out of it's threshold, find a new position to snap to (or don't, maybe)
            } else {
                target.data(pluginName).snapTo(dragStartSnapPosition);
            };
        }

    }

    function brokeThreshold(snapPosition, currentXPos){
        return (Math.abs(currentXPos - snapPosition.location) > snapPosition.threshold);
    }

    function getClosestSnapPos(target, excludedLocations){

        var snapPositions = target.data(pluginName).options.snapPositions;
        var currentXPos = getXPos(target)

        var closest = -1;
        var minDistance = -1;
        for(var i=0; i < snapPositions.length; i++){
            var snapPosition = snapPositions[i];

            if(excludedLocations.indexOf(snapPosition.location) == -1){
                var distance = Math.abs(currentXPos-snapPosition.location);

                if((distance < minDistance) || (minDistance == -1)){
                    minDistance = distance;
                    closest = snapPosition;
                }
            }
        }

        return closest;

    }

    /* Also sets the the current drag pos as data for the next drag */
    function deltaFromLastDrag(e, element){
        /* get the X position of the current drag event */
        var currentDragPosX = e.gesture.center.pageX;
        /* get the X position of the last drag event on this element */
        var lastDragPosX = element.data("last-drag-pos-x");

        /* compute delta by using these two positions, if there was no
         * previous event, default to 0
         */
        if (lastDragPosX == undefined) {
            var delta = 0;
        } else {
            var delta = currentDragPosX - lastDragPosX;
        }

        /* finally set the last drag position for next time */
        element.data("last-drag-pos-x", currentDragPosX);

        return delta;
    }

    function getXPos(elem){
        var transformMatrix = new WebKitCSSMatrix(elem.css("-webkit-transform"));
        var currentXPos = transformMatrix.m41; /* matrix 4th row, 1st column */
        return currentXPos;
    }

    $.fn.snapDragon.defaults = {
        ignore_vertical_drags: true
    };

}(jQuery, window, document));<|endoftext|>


<commit_before>const koa = require('koa');
const app = new koa();
const config = require('config');
const router = require('./router');
require('./db')();

app.keys = config.app.keys;
app.proxy = true;

app.use(require('koa-logger')());
app.use(require('koa-compress')());
app.use(require('koa-static-cache')('./public', {
	maxAge: config.app.cacheAge
}));
app.use(require('koa-views')(__dirname + '/views', {
	extension: 'pug'
}));

app.use(router.routes(), router.allowedMethods());

module.exports = app;
<commit_msg>Improve path resolution<commit_after>const koa = require('koa');
const app = new koa();
const config = require('config');
const path = require('path');
const router = require('./router');
require('./db')();

app.keys = config.app.keys;
app.proxy = true;

app.use(require('koa-logger')());
app.use(require('koa-compress')());
app.use(require('koa-static-cache')(path.join(__dirname, 'public'), {
	maxAge: config.app.cacheAge
}));
app.use(require('koa-views')(path.join(__dirname, 'views'), {
	extension: 'pug'
}));

app.use(router.routes(), router.allowedMethods());

module.exports = app;
<|endoftext|>