<commit_before>// Vkontakte (vk.com)
(function(hello) {

	hello.init({

		vk: {
			name: 'Vk',

			// See https://vk.com/dev/oauth_dialog
			oauth: {
				version: 2,
				auth: 'https://oauth.vk.com/authorize',
				grant: 'https://oauth.vk.com/access_token'
			},

			// Authorization scopes
			scope: {
				basic: '',
				email: 'email',
				offline_access: 'offline'
			},

			// Refresh the access_token
			refresh: true,

			login: function(p) {
				p.qs.display = window.navigator &&
					window.navigator.userAgent &&
					/ipad|phone|phone|android/.test(window.navigator.userAgent.toLowerCase())
					? 'mobile' : 'popup';
			},

			// API Base URL
			base: 'https://api.vk.com/method/',

			// Map GET requests
			get: {
				me: 'users.get'
			},

			// Map POST requests
			post: false,

			wrap: {
				me: formatUser
			},

			// No XHR
			xhr: false,

			// All requests should be JSONP as of missing CORS headers in https://api.vk.com/method/*
			jsonp: function(p, qs) {

				if (p.path === 'me') {
					qs.fields = 'id,first_name,last_name,photo_max';
				}

				return true;
			},

			// No form
			form: false
		}
	});

	function formatUser(o) {

		if (o != null && o.response != null && o.response.length) {
			o = o.response[0];
			o.id = o.uid;
			o.thumbnail = o.picture = o.photo_max;
			o.name = o.first_name + ' ' + o.last_name;

			var vk = hello.utils.store('vk');

			if (vk != null && vk.email != null)
				o.email = vk.email;
		}

		return o;
	}
})(hello);
<commit_msg>Added vk.js<commit_after>// Vkontakte (vk.com)
(function(hello) {

	hello.init({

		vk: {
			name: 'Vk',

			// See https://vk.com/dev/oauth_dialog
			oauth: {
				version: 2,
				auth: 'https://oauth.vk.com/authorize',
				grant: 'https://oauth.vk.com/access_token'
			},

			// Authorization scopes
			scope: {
				basic: '',
				email: 'email',
				offline_access: 'offline'
			},

			// Refresh the access_token
			refresh: true,

			login: function(p) {
				p.qs.display = window.navigator &&
					window.navigator.userAgent &&
					/ipad|phone|phone|android/.test(window.navigator.userAgent.toLowerCase())
					? 'mobile' : 'popup';
			},

			// API Base URL
			base: 'https://api.vk.com/method/',

			// Map GET requests
			get: {
				me: 'users.get'
			},

			// Map POST requests
			post: false,

			wrap: {
				me: formatUser
			},

			// No XHR
			xhr: false,

			// All requests should be JSONP as of missing CORS headers in https://api.vk.com/method/*
			jsonp: function(p, qs) {

				if (p.path === 'me') {
					qs.fields = 'id,first_name,last_name,photo_max';
				}

				return true;
			},

			// No form
			form: false
		}
	});

	function formatUser(o) {

		if (o != null && o.response != null && o.response.length) {
			o = o.response[0];
			o.id = o.uid;
			o.thumbnail = o.picture = o.photo_max;
			o.name = o.first_name + ' ' + o.last_name;

			var vk = hello.utils.store('vk');

			if (vk != null && vk.email != null)
				o.email = vk.email;
		}

		return o;
	}
})(hello);
<|endoftext|>


<commit_before>export default {
  el: {
    colorpicker: {
      confirm: 'Confirmar',
      clear: 'Netejar'
    },
    datepicker: {
      now: 'Ara',
      today: 'Avui',
      cancel: 'Cancel·lar',
      clear: 'Netejar',
      confirm: 'Confirmar',
      selectDate: 'Seleccionar data',
      selectTime: 'Seleccionar hora',
      startDate: 'Data Inici',
      startTime: 'Hora Inici',
      endDate: 'Data Final',
      endTime: 'Hora Final',
      year: 'Any',
      month1: 'Gener',
      month2: 'Febrer',
      month3: 'Març',
      month4: 'Abril',
      month5: 'Maig',
      month6: 'Juny',
      month7: 'Juliol',
      month8: 'Agost',
      month9: 'Setembre',
      month10: 'Octubre',
      month11: 'Novembre',
      month12: 'Desembre',
      // week: 'setmana',
      weeks: {
        sun: 'Dg',
        mon: 'Dl',
        tue: 'Dt',
        wed: 'Dc',
        thu: 'Dj',
        fri: 'Dv',
        sat: 'Ds'
      },
      months: {
        jan: 'Gen',
        feb: 'Febr',
        mar: 'Març',
        apr: 'Abr',
        may: 'Maig',
        jun: 'Juny',
        jul: 'Jul',
        aug: 'Ag',
        sep: 'Set',
        oct: 'Oct',
        nov: 'Nov',
        dec: 'Des'
      }
    },
    select: {
      loading: 'Carregant',
      noMatch: 'No hi ha dades que coincideixin',
      noData: 'Sense Dades',
      placeholder: 'Seleccionar'
    },
    cascader: {
      noMatch: 'No hi ha dades que coincideixin',
      loading: 'Carregant',
      placeholder: 'Seleccionar'
    },
    pagination: {
      goto: 'Anar a',
      pagesize: '/pagina',
      total: 'Total {total}',
      pageClassifier: ''
    },
    messagebox: {
      confirm: 'Acceptar',
      cancel: 'Cancel·lar',
      error: 'Entrada invàlida'
    },
    upload: {
      delete: 'Eliminar',
      preview: 'Vista Prèvia',
      continue: 'Continuar'
    },
    table: {
      emptyText: 'Sense Dades',
      confirmFilter: 'Confirmar',
      resetFilter: 'Netejar',
      clearFilter: 'Tot',
      sumText: 'Sum' // to be translated
    },
    tree: {
      emptyText: 'Sense Dades'
    },
    transfer: {
      noMatch: 'No hi ha dades que coincideixin',
      noData: 'Sense Dades',
      titles: ['Llista 1', 'Llista 2'],
      filterPlaceholder: 'Introdueix la paraula clau',
      noCheckedFormat: '{total} ítems',
      hasCheckedFormat: '{checked}/{total} seleccionats'
    }
  }
};
<commit_msg>Update ca.js<commit_after>export default {
  el: {
    colorpicker: {
      confirm: 'Confirmar',
      clear: 'Netejar'
    },
    datepicker: {
      now: 'Ara',
      today: 'Avui',
      cancel: 'Cancel·lar',
      clear: 'Netejar',
      confirm: 'Confirmar',
      selectDate: 'Seleccionar data',
      selectTime: 'Seleccionar hora',
      startDate: 'Data Inici',
      startTime: 'Hora Inici',
      endDate: 'Data Final',
      endTime: 'Hora Final',
      year: 'Any',
      month1: 'Gener',
      month2: 'Febrer',
      month3: 'Març',
      month4: 'Abril',
      month5: 'Maig',
      month6: 'Juny',
      month7: 'Juliol',
      month8: 'Agost',
      month9: 'Setembre',
      month10: 'Octubre',
      month11: 'Novembre',
      month12: 'Desembre',
      // week: 'setmana',
      weeks: {
        sun: 'Dg',
        mon: 'Dl',
        tue: 'Dt',
        wed: 'Dc',
        thu: 'Dj',
        fri: 'Dv',
        sat: 'Ds'
      },
      months: {
        jan: 'Gen',
        feb: 'Febr',
        mar: 'Març',
        apr: 'Abr',
        may: 'Maig',
        jun: 'Juny',
        jul: 'Jul',
        aug: 'Ag',
        sep: 'Set',
        oct: 'Oct',
        nov: 'Nov',
        dec: 'Des'
      }
    },
    select: {
      loading: 'Carregant',
      noMatch: 'No hi ha dades que coincideixin',
      noData: 'Sense Dades',
      placeholder: 'Seleccionar'
    },
    cascader: {
      noMatch: 'No hi ha dades que coincideixin',
      loading: 'Carregant',
      placeholder: 'Seleccionar'
    },
    pagination: {
      goto: 'Anar a',
      pagesize: '/pagina',
      total: 'Total {total}',
      pageClassifier: ''
    },
    messagebox: {
      confirm: 'Acceptar',
      cancel: 'Cancel·lar',
      error: 'Entrada invàlida'
    },
    upload: {
      delete: 'Eliminar',
      preview: 'Vista Prèvia',
      continue: 'Continuar'
    },
    table: {
      emptyText: 'Sense Dades',
      confirmFilter: 'Confirmar',
      resetFilter: 'Netejar',
      clearFilter: 'Tot',
      sumText: 'Tot'
    },
    tree: {
      emptyText: 'Sense Dades'
    },
    transfer: {
      noMatch: 'No hi ha dades que coincideixin',
      noData: 'Sense Dades',
      titles: ['Llista 1', 'Llista 2'],
      filterPlaceholder: 'Introdueix la paraula clau',
      noCheckedFormat: '{total} ítems',
      hasCheckedFormat: '{checked}/{total} seleccionats'
    }
  }
};
<|endoftext|>


<commit_before>/*
Mag.JS AddOns v0.21.8
(c) Michael Glazer 2016
https://github.com/magnumjs/mag.js
Requires: MagJS (core) Addons: Ajax , Router
*/

;
(function(mag, window, document, undefined) {

  'use strict';

  // helper
  mag.noop = function() {}

  //UTILITY
  // mag.utils.copy - now in core
  // mag.utils.merge - now in core

  mag.copy = mag.utils.copy
  mag.merge = mag.utils.merge

  /*
  controller:function(props)
    // if props has a property 'isVisible' when true will display entire module on before updates
    mag.show(this,'isVisible')
  }
  http://jsbin.com/fegizubime/edit?html,js,output
  */

  // show hide

  mag.show = function(context, conditionName) {
    var ctype = typeof context;
    if (ctype !== 'object') {
      var obj = {
        _config: function(node) {
          node.style.display = context ? 'block' : 'none'
        }
      }
      if (typeof conditionName == 'object') {
        mag.merge(conditionName, obj)
      }
      return obj
    } else if (ctype == 'object') {
      context.willload = function(event, node, inprops) {
        node.style.display = 'block'
      }
    } else {
      context.willupdate = function(event, node, inprops) {
        node.style.display = inprops[conditionName] ? 'block' : 'none'
      }
    }
  }

  // promises

  /*
  var d = mag.deferred()

  d.promise.then(function() {
    console.log('success', arguments)
  }, function() {
    console.log('failure', arguments)
  })
  d.reject({
    things: false
  })
  d.resolve({
    things: []
  })
  */

mag.deferred = function() {
  var Deferred = {}
  Deferred.promise = new Promise(function(resolve, reject) {
    Deferred.resolve = resolve
    Deferred.reject = reject
  })
  return Deferred
}

mag.when = function(arrayOfPromises, callback) {
  return Promise.all(arrayOfPromises).then(callback)
}

//TODO: add jsonp support

mag.request = function(options) {
  var deferred = mag.deferred();
  if (options.initialValue) {
    deferred.promise.initialValue = options.initialValue
  }
  //Uid:
  var key = JSON.stringify(options)
    //Cache:
  if (options.cache) {
    var cache = mag.cache(key)
    if (cache) {
      deferred.resolve(cache)
      return deferred.promise
    }
  }

  //In queue:
  if (mag.request.queue[key]) {
    return mag.request.queue[key]
  }
  //Add to queue
  mag.request.queue[key] = deferred.promise;

  var client = new XMLHttpRequest();
  var method = (options.method || 'GET').toUpperCase();
  var data = method === "GET" || !options.data ? "" : options.data

  client.onload = function(e) {
    var ct = client.getResponseHeader("content-type") || "";
    var data = e.target.responseText;
    if (ct.indexOf('json') > -1) {
      data = JSON.parse(data)
    }
    if (options.cache) {
      mag.cache(key, data, options.cacheTime, options.cacheType)
    }
    delete mag.request.queue[key];
    var headers = client.getAllResponseHeaders();
    deferred.resolve(data, headers);
  }

  client.onerror = function(e) {
    deferred.reject(e)
  };

  client.open(method, options.url);
    //Headers:
  if(options.headers){
    for(var i=0;i<options.headers.length;i++){
    	var header = options.headers[i]
      for(var k in header){
    	  client.setRequestHeader(k, header[k]);
      }
    }
  }
  client.send(data);

  return deferred.promise
}
mag.request.queue = {}

mag.cache = function(key, data, cacheTime, storageType) {
   var stype = window[storageType || 'sessionStorage']

  if (arguments.length == 1) {

    if (mag.cache.data[key]) {
      return mag.cache.data[key].data;
    } else {
      // check storage
      var item = stype.getItem(key)
      if (item) {
        mag.cache.data[key] = JSON.parse(item)
        return mag.cache.data[key].data
      }
      else return 0;
    }
  }

  if (mag.cache.data[key] && mag.cache.data[key].id) clearTimeout(mag.cache.data[key].id)

  var intervalID = setTimeout(function(key) {
    stype.removeItem(key);
    delete mag.cache.data[key]
  }.bind({}, key), cacheTime || 1000 * 60 * 10); //10 minutes

  mag.cache.data[key] = {
    id: intervalID,
    data: data
  }

  stype.setItem(key, JSON.stringify(mag.cache.data[key]))
}
mag.cache.data = {}

  // goes with mag.request for json ajax requests
  /*
  will show and hide all ''.loader' elements in transition
  */
  mag.requestWithFeedback = function(args) {
    var key = JSON.stringify(args)
    if (!mag.requestWithFeedback.cache[key]) {

      var loaders = document.querySelectorAll(".loader")

      //show icons
      for (var i = 0, loader; loader = loaders[i]; i++) loader.style.display = "block"

      var expire = function(data) {
        delete mag.requestWithFeedback.cache[key]

        if (Object.keys(mag.requestWithFeedback.cache).length == 0) {
          //hide icons
          for (var i = 0, loader; loader = loaders[i]; i++) loader.style.display = "none"
        }
        return data
      }
      mag.requestWithFeedback.cache[key] = mag.request(args)
      mag.requestWithFeedback.cache[key].then(expire, function(error) {
        expire(error)
        throw error
      })
    }
    return mag.requestWithFeedback.cache[key]
  }
  mag.requestWithFeedback.cache = {}

  // disable add to config
  // http://jsbin.com/zepacabile/edit?js,output
  // define condition func
  // this.show = mag.prop(false);

  //define context
  //   this.input = mag.disable(this.show)
  // OR mag.disable(this.show, this.input={})
  //TODO: change to mag.ui.disable
 mag.disable = function(condition, obj) {

  // add or merge to config if not exists
  var orig = obj && obj._config ? obj._config : function() {};

  var tmp = {
    _config: function(n) {
      orig.apply(this, arguments);
      if (condition()) n.setAttribute('disabled', 'disabled');
      else n.removeAttribute('disabled');
    }
  }
  if (obj) {
    mag.merge(obj, tmp);
  }
  return tmp;

}

  // TODO: change to mag.find
  // find a MagJS element Matcher
  mag.find = function(parentRootId, selector) {
    var parent = document.getElementById(parentRootId);
    return mag.fill.find(parent, selector)
  }

  // mag.addons.toMenu(['one', 'two', 'three'], state.selected())
  // http://jsbin.com/mapuwojumu/3/edit?js,output
  //TODO change to mag.ui.menu
  mag.toMenu = function(maps, selected) {
    return maps.map(function(v, k) {
      return {
        _text: v,
        _value: k,
        _selected: selected === k || selected === v ? true : null
      }
    })
  }

  /*
  module library creation with single global namespace / package names
  (function(namespace) {

    var mod = {
      view: function(state, props) {
      }
    }

    namespace.CommentBox = mod;

  })(mag.namespace('mglazer.mods.comments'));
  */
  mag.namespace = function(ns, obj) {
    var levels = ns.split('.'),
      first = levels.shift();
    obj = obj || this; //if no object argument supplied declare a global property
    obj[first] = obj[first] || {}; // initialize the "level"
    if (levels.length) { // recursion condition
      return mag.namespace(levels.join('.'), obj[first]);
    }
    return obj[first]; // return a reference to the top level object
  }

  //ROUTER:

  mag.route = (function(window) {

    'use strict';

    var routes = [];

    function addRoute(route, handler) {

      routes.push({
        parts: route.split('/'),
        handler: handler
      });
    }

    function load(route) {
      window.location.hash = route;
    }

    function start() {

      var path = window.location.hash.substr(1),
        parts = path.split('/'),
        partsLength = parts.length;

      for (var i = 0; i < routes.length; i++) {
        var route = routes[i];
        if (route.parts.length === partsLength) {
          var params = [];
          for (var j = 0; j < partsLength; j++) {
            if (route.parts[j].substr(0, 1) === ':') {
              params.push(parts[j]);
            } else if (route.parts[j] !== parts[j]) {
              break;
            }
          }
          if (j === partsLength) {
            route.handler.apply(undefined, params);
            return;
          }
        }
      }
    }

    window.onhashchange = start;

    return {
      addRoute: addRoute,
      load: load,
      start: start
    };

  }(window));

  //PLUGINS!
  // hookins

function forEach(obj, fn) {
  var keys = Object.keys(obj);
  for (var i = 0, l = keys.length; i < l; ++i) {
    var key = keys[i];
    fn(key, obj[key]);
  }
}

mag.hookin('attributes', 'key', function(data) {
  // remove system key from being added to attributes in html
  data.value = null
});

function camelDash (val) {
	return val.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

mag.hookin('attributes', 'style', function(data) {

  //convert from object
  if (typeof data.value === 'object') {
    // get current styles not overwrite existing?

    var ostyle = data.node.getAttribute('style') || '';

    // make sure not already in styles
    var nstyle = ''
    forEach(data.value, function(key, value) {
     nstyle += camelDash(key) + ':' + (!isNaN(value) ? (value + "px") : value) + ';';
    });

    if(ostyle && ~ostyle.indexOf(nstyle)) data.value=ostyle;
    else data.value = ostyle+nstyle;

  }
});

  // _className plugin example
  mag.hookin('attributes', 'className', function(data) {
    data.key = 'class'
    var newClass = data.value

    if (typeof data.value == 'string') {
      newClass = data.value.split(' ')
    } else if (typeof data.value == 'object') {
      for (var k in newClass) {
        data.node.classList.toggle(k, newClass[k])
      }
      data.value = data.node.classList + ''
      return
    }

    data.value = data.node.classList + ''

    for (var k in newClass) {
      var cls = newClass[k]
      if (cls.trim() && data.node.classList.length > 0 && !data.node.classList.contains(cls.trim())) {
        data.value = data.node.classList + ' ' + cls

      } else if (cls.trim() && data.node.classList.length == 0) {
        data.value += cls + ' '
      }
    }

    data.value = data.value.trim()
  })

  //Values hookin:
mag.hookin('values', '*', function(data) {
  var dtype = typeof data.value

  if (data.value == null) {

  } else
  // allow function to return values
  if (dtype === 'function' && data.value.toJSON) {
    data.change = 1
    data.value = data.value()
  } else
  // Allow for promises to be resolved
  if (dtype == 'object' && typeof data.value.then == 'function') {
    var mid = mag.utils.items.getItem(mag.fill.id);

    data.value.then(function(newData) {
      mag.mod.getState(mid)[data.key] = newData;
    })

    if (data.value.initialValue) {
      data.change = 1
      data.value = data.value.initialValue
    }
  }
})

//GetId helper method
mag.getId =function(instanceId){
  return mag.utils.items.getItemVal(instanceId);
};

mag.prop = function(store) {
  var prop = function() {
    if (arguments.length) store = arguments[0];
    return store;
  };

  prop.toJSON = function() {
    return store;
  };

  return prop;
};

mag.withProp = function(prop, withAttrCallback) {
  return function(e) {
    e = e || event;
    var currentTarget = e.currentTarget || this;
    withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop))
  }
}

})(mag, window || global || this, document);
<commit_msg>Update mag.addons.0.2.js<commit_after>/*
Mag.JS AddOns v0.21.9
(c) Michael Glazer 2016
https://github.com/magnumjs/mag.js
Requires: MagJS (core) Addons: Ajax , Router
*/

;
(function(mag, window, document, undefined) {

  'use strict';

  // helper
  mag.noop = function() {}

  //UTILITY
  // mag.utils.copy - now in core
  // mag.utils.merge - now in core

  mag.copy = mag.utils.copy
  mag.merge = mag.utils.merge

  /*
  controller:function(props)
    // if props has a property 'isVisible' when true will display entire module on before updates
    mag.show(this,'isVisible')
  }
  http://jsbin.com/fegizubime/edit?html,js,output
  */

  // show hide

  mag.show = function(context, conditionName) {
    var ctype = typeof context;
    if (ctype !== 'object') {
      var obj = {
        _config: function(node) {
          node.style.display = context ? 'block' : 'none'
        }
      }
      if (typeof conditionName == 'object') {
        mag.merge(conditionName, obj)
      }
      return obj
    } else if (ctype == 'object') {
      context.willload = function(event, node, inprops) {
        node.style.display = 'block'
      }
    } else {
      context.willupdate = function(event, node, inprops) {
        node.style.display = inprops[conditionName] ? 'block' : 'none'
      }
    }
  }

  // promises

  /*
  var d = mag.deferred()

  d.promise.then(function() {
    console.log('success', arguments)
  }, function() {
    console.log('failure', arguments)
  })
  d.reject({
    things: false
  })
  d.resolve({
    things: []
  })
  */

mag.deferred = function() {
  var Deferred = {}
  Deferred.promise = new Promise(function(resolve, reject) {
    Deferred.resolve = resolve
    Deferred.reject = reject
  })
  return Deferred
}

mag.when = function(arrayOfPromises, callback) {
  return Promise.all(arrayOfPromises).then(callback)
}

//TODO: add jsonp support

mag.request = function(options) {
  var deferred = mag.deferred();
  if (options.initialValue) {
    deferred.promise.initialValue = options.initialValue
  }
  //Uid:
  var key = JSON.stringify(options)
    //Cache:
  if (options.cache) {
    var cache = mag.cache(key)
    if (cache) {
      deferred.resolve(cache)
      return deferred.promise
    }
  }

  //In queue:
  if (mag.request.queue[key]) {
    return mag.request.queue[key]
  }
  //Add to queue
  mag.request.queue[key] = deferred.promise;

  var client = new XMLHttpRequest();
  var method = (options.method || 'GET').toUpperCase();
  var data = method === "GET" || !options.data ? "" : options.data

  client.onload = function(e) {
    var ct = client.getResponseHeader("content-type") || "";
    var data = e.target.responseText;
    if (ct.indexOf('json') > -1) {
      data = JSON.parse(data)
    }
    if (options.cache) {
      mag.cache(key, data, options.cacheTime, options.cacheType)
    }
    delete mag.request.queue[key];
    var headers = client.getAllResponseHeaders();
    deferred.resolve(data, headers);
  }

  client.onerror = function(e) {
    deferred.reject(e)
  };

  client.open(method, options.url);
    //Headers:
  if(options.headers){
    for(var i=0;i<options.headers.length;i++){
    	var header = options.headers[i]
      for(var k in header){
    	  client.setRequestHeader(k, header[k]);
      }
    }
  }
  client.send(data);

  return deferred.promise
}
mag.request.queue = {}

mag.cache = function(key, data, cacheTime, storageType) {
   var stype = window[storageType || 'sessionStorage']

  if (arguments.length == 1) {

    if (mag.cache.data[key]) {
      return mag.cache.data[key].data;
    } else {
      // check storage
      var item = stype.getItem(key)
      if (item) {
        mag.cache.data[key] = JSON.parse(item)
        return mag.cache.data[key].data
      }
      else return 0;
    }
  }

  if (mag.cache.data[key] && mag.cache.data[key].id) clearTimeout(mag.cache.data[key].id)

  var intervalID = setTimeout(function(key) {
    stype.removeItem(key);
    delete mag.cache.data[key]
  }.bind({}, key), cacheTime || 1000 * 60 * 10); //10 minutes

  mag.cache.data[key] = {
    id: intervalID,
    data: data
  }

  stype.setItem(key, JSON.stringify(mag.cache.data[key]))
}
mag.cache.data = {}

  // goes with mag.request for json ajax requests
  /*
  will show and hide all ''.loader' elements in transition
  */
  mag.requestWithFeedback = function(args) {
    var key = JSON.stringify(args)
    if (!mag.requestWithFeedback.cache[key]) {

      var loaders = document.querySelectorAll(".loader")

      //show icons
      for (var i = 0, loader; loader = loaders[i]; i++) loader.style.display = "block"

      var expire = function(data) {
        delete mag.requestWithFeedback.cache[key]

        if (Object.keys(mag.requestWithFeedback.cache).length == 0) {
          //hide icons
          for (var i = 0, loader; loader = loaders[i]; i++) loader.style.display = "none"
        }
        return data
      }
      mag.requestWithFeedback.cache[key] = mag.request(args)
      mag.requestWithFeedback.cache[key].then(expire, function(error) {
        expire(error)
        throw error
      })
    }
    return mag.requestWithFeedback.cache[key]
  }
  mag.requestWithFeedback.cache = {}

  // disable add to config
  // http://jsbin.com/zepacabile/edit?js,output
  // define condition func
  // this.show = mag.prop(false);

  //define context
  //   this.input = mag.disable(this.show)
  // OR mag.disable(this.show, this.input={})
  //TODO: change to mag.ui.disable
 mag.disable = function(condition, obj) {

  // add or merge to config if not exists
  var orig = obj && obj._config ? obj._config : function() {};

  var tmp = {
    _config: function(n) {
      orig.apply(this, arguments);
      if (condition()) n.setAttribute('disabled', 'disabled');
      else n.removeAttribute('disabled');
    }
  }
  if (obj) {
    mag.merge(obj, tmp);
  }
  return tmp;

}

  // TODO: change to mag.find
  // find a MagJS element Matcher
  mag.find = function(parentRootId, selector) {
    var parent = document.getElementById(parentRootId);
    return mag.fill.find(parent, selector)
  }

  // mag.addons.toMenu(['one', 'two', 'three'], state.selected())
  // http://jsbin.com/mapuwojumu/3/edit?js,output
  //TODO change to mag.ui.menu
  mag.toMenu = function(maps, selected) {
    return maps.map(function(v, k) {
      return {
        _text: v,
        _value: k,
        _selected: selected === k || selected === v ? true : null
      }
    })
  }

  /*
  module library creation with single global namespace / package names
  (function(namespace) {

    var mod = {
      view: function(state, props) {
      }
    }

    namespace.CommentBox = mod;

  })(mag.namespace('mglazer.mods.comments'));
  */
  mag.namespace = function(ns, obj) {
    var levels = ns.split('.'),
      first = levels.shift();
    obj = obj || this; //if no object argument supplied declare a global property
    obj[first] = obj[first] || {}; // initialize the "level"
    if (levels.length) { // recursion condition
      return mag.namespace(levels.join('.'), obj[first]);
    }
    return obj[first]; // return a reference to the top level object
  }

  //ROUTER:

  mag.route = (function(window) {

    'use strict';

    var routes = [];

    function addRoute(route, handler) {

      routes.push({
        parts: route.split('/'),
        handler: handler
      });
    }

    function load(route) {
      window.location.hash = route;
    }

    function start() {

      var path = window.location.hash.substr(1),
        parts = path.split('/'),
        partsLength = parts.length;

      for (var i = 0; i < routes.length; i++) {
        var route = routes[i];
        if (route.parts.length === partsLength) {
          var params = [];
          for (var j = 0; j < partsLength; j++) {
            if (route.parts[j].substr(0, 1) === ':') {
              params.push(parts[j]);
            } else if (route.parts[j] !== parts[j]) {
              break;
            }
          }
          if (j === partsLength) {
            route.handler.apply(undefined, params);
            return;
          }
        }
      }
    }

    window.onhashchange = start;

    return {
      addRoute: addRoute,
      load: load,
      start: start
    };

  }(window));

  //PLUGINS!
  // hookins

function forEach(obj, fn) {
  var keys = Object.keys(obj);
  for (var i = 0, l = keys.length; i < l; ++i) {
    var key = keys[i];
    fn(key, obj[key]);
  }
}

mag.hookin('attributes', 'key', function(data) {
  // remove system key from being added to attributes in html
  data.value = null
});

function camelDash (val) {
	return val.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

mag.hookin('attributes', 'style', function(data) {

  //convert from object
  if (typeof data.value === 'object') {
    // get current styles not overwrite existing?

    var ostyle = data.node.getAttribute('style') || '';

    // make sure not already in styles
    var nstyle = ''
    forEach(data.value, function(key, value) {
     nstyle += camelDash(key) + ':' + (!isNaN(value) ? (value + "px") : value) + ';';
    });

    if(ostyle && ~ostyle.indexOf(nstyle)) data.value=ostyle;
    else data.value = ostyle+nstyle;

  }
});

 // _className plugin example
  mag.hookin('attributes', 'className', function(data) {
    data.key = 'class';

    var newClass = data.value
    var origClass = data.node.classList + ''

    if (typeof data.value == 'string') {
      newClass = data.value.split(' ')
    } else if (typeof data.value == 'object') {
      for (var k in newClass) {
        data.node.classList.toggle(k, newClass[k])
      }
      data.value = data.node.classList + ''
      return
    }

    data.value = data.node.classList + ''

    for (var k in newClass) {
      var cls = newClass[k]
      if (cls.trim() && data.node.classList.length > 0 && !data.node.classList.contains(cls.trim())) {
        data.value = data.node.classList + ' ' + cls

      } else if (cls.trim() && data.node.classList.length == 0) {
        data.value += cls + ' '
      }
    }

    if(data.value.trim() !== origClass) {
      data.change = 1;
    }
    data.value = data.value.trim()
  })

  //Values hookin:
mag.hookin('values', '*', function(data) {
  var dtype = typeof data.value

  if (data.value == null) {

  } else
  // allow function to return values
  if (dtype === 'function' && data.value.toJSON) {
    data.change = 1
    data.value = data.value()
  } else
  // Allow for promises to be resolved
  if (dtype == 'object' && typeof data.value.then == 'function') {
    var mid = mag.utils.items.getItem(mag.fill.id);

    data.value.then(function(newData) {
      mag.mod.getState(mid)[data.key] = newData;
    })

    if (data.value.initialValue) {
      data.change = 1
      data.value = data.value.initialValue
    }
  }
})

//GetId helper method
mag.getId =function(instanceId){
  return mag.utils.items.getItemVal(instanceId);
};

mag.prop = function(store) {
  var prop = function() {
    if (arguments.length) store = arguments[0];
    return store;
  };

  prop.toJSON = function() {
    return store;
  };

  return prop;
};

mag.withProp = function(prop, withAttrCallback) {
  return function(e) {
    e = e || event;
    var currentTarget = e.currentTarget || this;
    withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop))
  }
}

})(mag, window || global || this, document);
<|endoftext|>


<commit_before>import { BASIC_MATERIAL, MAX_DIRECTIONAL } from '../constants';
import { color } from '../utils';
import Material from '../core/material';
import Texture from '../core/texture';
import { UBO, DIRECTIONAL, FOG } from '../renderer/chunks';

class Basic extends Material {

    constructor(props = {}) {
        super();
        this.type = BASIC_MATERIAL;

        this.map = new Texture();
        if (props.map) {
            this.map.fromImage(props.map);
        }

        Object.assign(this.uniforms, {
            color: {
                type: 'vec3',
                value: color.convert((props && props.color) || 0xffffff),
            },
            map: {
                type: 'sampler2D',
                value: this.map.texture,
            },
        });

        this.vertex = `#version 300 es
${UBO.scene()}
${UBO.model()}

in vec3 a_position;
in vec3 a_normal;
in vec2 a_uv;

out vec2 v_uv;
out vec3 v_normal;

void main() {
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0);
    v_uv = a_uv;
    v_normal = normalize(mat3(normalMatrix) * a_normal);
}
`;

        this.fragment = `#version 300 es

#define MAX_DIRECTIONAL ${MAX_DIRECTIONAL}

precision highp float;
precision highp int;

${UBO.scene()}
${UBO.model()}

${DIRECTIONAL.before()}

uniform vec3 color;
uniform sampler2D map;

in vec2 v_uv;
in vec3 v_normal;

out vec4 outColor;

float whenGreaterThan(float x, float y) {
    return max(sign(x - y), 0.0);
}

void main() {
    vec4 base = vec4(0.0, 0.0, 0.0, 1.0);
    base += texture(map, v_uv);
    base += vec4(color, 1.0);

    ${DIRECTIONAL.main()}
    // POINT light
    // SPOTLIGHTS
    ${FOG.linear()}

    outColor = base;
}`;
    }

}

export default Basic;
<commit_msg>basic material doesn't include lights<commit_after>import { BASIC_MATERIAL, MAX_DIRECTIONAL } from '../constants';
import { color } from '../utils';
import Material from '../core/material';
import Texture from '../core/texture';
import { UBO, FOG } from '../renderer/chunks';

class Basic extends Material {

    constructor(props = {}) {
        super();
        this.type = BASIC_MATERIAL;

        this.map = new Texture();
        if (props.map) {
            this.map.fromImage(props.map);
        }

        Object.assign(this.uniforms, {
            color: {
                type: 'vec3',
                value: color.convert((props && props.color) || 0xffffff),
            },
            map: {
                type: 'sampler2D',
                value: this.map.texture,
            },
        });

        this.vertex = `#version 300 es
${UBO.scene()}
${UBO.model()}

in vec3 a_position;
in vec3 a_normal;
in vec2 a_uv;

out vec2 v_uv;
out vec3 v_normal;

void main() {
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position, 1.0);
    v_uv = a_uv;
    v_normal = normalize(mat3(normalMatrix) * a_normal);
}
`;

        this.fragment = `#version 300 es

#define MAX_DIRECTIONAL ${MAX_DIRECTIONAL}

precision highp float;
precision highp int;

${UBO.scene()}
${UBO.model()}

uniform vec3 color;
uniform sampler2D map;

in vec2 v_uv;
in vec3 v_normal;

out vec4 outColor;

float whenGreaterThan(float x, float y) {
    return max(sign(x - y), 0.0);
}

void main() {
    vec4 base = vec4(0.0, 0.0, 0.0, 1.0);
    base += texture(map, v_uv);
    base += vec4(color, 1.0);

    ${FOG.linear()}

    outColor = base;
}`;
    }

}

export default Basic;
<|endoftext|>


<commit_before>macro async {
  case {
    $_ function $name:ident $params { $body ... }
  } => {
    letstx $ctx = [makeIdent('ctx', #{$_})];

    return #{
      macro await {
        rule { $expression:expr ; $after $[...] } => {
            return $expression.then(function () {
              $after $[...]
            });
        }
      }
      let (var) = macro {
        rule { $identifier:ident = await $expression:expr ; $after $[...] } => {
          return $expression.then(function ($identifier) {
            $after $[...]
          })
        }

        rule { $id } => { var $id }
      }

      let (=) = macro {
        rule infix { $identifier | await $expression:expr ; $after $[...] } => {
          return $expression.then(function (value) {
            $identifier = value;
            $after $[...]
          })
        }

        rule infix { $left:expr | $right:expr } => { $left = $right }
      }

      macro try {
        rule { $tryBody catch $catchParams $catchBody finally $finallyBody } => {
          return new Promise(function (resolve) {
            resolve(this);
          })
          .then(function () $tryBody)
          .catch(function $catchParams $catchBody)
          .finally(function () $finallyBody);
        }

        rule { $tryBody catch $catchParams $catchBody } => {
          return new Promise(function (resolve) {
            resolve(this);
          }).then(function () $tryBody).catch(function $catchParams $catchBody);
        }
      }

      function $name $params {
        var $ctx = this;
        let (this) = macro {
          rule {} => { $ctx }
        }

        return new Promise(function (resolve) {
          resolve(this);
        }).then(function () {
          $body ...
        });
      }
    };
  }
}
<commit_msg>Hoist var declaration to parent scope<commit_after>macro async {
  case {
    $_ function $name:ident $params { $body ... }
  } => {
    letstx $ctx = [makeIdent('ctx', #{$_})];

    return #{
      macro try {
        rule { $tryBody catch $catchParams $catchBody finally $finallyBody } => {
          return new Promise(function (resolve) {
            resolve(this);
          })
          .then(function () $tryBody)
          .catch(function $catchParams $catchBody)
          .finally(function () $finallyBody);
        }

        rule { $tryBody catch $catchParams $catchBody } => {
          return new Promise(function (resolve) {
            resolve(this);
          }).then(function () $tryBody).catch(function $catchParams $catchBody);
        }
      }

      macro await {
        rule { $expression:expr ; $after $[...] } => {
            return $expression.then(function () {
              $after $[...]
            });
        }
      }
      let (var) = macro {
        rule { $identifier:ident = await $expression:expr ; $after $[...] } => {
          var $identifier;
          return $expression.then(function (value) {
            $identifier = value;
            $after $[...]
          })
        }

        rule { $id } => { var $id }
      }

      let (=) = macro {
        rule infix { $identifier | await $expression:expr ; $after $[...] } => {
          return $expression.then(function (value) {
            $identifier = value;
            $after $[...]
          })
        }

        rule infix { $left:expr | $right:expr } => { $left = $right }
      }

      function $name $params {
        var $ctx = this;
        let (this) = macro {
          rule {} => { $ctx }
        }

        return new Promise(function (resolve) {
          resolve(this);
        }).then(function () {
          $body ...
        });
      }
    };
  }
}
<|endoftext|>


<commit_before>goog.provide('ol.asserts');

goog.require('ol');
goog.require('ol.AssertionError');

/**
 * @param {*} assertion Assertion we expected to be truthy.
 * @param {number} errorCode Error code.
 */
ol.asserts.assert = function(assertion, errorCode) {
  if (!assertion) {
    throw new ol.AssertionError(errorCode);
  }
};
<commit_msg>Remove unused goog.require<commit_after>goog.provide('ol.asserts');

goog.require('ol.AssertionError');

/**
 * @param {*} assertion Assertion we expected to be truthy.
 * @param {number} errorCode Error code.
 */
ol.asserts.assert = function(assertion, errorCode) {
  if (!assertion) {
    throw new ol.AssertionError(errorCode);
  }
};
<|endoftext|>


<commit_before>/**
 * @module ol/control
 */

export {default as Attribution} from './control/Attribution.js';
export {default as Control} from './control/Control.js';
export {default as FullScreen} from './control/FullScreen.js';
export {default as OverviewMap} from './control/OverviewMap.js';
export {default as Rotate} from './control/Rotate.js';
export {default as ScaleLine} from './control/ScaleLine.js';
export {default as Zoom} from './control/Zoom.js';
export {default as ZoomSlider} from './control/ZoomSlider.js';
export {default as ZoomToExtent} from './control/ZoomToExtent.js';
export {defaults} from './control/util.js';
<commit_msg>Re-export MousePosition from ol/control<commit_after>/**
 * @module ol/control
 */

export {default as Attribution} from './control/Attribution.js';
export {default as Control} from './control/Control.js';
export {default as FullScreen} from './control/FullScreen.js';
export {default as MousePosition} from './control/MousePosition.js';
export {default as OverviewMap} from './control/OverviewMap.js';
export {default as Rotate} from './control/Rotate.js';
export {default as ScaleLine} from './control/ScaleLine.js';
export {default as Zoom} from './control/Zoom.js';
export {default as ZoomSlider} from './control/ZoomSlider.js';
export {default as ZoomToExtent} from './control/ZoomToExtent.js';
export {defaults} from './control/util.js';
<|endoftext|>


<commit_before>
goog.provide('ol.Kinetic');

goog.require('goog.array');
goog.require('ol.Pixel');
goog.require('ol.animation');

/**
 * @typedef {{x: number,
 *            y: number,
 *            t: number}}
 */
ol.KineticPoint;

/**
 * @constructor
 * @param {number} decay Rate of decay (must be negative).
 * @param {number} v_min Minimum velocity (pixels/millisecond).
 * @param {number} delay Delay to consider to calculate the kinetic
 *     initial values (milliseconds).
 */
ol.Kinetic = function(decay, v_min, delay) {

  /**
   * @private
   * @type {number}
   */
  this.decay_ = decay;

  /**
   * @private
   * @type {number}
   */
  this.v_min_ = v_min;

  /**
   * @private
   * @type {number}
   */
  this.delay_ = delay;

  /**
   * @private
   * @type {Array.<ol.KineticPoint>}
   */
  this.points_ = [];

  /**
   * @private
   * @type {number}
   */
  this.angle_ = 0;

  /**
   * @private
   * @type {number}
   */
  this.v_0_ = 0;
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 */
ol.Kinetic.prototype.begin = function(browserEvent) {
  this.points_.length = 0;
  this.angle_ = 0;
  this.v_0_ = 0;
  this.update(browserEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 */
ol.Kinetic.prototype.update = function(browserEvent) {
  this.points_.push({
    x: browserEvent.clientX,
    y: browserEvent.clientY,
    t: goog.now()
  });
};

/**
 * @return {boolean} Whether we should do kinetic animation.
 */
ol.Kinetic.prototype.end = function() {
  var now = goog.now();
  var lastIndex = this.points_.length - 1;
  var firstIndex = lastIndex - 1;
  while (firstIndex >= 0 && this.points_[firstIndex].t > now - this.delay_) {
    firstIndex--;
  }
  if (firstIndex >= 0) {
    var first = this.points_[firstIndex];
    var last = this.points_[lastIndex];
    var dx = last.x - first.x;
    var dy = last.y - first.y;
    this.angle_ = Math.atan2(dy, dx);
    this.v_0_ = Math.sqrt(dx * dx + dy * dy) / (last.t - first.t);
    return this.v_0_ > this.v_min_;
  }
  return false;
};

/**
 * @param {ol.Coordinate} source Source coordinate for the animation.
 * @return {ol.PreRenderFunction} Pre-render function for kinetic animation.
 */
ol.Kinetic.prototype.createPanFrom = function(source) {
  var decay = this.decay_;
  var v_0 = this.v_0_;
  var v_min = this.v_min_;
  var duration = this.getDuration();
  var easingFunction = function(t) {
    return v_0 * (Math.exp((decay * t) * duration) - 1) / (v_min - v_0);
  };
  return ol.animation.createPanFrom({
    source: source,
    duration: duration,
    easing: easingFunction
  });
};

/**
 * @return {number} Duration of animation (milliseconds).
 */
ol.Kinetic.prototype.getDuration = function() {
  return Math.log(this.v_min_ / this.v_0_) / this.decay_;
};

/**
 * @return {number} Total distance travelled (pixels).
 */
ol.Kinetic.prototype.getDistance = function() {
  return (this.v_min_ - this.v_0_) / this.decay_;
};

/**
 * @return {number} Angle of the kinetic panning animation (radians).
 */
ol.Kinetic.prototype.getAngle = function() {
  return this.angle_;
};
<commit_msg>Renaming to be more consistent with ol3 style<commit_after>
goog.provide('ol.Kinetic');

goog.require('goog.array');
goog.require('ol.Pixel');
goog.require('ol.animation');

/**
 * @typedef {{x: number,
 *            y: number,
 *            t: number}}
 */
ol.KineticPoint;

/**
 * @constructor
 * @param {number} decay Rate of decay (must be negative).
 * @param {number} minVelocity Minimum velocity (pixels/millisecond).
 * @param {number} delay Delay to consider to calculate the kinetic
 *     initial values (milliseconds).
 */
ol.Kinetic = function(decay, minVelocity, delay) {

  /**
   * @private
   * @type {number}
   */
  this.decay_ = decay;

  /**
   * @private
   * @type {number}
   */
  this.minVelocity_ = minVelocity;

  /**
   * @private
   * @type {number}
   */
  this.delay_ = delay;

  /**
   * @private
   * @type {Array.<ol.KineticPoint>}
   */
  this.points_ = [];

  /**
   * @private
   * @type {number}
   */
  this.angle_ = 0;

  /**
   * @private
   * @type {number}
   */
  this.initialVelocity_ = 0;
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 */
ol.Kinetic.prototype.begin = function(browserEvent) {
  this.points_.length = 0;
  this.angle_ = 0;
  this.initialVelocity_ = 0;
  this.update(browserEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 */
ol.Kinetic.prototype.update = function(browserEvent) {
  this.points_.push({
    x: browserEvent.clientX,
    y: browserEvent.clientY,
    t: goog.now()
  });
};

/**
 * @return {boolean} Whether we should do kinetic animation.
 */
ol.Kinetic.prototype.end = function() {
  var now = goog.now();
  var lastIndex = this.points_.length - 1;
  var firstIndex = lastIndex - 1;
  while (firstIndex >= 0 && this.points_[firstIndex].t > now - this.delay_) {
    firstIndex--;
  }
  if (firstIndex >= 0) {
    var first = this.points_[firstIndex];
    var last = this.points_[lastIndex];
    var dx = last.x - first.x;
    var dy = last.y - first.y;
    this.angle_ = Math.atan2(dy, dx);
    this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / (last.t - first.t);
    return this.initialVelocity_ > this.minVelocity_;
  }
  return false;
};

/**
 * @param {ol.Coordinate} source Source coordinate for the animation.
 * @return {ol.PreRenderFunction} Pre-render function for kinetic animation.
 */
ol.Kinetic.prototype.createPanFrom = function(source) {
  var decay = this.decay_;
  var initialVelocity = this.initialVelocity_;
  var minVelocity = this.minVelocity_;
  var duration = this.getDuration();
  var easingFunction = function(t) {
    return initialVelocity * (Math.exp((decay * t) * duration) - 1) /
        (minVelocity - initialVelocity);
  };
  return ol.animation.createPanFrom({
    source: source,
    duration: duration,
    easing: easingFunction
  });
};

/**
 * @return {number} Duration of animation (milliseconds).
 */
ol.Kinetic.prototype.getDuration = function() {
  return Math.log(this.minVelocity_ / this.initialVelocity_) / this.decay_;
};

/**
 * @return {number} Total distance travelled (pixels).
 */
ol.Kinetic.prototype.getDistance = function() {
  return (this.minVelocity_ - this.initialVelocity_) / this.decay_;
};

/**
 * @return {number} Angle of the kinetic panning animation (radians).
 */
ol.Kinetic.prototype.getAngle = function() {
  return this.angle_;
};
<|endoftext|>


<commit_before>goog.provide('ol.Overlay');
goog.provide('ol.OverlayPositioning');
goog.provide('ol.OverlayProperty');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.style');
goog.require('ol.Coordinate');
goog.require('ol.Map');
goog.require('ol.MapEventType');
goog.require('ol.Object');

/**
 * @enum {string}
 */
ol.OverlayProperty = {
  ELEMENT: 'element',
  MAP: 'map',
  OFFSET: 'offset',
  POSITION: 'position',
  POSITIONING: 'positioning'
};

/**
 * Overlay position: `'bottom-left'`, `'bottom-center'`,  `'bottom-right'`,
 * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`,
 * `'top-center'`, `'top-right'`
 * @enum {string}
 * @api stable
 */
ol.OverlayPositioning = {
  BOTTOM_LEFT: 'bottom-left',
  BOTTOM_CENTER: 'bottom-center',
  BOTTOM_RIGHT: 'bottom-right',
  CENTER_LEFT: 'center-left',
  CENTER_CENTER: 'center-center',
  CENTER_RIGHT: 'center-right',
  TOP_LEFT: 'top-left',
  TOP_CENTER: 'top-center',
  TOP_RIGHT: 'top-right'
};

/**
 * @classdesc
 * Like {@link ol.control.Control}, Overlays are visible widgets.
 * Unlike Controls, they are not in a fixed position on the screen, but are tied
 * to a geographical coordinate, so panning the map will move an Overlay but not
 * a Control.
 *
 * Example:
 *
 *     var popup = new ol.Overlay({
 *       element: document.getElementById('popup')
 *     });
 *     popup.setPosition(coordinate);
 *     map.addOverlay(popup);
 *
 * @constructor
 * @extends {ol.Object}
 * @param {olx.OverlayOptions} options Overlay options.
 * @api stable
 */
ol.Overlay = function(options) {

  goog.base(this);

  /**
   * @private
   * @type {boolean}
   */
  this.insertFirst_ = goog.isDef(options.insertFirst) ?
      options.insertFirst : true;

  /**
   * @private
   * @type {boolean}
   */
  this.stopEvent_ = goog.isDef(options.stopEvent) ? options.stopEvent : true;

  /**
   * @private
   * @type {Element}
   */
  this.element_ = goog.dom.createElement(goog.dom.TagName.DIV);
  this.element_.style.position = 'absolute';

  /**
   * @private
   * @type {{bottom_: string,
   *         left_: string,
   *         right_: string,
   *         top_: string,
   *         visible: boolean}}
   */
  this.rendered_ = {
    bottom_: '',
    left_: '',
    right_: '',
    top_: '',
    visible: true
  };

  /**
   * @private
   * @type {goog.events.Key}
   */
  this.mapPostrenderListenerKey_ = null;

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT),
      this.handleElementChanged, false, this);

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP),
      this.handleMapChanged, false, this);

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET),
      this.handleOffsetChanged, false, this);

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION),
      this.handlePositionChanged, false, this);

  goog.events.listen(
      this,
      ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING),
      this.handlePositioningChanged, false, this);

  if (goog.isDef(options.element)) {
    this.setElement(options.element);
  }

  this.setOffset(goog.isDef(options.offset) ? options.offset : [0, 0]);

  this.setPositioning(goog.isDef(options.positioning) ?
      /** @type {ol.OverlayPositioning} */ (options.positioning) :
      ol.OverlayPositioning.TOP_LEFT);

  if (goog.isDef(options.position)) {
    this.setPosition(options.position);
  }

};
goog.inherits(ol.Overlay, ol.Object);

/**
 * Get the DOM element of this overlay.
 * @return {Element|undefined} The Element containing the overlay.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getElement = function() {
  return /** @type {Element|undefined} */ (
      this.get(ol.OverlayProperty.ELEMENT));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getElement',
    ol.Overlay.prototype.getElement);

/**
 * Get the map associated with this overlay.
 * @return {ol.Map|undefined} The map that the overlay is part of.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getMap = function() {
  return /** @type {ol.Map|undefined} */ (
      this.get(ol.OverlayProperty.MAP));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getMap',
    ol.Overlay.prototype.getMap);

/**
 * Get the offset of this overlay.
 * @return {Array.<number>} The offset.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getOffset = function() {
  return /** @type {Array.<number>} */ (
      this.get(ol.OverlayProperty.OFFSET));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getOffset',
    ol.Overlay.prototype.getOffset);

/**
 * Get the current position of this overlay.
 * @return {ol.Coordinate|undefined} The spatial point that the overlay is
 *     anchored at.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getPosition = function() {
  return /** @type {ol.Coordinate|undefined} */ (
      this.get(ol.OverlayProperty.POSITION));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getPosition',
    ol.Overlay.prototype.getPosition);

/**
 * Get the current positioning of this overlay.
 * @return {ol.OverlayPositioning} How the overlay is positioned
 *     relative to its point on the map.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getPositioning = function() {
  return /** @type {ol.OverlayPositioning} */ (
      this.get(ol.OverlayProperty.POSITIONING));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getPositioning',
    ol.Overlay.prototype.getPositioning);

/**
 * @protected
 */
ol.Overlay.prototype.handleElementChanged = function() {
  goog.dom.removeChildren(this.element_);
  var element = this.getElement();
  if (goog.isDefAndNotNull(element)) {
    goog.dom.append(/** @type {!Node} */ (this.element_), element);
  }
};

/**
 * @protected
 */
ol.Overlay.prototype.handleMapChanged = function() {
  if (!goog.isNull(this.mapPostrenderListenerKey_)) {
    goog.dom.removeNode(this.element_);
    goog.events.unlistenByKey(this.mapPostrenderListenerKey_);
    this.mapPostrenderListenerKey_ = null;
  }
  var map = this.getMap();
  if (goog.isDefAndNotNull(map)) {
    this.mapPostrenderListenerKey_ = goog.events.listen(map,
        ol.MapEventType.POSTRENDER, this.handleMapPostrender, false, this);
    this.updatePixelPosition_();
    var container = this.stopEvent_ ?
        map.getOverlayContainerStopEvent() : map.getOverlayContainer();
    if (this.insertFirst_) {
      goog.dom.insertChildAt(/** @type {!Element} */ (
          container), this.element_, 0);
    } else {
      goog.dom.append(/** @type {!Node} */ (container), this.element_);
    }
  }
};

/**
 * @protected
 */
ol.Overlay.prototype.handleMapPostrender = function() {
  this.updatePixelPosition_();
};

/**
 * @protected
 */
ol.Overlay.prototype.handleOffsetChanged = function() {
  this.updatePixelPosition_();
};

/**
 * @protected
 */
ol.Overlay.prototype.handlePositionChanged = function() {
  this.updatePixelPosition_();
};

/**
 * @protected
 */
ol.Overlay.prototype.handlePositioningChanged = function() {
  this.updatePixelPosition_();
};

/**
 * Set the DOM element to be associated with this overlay.
 * @param {Element|undefined} element The Element containing the overlay.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setElement = function(element) {
  this.set(ol.OverlayProperty.ELEMENT, element);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setElement',
    ol.Overlay.prototype.setElement);

/**
 * Set the map to be associated with this overlay.
 * @param {ol.Map|undefined} map The map that the overlay is part of.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setMap = function(map) {
  this.set(ol.OverlayProperty.MAP, map);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setMap',
    ol.Overlay.prototype.setMap);

/**
 * Set the offset for this overlay.
 * @param {Array.<number>} offset Offset.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setOffset = function(offset) {
  this.set(ol.OverlayProperty.OFFSET, offset);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setOffset',
    ol.Overlay.prototype.setOffset);

/**
 * Set the position for this overlay.
 * @param {ol.Coordinate|undefined} position The spatial point that the overlay
 *     is anchored at.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setPosition = function(position) {
  this.set(ol.OverlayProperty.POSITION, position);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setPosition',
    ol.Overlay.prototype.setPosition);

/**
 * Set the positioning for this overlay.
 * @param {ol.OverlayPositioning} positioning how the overlay is
 *     positioned relative to its point on the map.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setPositioning = function(positioning) {
  this.set(ol.OverlayProperty.POSITIONING, positioning);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setPositioning',
    ol.Overlay.prototype.setPositioning);

/**
 * @private
 */
ol.Overlay.prototype.updatePixelPosition_ = function() {

  var map = this.getMap();
  var position = this.getPosition();
  if (!goog.isDef(map) || !map.isRendered() || !goog.isDef(position)) {
    if (this.rendered_.visible) {
      goog.style.setElementShown(this.element_, false);
      this.rendered_.visible = false;
    }
    return;
  }

  var pixel = map.getPixelFromCoordinate(position);
  goog.asserts.assert(!goog.isNull(pixel));
  var mapSize = map.getSize();
  goog.asserts.assert(goog.isDef(mapSize));
  var style = this.element_.style;
  var offset = this.getOffset();
  goog.asserts.assert(goog.isArray(offset));
  var positioning = this.getPositioning();
  goog.asserts.assert(goog.isDef(positioning));

  if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT ||
      positioning == ol.OverlayPositioning.CENTER_RIGHT ||
      positioning == ol.OverlayPositioning.TOP_RIGHT) {
    if (this.rendered_.left_ !== '') {
      this.rendered_.left_ = style.left = '';
    }
    var right = Math.round(mapSize[0] - pixel[0]) + 'px';
    if (this.rendered_.right_ != right) {
      this.rendered_.right_ = style.right = right;
    }
  } else {
    if (this.rendered_.right_ !== '') {
      this.rendered_.right_ = style.right = '';
    }
    var offsetX = -offset[0];
    if (positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
        positioning == ol.OverlayPositioning.CENTER_CENTER ||
        positioning == ol.OverlayPositioning.TOP_CENTER) {
      offsetX += goog.style.getSize(this.element_).width / 2;
    }
    var left = Math.round(pixel[0] - offsetX) + 'px';
    if (this.rendered_.left_ != left) {
      this.rendered_.left_ = style.left = left;
    }
  }
  if (positioning == ol.OverlayPositioning.BOTTOM_LEFT ||
      positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
      positioning == ol.OverlayPositioning.BOTTOM_RIGHT) {
    if (this.rendered_.top_ !== '') {
      this.rendered_.top_ = style.top = '';
    }
    var bottom = Math.round(mapSize[1] - pixel[1]) + 'px';
    if (this.rendered_.bottom_ != bottom) {
      this.rendered_.bottom_ = style.bottom = bottom;
    }
  } else {
    if (this.rendered_.bottom_ !== '') {
      this.rendered_.bottom_ = style.bottom = '';
    }
    var offsetY = -offset[1];
    if (positioning == ol.OverlayPositioning.CENTER_LEFT ||
        positioning == ol.OverlayPositioning.CENTER_CENTER ||
        positioning == ol.OverlayPositioning.CENTER_RIGHT) {
      offsetY += goog.style.getSize(this.element_).height / 2;
    }
    var top = Math.round(pixel[1] - offsetY) + 'px';
    if (this.rendered_.top_ != top) {
      this.rendered_.top_ = style.top = top;
    }
  }

  if (!this.rendered_.visible) {
    goog.style.setElementShown(this.element_, true);
    this.rendered_.visible = true;
  }

};
<commit_msg>Making ol.Overlay accept offset values if positioning right or bottom<commit_after>goog.provide('ol.Overlay');
goog.provide('ol.OverlayPositioning');
goog.provide('ol.OverlayProperty');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.style');
goog.require('ol.Coordinate');
goog.require('ol.Map');
goog.require('ol.MapEventType');
goog.require('ol.Object');

/**
 * @enum {string}
 */
ol.OverlayProperty = {
  ELEMENT: 'element',
  MAP: 'map',
  OFFSET: 'offset',
  POSITION: 'position',
  POSITIONING: 'positioning'
};

/**
 * Overlay position: `'bottom-left'`, `'bottom-center'`,  `'bottom-right'`,
 * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`,
 * `'top-center'`, `'top-right'`
 * @enum {string}
 * @api stable
 */
ol.OverlayPositioning = {
  BOTTOM_LEFT: 'bottom-left',
  BOTTOM_CENTER: 'bottom-center',
  BOTTOM_RIGHT: 'bottom-right',
  CENTER_LEFT: 'center-left',
  CENTER_CENTER: 'center-center',
  CENTER_RIGHT: 'center-right',
  TOP_LEFT: 'top-left',
  TOP_CENTER: 'top-center',
  TOP_RIGHT: 'top-right'
};

/**
 * @classdesc
 * Like {@link ol.control.Control}, Overlays are visible widgets.
 * Unlike Controls, they are not in a fixed position on the screen, but are tied
 * to a geographical coordinate, so panning the map will move an Overlay but not
 * a Control.
 *
 * Example:
 *
 *     var popup = new ol.Overlay({
 *       element: document.getElementById('popup')
 *     });
 *     popup.setPosition(coordinate);
 *     map.addOverlay(popup);
 *
 * @constructor
 * @extends {ol.Object}
 * @param {olx.OverlayOptions} options Overlay options.
 * @api stable
 */
ol.Overlay = function(options) {

  goog.base(this);

  /**
   * @private
   * @type {boolean}
   */
  this.insertFirst_ = goog.isDef(options.insertFirst) ?
      options.insertFirst : true;

  /**
   * @private
   * @type {boolean}
   */
  this.stopEvent_ = goog.isDef(options.stopEvent) ? options.stopEvent : true;

  /**
   * @private
   * @type {Element}
   */
  this.element_ = goog.dom.createElement(goog.dom.TagName.DIV);
  this.element_.style.position = 'absolute';

  /**
   * @private
   * @type {{bottom_: string,
   *         left_: string,
   *         right_: string,
   *         top_: string,
   *         visible: boolean}}
   */
  this.rendered_ = {
    bottom_: '',
    left_: '',
    right_: '',
    top_: '',
    visible: true
  };

  /**
   * @private
   * @type {goog.events.Key}
   */
  this.mapPostrenderListenerKey_ = null;

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT),
      this.handleElementChanged, false, this);

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP),
      this.handleMapChanged, false, this);

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET),
      this.handleOffsetChanged, false, this);

  goog.events.listen(
      this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION),
      this.handlePositionChanged, false, this);

  goog.events.listen(
      this,
      ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING),
      this.handlePositioningChanged, false, this);

  if (goog.isDef(options.element)) {
    this.setElement(options.element);
  }

  this.setOffset(goog.isDef(options.offset) ? options.offset : [0, 0]);

  this.setPositioning(goog.isDef(options.positioning) ?
      /** @type {ol.OverlayPositioning} */ (options.positioning) :
      ol.OverlayPositioning.TOP_LEFT);

  if (goog.isDef(options.position)) {
    this.setPosition(options.position);
  }

};
goog.inherits(ol.Overlay, ol.Object);

/**
 * Get the DOM element of this overlay.
 * @return {Element|undefined} The Element containing the overlay.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getElement = function() {
  return /** @type {Element|undefined} */ (
      this.get(ol.OverlayProperty.ELEMENT));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getElement',
    ol.Overlay.prototype.getElement);

/**
 * Get the map associated with this overlay.
 * @return {ol.Map|undefined} The map that the overlay is part of.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getMap = function() {
  return /** @type {ol.Map|undefined} */ (
      this.get(ol.OverlayProperty.MAP));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getMap',
    ol.Overlay.prototype.getMap);

/**
 * Get the offset of this overlay.
 * @return {Array.<number>} The offset.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getOffset = function() {
  return /** @type {Array.<number>} */ (
      this.get(ol.OverlayProperty.OFFSET));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getOffset',
    ol.Overlay.prototype.getOffset);

/**
 * Get the current position of this overlay.
 * @return {ol.Coordinate|undefined} The spatial point that the overlay is
 *     anchored at.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getPosition = function() {
  return /** @type {ol.Coordinate|undefined} */ (
      this.get(ol.OverlayProperty.POSITION));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getPosition',
    ol.Overlay.prototype.getPosition);

/**
 * Get the current positioning of this overlay.
 * @return {ol.OverlayPositioning} How the overlay is positioned
 *     relative to its point on the map.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.getPositioning = function() {
  return /** @type {ol.OverlayPositioning} */ (
      this.get(ol.OverlayProperty.POSITIONING));
};
goog.exportProperty(
    ol.Overlay.prototype,
    'getPositioning',
    ol.Overlay.prototype.getPositioning);

/**
 * @protected
 */
ol.Overlay.prototype.handleElementChanged = function() {
  goog.dom.removeChildren(this.element_);
  var element = this.getElement();
  if (goog.isDefAndNotNull(element)) {
    goog.dom.append(/** @type {!Node} */ (this.element_), element);
  }
};

/**
 * @protected
 */
ol.Overlay.prototype.handleMapChanged = function() {
  if (!goog.isNull(this.mapPostrenderListenerKey_)) {
    goog.dom.removeNode(this.element_);
    goog.events.unlistenByKey(this.mapPostrenderListenerKey_);
    this.mapPostrenderListenerKey_ = null;
  }
  var map = this.getMap();
  if (goog.isDefAndNotNull(map)) {
    this.mapPostrenderListenerKey_ = goog.events.listen(map,
        ol.MapEventType.POSTRENDER, this.handleMapPostrender, false, this);
    this.updatePixelPosition_();
    var container = this.stopEvent_ ?
        map.getOverlayContainerStopEvent() : map.getOverlayContainer();
    if (this.insertFirst_) {
      goog.dom.insertChildAt(/** @type {!Element} */ (
          container), this.element_, 0);
    } else {
      goog.dom.append(/** @type {!Node} */ (container), this.element_);
    }
  }
};

/**
 * @protected
 */
ol.Overlay.prototype.handleMapPostrender = function() {
  this.updatePixelPosition_();
};

/**
 * @protected
 */
ol.Overlay.prototype.handleOffsetChanged = function() {
  this.updatePixelPosition_();
};

/**
 * @protected
 */
ol.Overlay.prototype.handlePositionChanged = function() {
  this.updatePixelPosition_();
};

/**
 * @protected
 */
ol.Overlay.prototype.handlePositioningChanged = function() {
  this.updatePixelPosition_();
};

/**
 * Set the DOM element to be associated with this overlay.
 * @param {Element|undefined} element The Element containing the overlay.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setElement = function(element) {
  this.set(ol.OverlayProperty.ELEMENT, element);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setElement',
    ol.Overlay.prototype.setElement);

/**
 * Set the map to be associated with this overlay.
 * @param {ol.Map|undefined} map The map that the overlay is part of.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setMap = function(map) {
  this.set(ol.OverlayProperty.MAP, map);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setMap',
    ol.Overlay.prototype.setMap);

/**
 * Set the offset for this overlay.
 * @param {Array.<number>} offset Offset.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setOffset = function(offset) {
  this.set(ol.OverlayProperty.OFFSET, offset);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setOffset',
    ol.Overlay.prototype.setOffset);

/**
 * Set the position for this overlay.
 * @param {ol.Coordinate|undefined} position The spatial point that the overlay
 *     is anchored at.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setPosition = function(position) {
  this.set(ol.OverlayProperty.POSITION, position);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setPosition',
    ol.Overlay.prototype.setPosition);

/**
 * Set the positioning for this overlay.
 * @param {ol.OverlayPositioning} positioning how the overlay is
 *     positioned relative to its point on the map.
 * @observable
 * @api stable
 */
ol.Overlay.prototype.setPositioning = function(positioning) {
  this.set(ol.OverlayProperty.POSITIONING, positioning);
};
goog.exportProperty(
    ol.Overlay.prototype,
    'setPositioning',
    ol.Overlay.prototype.setPositioning);

/**
 * @private
 */
ol.Overlay.prototype.updatePixelPosition_ = function() {

  var map = this.getMap();
  var position = this.getPosition();
  if (!goog.isDef(map) || !map.isRendered() || !goog.isDef(position)) {
    if (this.rendered_.visible) {
      goog.style.setElementShown(this.element_, false);
      this.rendered_.visible = false;
    }
    return;
  }

  var pixel = map.getPixelFromCoordinate(position);
  goog.asserts.assert(!goog.isNull(pixel));
  var mapSize = map.getSize();
  goog.asserts.assert(goog.isDef(mapSize));
  var style = this.element_.style;
  var offset = this.getOffset();
  goog.asserts.assert(goog.isArray(offset));
  var positioning = this.getPositioning();
  goog.asserts.assert(goog.isDef(positioning));

  var offsetX = offset[0];
  var offsetY = offset[1];
  if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT ||
      positioning == ol.OverlayPositioning.CENTER_RIGHT ||
      positioning == ol.OverlayPositioning.TOP_RIGHT) {
    if (this.rendered_.left_ !== '') {
      this.rendered_.left_ = style.left = '';
    }
    var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
    if (this.rendered_.right_ != right) {
      this.rendered_.right_ = style.right = right;
    }
  } else {
    if (this.rendered_.right_ !== '') {
      this.rendered_.right_ = style.right = '';
    }
    if (positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
        positioning == ol.OverlayPositioning.CENTER_CENTER ||
        positioning == ol.OverlayPositioning.TOP_CENTER) {
      offsetX -= goog.style.getSize(this.element_).width / 2;
    }
    var left = Math.round(pixel[0] + offsetX) + 'px';
    if (this.rendered_.left_ != left) {
      this.rendered_.left_ = style.left = left;
    }
  }
  if (positioning == ol.OverlayPositioning.BOTTOM_LEFT ||
      positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
      positioning == ol.OverlayPositioning.BOTTOM_RIGHT) {
    if (this.rendered_.top_ !== '') {
      this.rendered_.top_ = style.top = '';
    }
    var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
    if (this.rendered_.bottom_ != bottom) {
      this.rendered_.bottom_ = style.bottom = bottom;
    }
  } else {
    if (this.rendered_.bottom_ !== '') {
      this.rendered_.bottom_ = style.bottom = '';
    }
    if (positioning == ol.OverlayPositioning.CENTER_LEFT ||
        positioning == ol.OverlayPositioning.CENTER_CENTER ||
        positioning == ol.OverlayPositioning.CENTER_RIGHT) {
      offsetY -= goog.style.getSize(this.element_).height / 2;
    }
    var top = Math.round(pixel[1] + offsetY) + 'px';
    if (this.rendered_.top_ != top) {
      this.rendered_.top_ = style.top = top;
    }
  }

  if (!this.rendered_.visible) {
    goog.style.setElementShown(this.element_, true);
    this.rendered_.visible = true;
  }

};
<|endoftext|>


<commit_before>
/**
 * OptiScroll, use this to create instances
 * ```
 * var scrolltime = new OptiScroll(element);
 * ```
 */
var OptiScroll = function OptiScroll(element, options) {
  return new OptiScroll.Instance(element, options || {});
};

var GS = OptiScroll.globalSettings = {
  scrollMinUpdateInterval: 1000 / 40, // 40 FPS
  checkFrequency: 1000,
  pauseCheck: false
};

OptiScroll.defaults = {
  fixTouchPageBounce: true,
  forceScrollbars: false,
  scrollStopDelay: 300,
  maxTrackSize: 95,
  minTrackSize: 5,
  draggableTracks: true,
  autoUpdate: true,
  classPrefix: 'optiscroll'
};

OptiScroll.Instance = function ( element, options ) {
  var me = this;

  me.element = element;
  me.scrollEl = element.children[0];

  // instance variables
  me.settings = _extend( _extend({}, OptiScroll.defaults), options || {});

  me.cache = {};

  me.init();
};

OptiScroll.Instance.prototype.init = function () {
  var me = this,
      settings = me.settings;

  // add instance to global array for timed check
  if(settings.autoUpdate) {
    G.instances.push( me );
  }

  // initialize scrollbars
  me.scrollbars = {
    v: new Scrollbar('v', me),
    h: new Scrollbar('h', me)
  };

  // disable forced scrollbars if Firefox
  // because we cannot hide native scrollbars yet
  if(G.nativeScrollbarSize === 0 && 'mozRequestAnimationFrame' in window) {
    settings.forceScrollbars = false;
  }

  // create DOM scrollbars only if they have size or if it's forced
  if(G.nativeScrollbarSize || settings.forceScrollbars) {
    Utils.hideNativeScrollbars(me.scrollEl);
    _invoke(me.scrollbars, 'create');
  }

  if(G.isTouch && settings.fixTouchPageBounce) {
    toggleClass(me.element, settings.classPrefix+'-nobounce', true);
  }

  // calculate scrollbars
  me.update();

  // bind container events
  me.bind();

  // start the timed check if it is not already running
  if(settings.autoUpdate && !G.checkTimer) {
    Utils.checkLoop();
  }

};

OptiScroll.Instance.prototype.bind = function () {
  var me = this,
      listeners = me.listeners = {},
      scrollEl = me.scrollEl;

  // scroll event binding
  listeners.scroll = function (ev) { Events.scroll(ev, me); };

  // overflow events bindings (non standard, moz + webkit)
  // to update scrollbars immediately
  listeners.overflow = listeners.underflow = listeners.overflowchanged = function (ev) { me.update(); };

  if(G.isTouch) {
    listeners.touchstart = function (ev) { Events.touchstart(ev, me); };
    listeners.touchend = function (ev) { Events.touchend(ev, me); };
  }

  for (var ev in listeners) {
    scrollEl.addEventListener(ev, listeners[ev]);
  }

};

OptiScroll.Instance.prototype.update = function () {
  var me = this,
      oldcH = me.cache.clientH,
      scrollEl = me.scrollEl,
      cache = me.cache,
      sH = scrollEl.scrollHeight,
      cH = scrollEl.clientHeight,
      sW = scrollEl.scrollWidth,
      cW = scrollEl.clientWidth;

  if( sH !== cache.scrollH || cH !== cache.clientH ||
    sW !== cache.scrollW || cW !== cache.clientW ) {

    // if the element is no more in the DOM
    if(sH === 0 && cH === 0 && !document.body.contains(me.element)) {
      me.destroy();
      return false;
    }

    cache.scrollH = sH;
    cache.clientH = cH;
    cache.scrollW = sW;
    cache.clientW = cW;

    // only fire if cache was defined
    if( oldcH !== undefined ) {
      me.fireCustomEvent('sizechange');
    }

    // this will update the scrollbar
    // and check if bottom is reached
    Events.scrollStop(me);
  }
};

/**
 * Animate scrollTo
 * ```
 * $(el).optiScroll('scrollTo', 'left', 100, 200) // scrolls x,y in 200ms
 * ```
 */
OptiScroll.Instance.prototype.scrollTo = function (destX, destY, duration, disableEvents) {
  var me = this,
      cache = me.cache,
      startX, startY, endX, endY;

  G.pauseCheck = true;
  // force update
  me.update();

  startX = endX = me.scrollEl.scrollLeft;
  startY = endY = me.scrollEl.scrollTop;

  if (typeof destX === 'string') { // left or right
    endX = (destX === 'left') ? 0 : cache.scrollW - cache.clientW;
  } else if (typeof destX === 'number') {
    endX = destX;
  }

  if (typeof destY === 'string') { // top or bottom
    endY = (destY === 'top') ? 0 : cache.scrollH - cache.clientH;
  } else if (typeof destY === 'number') {
    endY = destY;
  }

  me.disableScrollEv = disableEvents;

  // animate
  me.animateScroll(startX, endX, startY, endY, duration);

};

OptiScroll.Instance.prototype.scrollIntoView = function (elem, duration, delta) {
  var me = this,
      scrollEl = me.scrollEl,
      eDim, sDim,
      leftEdge, topEdge, rightEdge, bottomEdge,
      startX, startY, endX, endY;

  G.pauseCheck = true;
  // force update
  me.update();

  if(typeof elem === 'string') { // selector
    elem = scrollEl.querySelector(elem);
  }

  if(elem.length && elem.jquery) { // jquery element
    elem = elem[0];
  }

  if(typeof delta === 'number') { // same delta for all
    delta = { top:delta, right:delta, bottom:delta, left:delta };
  }

  delta = delta || {};
  eDim = elem.getBoundingClientRect();
  sDim = scrollEl.getBoundingClientRect();

  startX = endX = scrollEl.scrollLeft;
  startY = endY = scrollEl.scrollTop;
  leftEdge = startX + eDim.left - sDim.left - (delta.left || 0);
  topEdge = startY + eDim.top - sDim.top - (delta.top || 0);
  rightEdge = startX + eDim.left - sDim.left + eDim.width - me.cache.clientW + (delta.right || 0);
  bottomEdge = startY + eDim.top - sDim.top + eDim.height - me.cache.clientH + (delta.bottom || 0);

  if(leftEdge < startX || rightEdge > startX) {
    endX = (leftEdge < startX) ? leftEdge : rightEdge;
  }

  if(topEdge < startY || bottomEdge > startY) {
    endY = (topEdge < startY) ? topEdge : bottomEdge;
  }

  // animate
  me.animateScroll(startX, endX, startY, endY, duration);
};

OptiScroll.Instance.prototype.animateScroll = function (startX, endX, startY, endY, duration) {
  var me = this,
      scrollEl = me.scrollEl,
      startTime = getTime();

  if(endX === startX && endY === startY) {
    return;
  }

  if(duration === 0) {
    scrollEl.scrollLeft = endX;
    scrollEl.scrollTop = endY;
    animationTimeout( function () { me.disableScrollEv = false; }); // restore
    return;
  }

  if(typeof duration !== 'number') { // undefined or auto
    // 500px in 700ms, 1000px in 1080ms, 2000px in 1670ms
    duration = Math.pow( Math.max( Math.abs(endX - startX), Math.abs(endY - startY) ), 0.62) * 15;
  }

  var scrollAnimation = function () {
    var time = Math.min(1, ((getTime() - startTime) / duration)),
        easedTime = Utils.easingFunction(time);

    if( endY !== startY ) {
      scrollEl.scrollTop = (easedTime * (endY - startY)) + startY;
    }
    if( endX !== startX ) {
      scrollEl.scrollLeft = (easedTime * (endX - startX)) + startX;
    }

    if(time < 1) {
      animationTimeout(scrollAnimation);
    } else {
      me.disableScrollEv = false;
      // now the internal scroll event will fire
    }
  };

  animationTimeout(scrollAnimation);
};

OptiScroll.Instance.prototype.destroy = function () {
  var me = this,
      scrollEl = me.scrollEl,
      listeners = me.listeners,
      index = G.instances.indexOf( me );

  // unbind events
  for (var ev in listeners) {
    scrollEl.removeEventListener(ev, listeners[ev]);
  }

  // remove scrollbars elements
  _invoke(me.scrollbars, 'remove');

  // restore style
  scrollEl.removeAttribute('style');
  scrollEl.removeAttribute('data-scroll');

  // remove classes
  toggleClass(me.element, me.settings.classPrefix+'-nobounce', false);

  // defer instance removal from global array
  // to not affect checkLoop _invoke
  if (index > -1) {
    animationTimeout(function () {
      G.instances.splice(index, 1);
    });
  }
};

OptiScroll.Instance.prototype.fireCustomEvent = function (eventName) {
  var eventData = Utils.exposedData(this.cache),
      cEvent = new CustomEvent(eventName, { detail: eventData });

  this.element.dispatchEvent(cEvent);
};

<commit_msg>Update scrollbars instead of firing scrollstop event<commit_after>
/**
 * OptiScroll, use this to create instances
 * ```
 * var scrolltime = new OptiScroll(element);
 * ```
 */
var OptiScroll = function OptiScroll(element, options) {
  return new OptiScroll.Instance(element, options || {});
};

var GS = OptiScroll.globalSettings = {
  scrollMinUpdateInterval: 1000 / 40, // 40 FPS
  checkFrequency: 1000,
  pauseCheck: false
};

OptiScroll.defaults = {
  fixTouchPageBounce: true,
  forceScrollbars: false,
  scrollStopDelay: 300,
  maxTrackSize: 95,
  minTrackSize: 5,
  draggableTracks: true,
  autoUpdate: true,
  classPrefix: 'optiscroll'
};

OptiScroll.Instance = function ( element, options ) {
  var me = this;

  me.element = element;
  me.scrollEl = element.children[0];

  // instance variables
  me.settings = _extend( _extend({}, OptiScroll.defaults), options || {});

  me.cache = {};

  me.init();
};

OptiScroll.Instance.prototype.init = function () {
  var me = this,
      settings = me.settings;

  // add instance to global array for timed check
  if(settings.autoUpdate) {
    G.instances.push( me );
  }

  // initialize scrollbars
  me.scrollbars = {
    v: new Scrollbar('v', me),
    h: new Scrollbar('h', me)
  };

  // disable forced scrollbars if Firefox
  // because we cannot hide native scrollbars yet
  if(G.nativeScrollbarSize === 0 && 'mozRequestAnimationFrame' in window) {
    settings.forceScrollbars = false;
  }

  // create DOM scrollbars only if they have size or if it's forced
  if(G.nativeScrollbarSize || settings.forceScrollbars) {
    Utils.hideNativeScrollbars(me.scrollEl);
    _invoke(me.scrollbars, 'create');
  }

  if(G.isTouch && settings.fixTouchPageBounce) {
    toggleClass(me.element, settings.classPrefix+'-nobounce', true);
  }

  // calculate scrollbars
  me.update();

  // bind container events
  me.bind();

  // start the timed check if it is not already running
  if(settings.autoUpdate && !G.checkTimer) {
    Utils.checkLoop();
  }

};

OptiScroll.Instance.prototype.bind = function () {
  var me = this,
      listeners = me.listeners = {},
      scrollEl = me.scrollEl;

  // scroll event binding
  listeners.scroll = function (ev) { Events.scroll(ev, me); };

  // overflow events bindings (non standard, moz + webkit)
  // to update scrollbars immediately
  listeners.overflow = listeners.underflow = listeners.overflowchanged = function (ev) { me.update(); };

  if(G.isTouch) {
    listeners.touchstart = function (ev) { Events.touchstart(ev, me); };
    listeners.touchend = function (ev) { Events.touchend(ev, me); };
  }

  for (var ev in listeners) {
    scrollEl.addEventListener(ev, listeners[ev]);
  }

};

OptiScroll.Instance.prototype.update = function () {
  var me = this,
      oldcH = me.cache.clientH,
      scrollEl = me.scrollEl,
      cache = me.cache,
      sH = scrollEl.scrollHeight,
      cH = scrollEl.clientHeight,
      sW = scrollEl.scrollWidth,
      cW = scrollEl.clientWidth;

  if( sH !== cache.scrollH || cH !== cache.clientH ||
    sW !== cache.scrollW || cW !== cache.clientW ) {

    // if the element is no more in the DOM
    if(sH === 0 && cH === 0 && !document.body.contains(me.element)) {
      me.destroy();
      return false;
    }

    cache.scrollH = sH;
    cache.clientH = cH;
    cache.scrollW = sW;
    cache.clientW = cW;

    // only fire if cache was defined
    if( oldcH !== undefined ) {
      me.fireCustomEvent('sizechange');
    }

    // this will update the scrollbar
    // and check if bottom is reached
    _invoke(me.scrollbars, 'update');
  }
};

/**
 * Animate scrollTo
 * ```
 * $(el).optiScroll('scrollTo', 'left', 100, 200) // scrolls x,y in 200ms
 * ```
 */
OptiScroll.Instance.prototype.scrollTo = function (destX, destY, duration, disableEvents) {
  var me = this,
      cache = me.cache,
      startX, startY, endX, endY;

  G.pauseCheck = true;
  // force update
  me.update();

  startX = endX = me.scrollEl.scrollLeft;
  startY = endY = me.scrollEl.scrollTop;

  if (typeof destX === 'string') { // left or right
    endX = (destX === 'left') ? 0 : cache.scrollW - cache.clientW;
  } else if (typeof destX === 'number') {
    endX = destX;
  }

  if (typeof destY === 'string') { // top or bottom
    endY = (destY === 'top') ? 0 : cache.scrollH - cache.clientH;
  } else if (typeof destY === 'number') {
    endY = destY;
  }

  me.disableScrollEv = disableEvents;

  // animate
  me.animateScroll(startX, endX, startY, endY, duration);

};

OptiScroll.Instance.prototype.scrollIntoView = function (elem, duration, delta) {
  var me = this,
      scrollEl = me.scrollEl,
      eDim, sDim,
      leftEdge, topEdge, rightEdge, bottomEdge,
      startX, startY, endX, endY;

  G.pauseCheck = true;
  // force update
  me.update();

  if(typeof elem === 'string') { // selector
    elem = scrollEl.querySelector(elem);
  }

  if(elem.length && elem.jquery) { // jquery element
    elem = elem[0];
  }

  if(typeof delta === 'number') { // same delta for all
    delta = { top:delta, right:delta, bottom:delta, left:delta };
  }

  delta = delta || {};
  eDim = elem.getBoundingClientRect();
  sDim = scrollEl.getBoundingClientRect();

  startX = endX = scrollEl.scrollLeft;
  startY = endY = scrollEl.scrollTop;
  leftEdge = startX + eDim.left - sDim.left - (delta.left || 0);
  topEdge = startY + eDim.top - sDim.top - (delta.top || 0);
  rightEdge = startX + eDim.left - sDim.left + eDim.width - me.cache.clientW + (delta.right || 0);
  bottomEdge = startY + eDim.top - sDim.top + eDim.height - me.cache.clientH + (delta.bottom || 0);

  if(leftEdge < startX || rightEdge > startX) {
    endX = (leftEdge < startX) ? leftEdge : rightEdge;
  }

  if(topEdge < startY || bottomEdge > startY) {
    endY = (topEdge < startY) ? topEdge : bottomEdge;
  }

  // animate
  me.animateScroll(startX, endX, startY, endY, duration);
};

OptiScroll.Instance.prototype.animateScroll = function (startX, endX, startY, endY, duration) {
  var me = this,
      scrollEl = me.scrollEl,
      startTime = getTime();

  if(endX === startX && endY === startY) {
    return;
  }

  if(duration === 0) {
    scrollEl.scrollLeft = endX;
    scrollEl.scrollTop = endY;
    animationTimeout( function () { me.disableScrollEv = false; }); // restore
    return;
  }

  if(typeof duration !== 'number') { // undefined or auto
    // 500px in 700ms, 1000px in 1080ms, 2000px in 1670ms
    duration = Math.pow( Math.max( Math.abs(endX - startX), Math.abs(endY - startY) ), 0.62) * 15;
  }

  var scrollAnimation = function () {
    var time = Math.min(1, ((getTime() - startTime) / duration)),
        easedTime = Utils.easingFunction(time);

    if( endY !== startY ) {
      scrollEl.scrollTop = (easedTime * (endY - startY)) + startY;
    }
    if( endX !== startX ) {
      scrollEl.scrollLeft = (easedTime * (endX - startX)) + startX;
    }

    if(time < 1) {
      animationTimeout(scrollAnimation);
    } else {
      me.disableScrollEv = false;
      // now the internal scroll event will fire
    }
  };

  animationTimeout(scrollAnimation);
};

OptiScroll.Instance.prototype.destroy = function () {
  var me = this,
      scrollEl = me.scrollEl,
      listeners = me.listeners,
      index = G.instances.indexOf( me );

  // unbind events
  for (var ev in listeners) {
    scrollEl.removeEventListener(ev, listeners[ev]);
  }

  // remove scrollbars elements
  _invoke(me.scrollbars, 'remove');

  // restore style
  scrollEl.removeAttribute('style');
  scrollEl.removeAttribute('data-scroll');

  // remove classes
  toggleClass(me.element, me.settings.classPrefix+'-nobounce', false);

  // defer instance removal from global array
  // to not affect checkLoop _invoke
  if (index > -1) {
    animationTimeout(function () {
      G.instances.splice(index, 1);
    });
  }
};

OptiScroll.Instance.prototype.fireCustomEvent = function (eventName) {
  var eventData = Utils.exposedData(this.cache),
      cEvent = new CustomEvent(eventName, { detail: eventData });

  this.element.dispatchEvent(cEvent);
};

<|endoftext|>