<commit_before>steal.plugins('jquery/lang/observe',
	'jquery/event/hashchange',
	'jquery/lang/deparam').then(function($){

	var routes = [],
		globalDefaults;

	$.route = {
		param: function(data){
			return $.param(data);
		},
		deparam: function(url){
			return $.String.deparam( url );
		},
		state: new $.Observe({}),
		/**
		 * $.route.route("", {type: "videos"});
		 * $.route.route("{type}");
		 *
		 * @param {Object} name
		 * @param {Object} defaults
		 */
		route : function(name, defaults){

		}
	}

	var throttle = function(func, time){
		var timer;
		return function(){
			clearTimeout(timer);
			timer = setTimeout(func, time || 1);
		}
	},
	curParams,
	setState = function(){

		var hash = window.location.hash.substr(2); // everything after #!
			//deparam it
			var props = $.route.deparam(hash);
			curParams = props;
			$.route.state.merge(props, true);

	};

	// update the state object
	$(window).bind('hashchange', throttle(setState));
	setState();

	// update the page
	$.route.state.bind("change", throttle( function(){
		// param and change the hash if necessary

		// throttle
		window.location.hash ="#!"+$.route.param($.route.state.serialize())
	}));

	// filter -> parts of the hash that should not be put in the hash
	// this is for state that is needed, but not in the url ... like count
	// it's like we need an object that mimicks another object (the client state), but
	// is not the same thing

	// facade
	//var facade = $.Observe($.route.state);
	// you can add properties to facade and use that to communicate non-route state changes

	// but is this necessary?  Is this part of state?

	// grid has the object that you can connect to for state changes

	// can I add this to the route somewhere?

	// $.route.state.attr("grid", grid.data() );

	// defaults?

	/**
	 * Returns the url for the set of options provided.
	 *
	 *
	 *
	 *
	 * @param {Object} options
	 */
	$.route.urlFor = function(options, merge){
		//merges
		if(!merge){
			return "#!"+$.route.param(options)
		} else {
			return "#!"+$.route.param($.extend({}, curParams, options))
		}
	}
	$.route.linkTo = function(name, options, props){
		return ""+name+"";
	}
	var makeProps = function(props){
			var html = [],
				name, val;
			for(name in props){
				val = props[name]
				if(name === 'className'){
					name='class'
				}
				val && html.push(name,"=\"",
					escapeHTML(val),
					"\" ");
			}
			return html.join("")
		},
		escapeHTML = function(content){
			return content
					.replace(/"/g, '"')
					.replace(/'/g, "'");
		}
	$.route.current = function(options){
		return window.location.hash == "#!"+$.route.param(options)
	}
})
<commit_msg>updating steals<commit_after>steal('jquery/lang/observe',
	'jquery/event/hashchange',
	'jquery/lang/deparam', function($){

	var routes = [],
		globalDefaults;

	$.route = {
		param: function(data){
			return $.param(data);
		},
		deparam: function(url){
			return $.String.deparam( url );
		},
		state: new $.Observe({}),
		/**
		 * $.route.route("", {type: "videos"});
		 * $.route.route("{type}");
		 *
		 * @param {Object} name
		 * @param {Object} defaults
		 */
		route : function(name, defaults){

		}
	}

	var throttle = function(func, time){
		var timer;
		return function(){
			clearTimeout(timer);
			timer = setTimeout(func, time || 1);
		}
	},
	curParams,
	setState = function(){

		var hash = window.location.hash.substr(2); // everything after #!
			//deparam it
			var props = $.route.deparam(hash);
			curParams = props;
			$.route.state.merge(props, true);

	};

	// update the state object
	$(window).bind('hashchange', throttle(setState));
	setState();

	// update the page
	$.route.state.bind("change", throttle( function(){
		// param and change the hash if necessary

		// throttle
		window.location.hash ="#!"+$.route.param($.route.state.serialize())
	}));

	// filter -> parts of the hash that should not be put in the hash
	// this is for state that is needed, but not in the url ... like count
	// it's like we need an object that mimicks another object (the client state), but
	// is not the same thing

	// facade
	//var facade = $.Observe($.route.state);
	// you can add properties to facade and use that to communicate non-route state changes

	// but is this necessary?  Is this part of state?

	// grid has the object that you can connect to for state changes

	// can I add this to the route somewhere?

	// $.route.state.attr("grid", grid.data() );

	// defaults?

	/**
	 * Returns the url for the set of options provided.
	 *
	 *
	 *
	 *
	 * @param {Object} options
	 */
	$.route.urlFor = function(options, merge){
		//merges
		if(!merge){
			return "#!"+$.route.param(options)
		} else {
			return "#!"+$.route.param($.extend({}, curParams, options))
		}
	}
	$.route.linkTo = function(name, options, props){
		return ""+name+"";
	}
	var makeProps = function(props){
			var html = [],
				name, val;
			for(name in props){
				val = props[name]
				if(name === 'className'){
					name='class'
				}
				val && html.push(name,"=\"",
					escapeHTML(val),
					"\" ");
			}
			return html.join("")
		},
		escapeHTML = function(content){
			return content
					.replace(/"/g, '"')
					.replace(/'/g, "'");
		}
	$.route.current = function(options){
		return window.location.hash == "#!"+$.route.param(options)
	}
})
<|endoftext|>


<commit_before>function swap(arr, i, j) {
  if (i === j) {
    return;
  }
  const tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp;
}

function checkArray(arr) {
  if (!Array.isArray(arr)) {
    throw new Error("Expect input to be an array.");
  }
}

/**
 * Bubble sort, sorted by swapping item pairs(if needed) from the start postion to the end of the array.
 * First round will have a largest item swapped to the array end, and second round will have the
 * second largest item swapped to array end minus one position, and so on until all items are sorted.
 *
 * Time complexity: O(N, N^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function bubbleSort(array) {
  const arr = array.slice();
  checkArray(arr);
  for (let i = arr.length - 1; i > 0; i--) {
    for (let j = 0; j < i; j++) {
      if (arr[j] > arr[j + 1]) {
        swap(arr, j, j + 1);
      }
    }
  }
  return arr;
}

/**
 * Selection sort, sorted by selecting min to max items for the start to the end position of the array.
 *
 * Time complexity: O(N^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function selectionSort(array) {
  const arr = array.slice();
  checkArray(arr);
  for (let i = 0; i < arr.length - 1; i++) {
    let min = i;
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[min] >= arr[j]) {
        min = j;
      }
    }
    swap(arr, i, min);
  }
  return arr;
}

/**
 * Insertion sort, sorted by inserting each item into a proper position of the sorted part of the
 * array before it.
 * The second item is the first one to insert, this carries on until the last item is inserted into
 * the sorted part of the array before it.
 * Insertion sort is extra fast when the array to sort is small, or is partially sorted.
 *
 * Time complexity: O(N, N^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function insertionSort(array) {
  const arr = array.slice();
  checkArray(arr);
  for (let i = 1; i < arr.length; i++) {
    let cur = i;
    const curVal = arr[cur];
    while (cur > 0 && arr[cur - 1] > curVal) {
      arr[cur] = arr[cur - 1];
      cur -= 1;
    }
    arr[cur] = curVal;
  }
  return arr;
}

/**
 * Shell sort, a type of insertion sort, sorted by swapping each gapped array items. The gap reduces
 * after the gapped array items are sorted. This goes on until the array is sorted.
 * The gap number is determined by a base number, for example, if the base number is 2, then for an
 * array of 16 items, its gap range will be 7, 3, 1.
 *
 * Time complexity: O(NlogN, N(logN)^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function shellSort(array, base = 3) {
  const arr = array.slice();
  const len = arr.length;
  let gap = 1;

  while (gap < len / base) {
    gap = gap * base + 1;
  }
  while (gap > 0) {
    for (let init = gap; init < len; init++) {
      const tmp = arr[init];
      let pos = init;
      for (; pos >= gap && arr[pos - gap] > tmp; pos -= gap) {
        arr[pos] = arr[pos - gap];
      }
      arr[pos] = tmp;
    }
    gap = Math.floor(gap / base);
  }

  return arr;
}

/**
 * Quick sort, sorted by performing a partition process for a chosen pivot item, and the same is done
 * for the left/right partitioned parts, and so on.
 * The partition process will swap pairs of items until the left part are all smaller than pivot,
 * and right part are all larger.
 * This function implemented it by creating extra partitioned array upon each partition process.
 * It's concise and easy to read, but has extra space complexity than quickSort implementation below.
 *
 * Time complexity: O(NlogN, N^2)
 * Space complexity: O(N)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function quickSortWithArray(array) {
  const arr = array.slice();
  checkArray(arr);
  if (arr.length < 2) {
    return arr;
  }
  const [pivot, ...rest] = arr;
  const larger = rest.filter((item) => item > pivot);
  const smaller = rest.filter((item) => item <= pivot);

  return [...quickSortWithArray(smaller), pivot, ...quickSortWithArray(larger)];
}

/**
 * Quick sort, sorted by performing a partition process for a chosen pivot item, and the same is done
 * for the left/right partitioned parts, and so on.
 * The partition process will swap pairs of items until the left part are all smaller than pivot,
 * and right part are all larger.
 *
 * Time complexity: O(NlogN, N^2)
 * Space complexity: O(logN)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function quickSort(arr, lo, hi) {
  checkArray(arr);
  lo = typeof lo === "number" ? lo : 0;
  hi = typeof hi === "number" ? hi : arr.length;

  if (hi <= lo) return arr;

  let start = lo;
  let end = hi;
  const pivot = arr[lo];

  while (start < end) {
    while (arr[++start] <= pivot) if (start === hi) break;
    while (arr[--end] >= pivot) if (end === lo) break;
    if (start >= end) break;
    swap(arr, start, end);
  }
  swap(arr, lo, end);

  quickSort(arr, lo, end);
  quickSort(arr, end + 1, hi);

  return arr;
}

/**
 * Merge sort, sorted by recursively dividing the array into two sub-arrays and merging corresponding
 * sub-arrays back into a sorted array. The merge process ensures that the merged array is sorted.
 *
 * Time complexity: O(NlogN)
 * Space complexity: O(N)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function mergeSort(array) {
  const arr = array.slice();
  checkArray(arr);
  if (arr.length < 2) {
    return arr;
  }
  const merge = (arr1, arr2) => {
    const result = [];
    const arrLen1 = arr1.length;
    const arrLen2 = arr2.length;
    let pt1 = 0;
    let pt2 = 0;

    while (pt1 < arrLen1 && pt2 < arrLen2) {
      if (arr1[pt1] === arr2[pt2]) {
        result.push(arr1[pt1], arr2[pt2]);
        pt1 += 1;
        pt2 += 1;
      } else if (arr1[pt1] > arr2[pt2]) {
        result.push(arr2[pt2]);
        pt2 += 1;
      } else {
        result.push(arr1[pt1]);
        pt1 += 1;
      }
    }

    return result.concat(arr1.slice(pt1)).concat(arr2.slice(pt2));
  };
  const mid = Math.floor(arr.length - 1 / 2);
  const leftArr = arr.slice(0, mid);
  const rightArr = arr.slice(mid);

  return merge(mergeSort(leftArr), mergeSort(rightArr));
}

/**
 * Heap sort, sorted by using the heapify process of the Heap data structure.
 * The Heap data structure looks like a binary tree, but there cannot be `null` gap within it.
 * A proper Heap should have the property that all parent nodes are larger than or equal to its child
 * nodes.
 * The heapify process can find the largest item of the array at a time, and then swap the largest
 * item to the end of the array. This process is repeated until all the array become sorted.
 *
 * Time complexity: O(NlogN)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function heapSort(array) {
  const arr = array.slice();
  checkArray(arr);
  if (arr.length < 2) {
    return arr;
  }
  const heapify = (list, index, end = list.length - 1) => {
    const parentIndex = Math.ceil(index / 2) - 1;
    if (index < 0 || parentIndex < 0) {
      return;
    }
    const isLeft = index % 2 === 1;
    const peerIndex = isLeft ? index + 1 : index - 1;

    let largest = parentIndex;
    if (list[index] > list[largest]) largest = index;
    if (peerIndex <= end && list[peerIndex] > list[largest]) largest = peerIndex;
    if (largest !== parentIndex) swap(list, largest, parentIndex);

    heapify(list, index - 2, end);
  };

  for (let last = arr.length - 1; last > 0; last -= 1) {
    heapify(arr, last, last);
    swap(arr, 0, last);
  }

  return arr;
}
<commit_msg>refined a bit on sorting algorithm<commit_after>function swap(arr, i, j) {
  if (i === j) {
    return;
  }
  const tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp;
}

function checkArray(arr) {
  if (!Array.isArray(arr)) {
    throw new Error("Expect input to be an array.");
  }
}

/**
 * Bubble sort, sorted by swapping item pairs(if needed) from the start postion to the end of the
 * array.
 * First round will have a largest item swapped to the array end, and second round will have the
 * second largest item swapped to array end - 1 position, and so on until all items are sorted.
 *
 * Time complexity: O(N, N^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function bubbleSort(array) {
  const arr = array.slice();
  checkArray(arr);
  let hasSwap = false;
  for (let i = arr.length - 1; i > 0; i--) {
    for (let j = 0; j < i; j++) {
      if (arr[j] > arr[j + 1]) {
        swap(arr, j, j + 1);
        hasSwap = true;
      }
    }
    if (!hasSwap) {
      return arr;
    }
  }
  return arr;
}

/**
 * Selection sort, sorted by selecting min to max items for the start to the end position of the
 * array.
 *
 * Time complexity: O(N^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function selectionSort(array) {
  const arr = array.slice();
  checkArray(arr);
  for (let i = 0; i < arr.length - 1; i++) {
    let min = i;
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[min] >= arr[j]) {
        min = j;
      }
    }
    swap(arr, i, min);
  }
  return arr;
}

/**
 * Insertion sort, sorted by inserting each item into a proper position of the sorted part of the
 * array before it.
 * The second item is the first one to insert, this carries on until the last item is inserted into
 * the sorted part of the array before it.
 * Insertion sort is extra fast when the array to sort is small, or is partially sorted.
 *
 * Time complexity: O(N, N^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function insertionSort(array) {
  const arr = array.slice();
  checkArray(arr);
  for (let i = 1; i < arr.length; i++) {
    let cur = i;
    const curVal = arr[cur];
    while (cur > 0 && arr[cur - 1] > curVal) {
      arr[cur] = arr[cur - 1];
      cur -= 1;
    }
    arr[cur] = curVal;
  }
  return arr;
}

/**
 * Shell sort, a type of insertion sort, sorted by swapping each gapped array items. The gap reduces
 * after the gapped array items are sorted. This goes on until the array is sorted.
 * The gap number is determined by a base number, for example, if the base number is 2, then for an
 * array of 16 items, its gap range will be 7, 3, 1.
 *
 * Time complexity: O(NlogN, N(logN)^2)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function shellSort(array, base = 3) {
  const arr = array.slice();
  const len = arr.length;
  let gap = 1;

  while (gap < len / base) {
    gap = gap * base + 1;
  }
  while (gap > 0) {
    for (let init = gap; init < len; init++) {
      const tmp = arr[init];
      let pos = init;
      for (; pos >= gap && arr[pos - gap] > tmp; pos -= gap) {
        arr[pos] = arr[pos - gap];
      }
      arr[pos] = tmp;
    }
    gap = Math.floor(gap / base);
  }

  return arr;
}

/**
 * Quick sort, sorted by performing a partition process for a chosen pivot item, and the same is
 * done for the left/right partitioned parts, and so on.
 * The partition process will swap pairs of items until the left part are all smaller than pivot,
 * and right part are all larger.
 * This function implemented it by creating extra partitioned array upon each partition process.
 * It's concise and easy to read, but has extra space complexity.
 *
 * Time complexity: O(NlogN, N^2)
 * Space complexity: O(N)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function quickSortWithArray(array) {
  const arr = array.slice();
  checkArray(arr);
  if (arr.length < 2) {
    return arr;
  }
  const [pivot, ...rest] = arr;
  const larger = rest.filter((item) => item > pivot);
  const smaller = rest.filter((item) => item <= pivot);

  return [...quickSortWithArray(smaller), pivot, ...quickSortWithArray(larger)];
}

/**
 * Quick sort, sorted by performing a partition process for a chosen pivot item, and the same is
 * done for the left/right partitioned parts, and so on.
 * The partition process will swap pairs of items until the left part are all smaller than pivot,
 * and right part are all larger.
 *
 * Time complexity: O(NlogN, N^2)
 * Space complexity: O(logN)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function quickSort(array, lo, hi) {
  checkArray(array);
  lo = typeof lo === "number" ? lo : 0;
  hi = typeof hi === "number" ? hi : array.length;
  if (hi <= lo) return array;

  const partition = (arr, left, right) => {
    let start = left;
    let end = right;
    const pivot = arr[left];

    while (start < end) {
      while (arr[++start] <= pivot) if (start === right) break; // eslint-disable-line no-plusplus
      while (arr[--end] >= pivot) if (end === left) break; // eslint-disable-line no-plusplus
      if (start >= end) break;
      swap(arr, start, end);
    }
    swap(arr, left, end);
    return end;
  };
  const pivot = partition(array, lo, hi);
  quickSort(array, lo, pivot);
  quickSort(array, pivot + 1, hi);

  return array;
}

/**
 * Merge sort, sorted by recursively dividing the array into two sub-arrays and merging
 * corresponding sub-arrays back into a sorted array. The merge process ensures that the merged
 * array is sorted.
 *
 * Time complexity: O(NlogN)
 * Space complexity: O(N)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function mergeSort(array) {
  const arr = array.slice();
  checkArray(arr);
  if (arr.length < 2) {
    return arr;
  }
  const merge = (a, b) => {
    const result = [];
    const lenA = a.length;
    const lenB = b.length;
    let i = 0;
    let j = 0;
    while (i < lenA && j < lenB) {
      if (a[i] === b[j]) {
        result.push(a[i], b[j]);
        i += 1;
        j += 1;
      } else if (a[i] > b[j]) {
        result.push(b[j]);
        j += 1;
      } else {
        result.push(a[i]);
        i += 1;
      }
    }
    return result.concat(a.slice(i)).concat(b.slice(j));
  };
  const mid = Math.floor(arr.length / 2);
  return merge(mergeSort(arr.slice(0, mid)), mergeSort(arr.slice(mid)));
}

/**
 * Heap sort, sorted by using the heapify process of the Heap data structure.
 * The Heap data structure looks like a binary tree, but there cannot be `null` gap within it.
 * A proper Heap should have the property that all parent nodes are larger than or equal to its
 * child nodes.
 * The heapify process can find the largest item of the array at a time, and then swap the largest
 * item to the end of the array. This process is repeated until all the array become sorted.
 *
 * Time complexity: O(NlogN)
 * Space complexity: O(1)
 *
 * @param {Array} array
 * @return {Array}
 *
 */
export function heapSort(array) {
  const arr = array.slice();
  checkArray(arr);
  if (arr.length < 2) {
    return arr;
  }
  const heapify = (list, index, end = list.length - 1) => {
    const parentIndex = Math.ceil(index / 2) - 1;
    if (index < 0 || parentIndex < 0) {
      return;
    }
    const isLeft = index % 2 === 1;
    const peerIndex = isLeft ? index + 1 : index - 1;

    let largest = parentIndex;
    if (list[index] > list[largest]) largest = index;
    if (peerIndex <= end && list[peerIndex] > list[largest]) largest = peerIndex;
    if (largest !== parentIndex) swap(list, largest, parentIndex);

    heapify(list, index - 2, end);
  };

  for (let last = arr.length - 1; last > 0; last -= 1) {
    heapify(arr, last, last);
    swap(arr, 0, last);
  }

  return arr;
}
<|endoftext|>


<commit_before>
(function (window, $, H5AI, config) {

	H5AI.core = (function () {

		var $window = $(window),
			defaults = {
				store: {
					viewmode: "h5ai.pref.viewmode",
					lang: "h5ai.pref.lang"
				},
				callbacks: {
					pathClick: []
				},

				rootAbsHref: "/",
				h5aiAbsHref: "/_h5ai/",
				customHeader: null,
				customFooter: null,
				viewmodes: ["details", "icons"],
				sortorder: "na",
				showTree: true,
				slideTree: true,
				folderStatus: {},
				lang: "en",
				useBrowserLang: true,
				setParentFolderLabels: true,
				linkHoverStates: true,
				dateFormat: "yyyy-MM-dd HH:mm",
				showThumbs: false,
				thumbTypes: ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
				zippedDownload: false,
				qrCodesSize: null,
				showFilter: false
			},
			settings = $.extend({}, defaults, config.options),
			currentDateFormat = settings.dateFormat,
			extToFileType = (function (types) {
				var map = {};
				$.each(types, function (type, exts) {
					$.each(exts, function (idx, ext) {
						map[ext] = type;
					});
				});
				return map;
			}(config.types)),
			hash = function (obj) {

				if ($.isPlainObject(obj)) {
					var hashStr = '';
					$.each($.extend({}, hash(), obj), function (key, value) {
						if (value) {
							hashStr += '/' + key + '=' + value;
						}
					});
					hashStr = '#!' + hashStr;
					window.location.hash = hashStr;
					return hashStr;
				} else {
					var result = {},
						parts = document.location.hash.split('/');

					if (parts.length >= 2 || parts[0] === '#!') {
						parts.shift();
						$.each(parts, function (idx, part) {

							var match = /^([^=]*)=(.*?)$/.exec(part);
							if (match) {
								result[match[1]] = match[2];
							}
						});
					}
					return typeof obj === 'string' ? result[obj] : result;
				}
			},
			api = function () {

				return settings.h5aiAbsHref + "php/api.php";
			},
			image = function (id, noPngExt) {

				return settings.h5aiAbsHref + "images/" + id + (noPngExt ? "" : ".png");
			},
			icon = function (id, big) {

				return settings.h5aiAbsHref + "icons/" + (big ? "48x48" : "16x16") + "/" + id + ".png";
			},
			viewmode = function (viewmode) {

				var $viewDetails = $("#viewdetails"),
					$viewIcons = $("#viewicons"),
					$extended = $("#extended");

				if (viewmode) {
					amplify.store(settings.store.viewmode, viewmode);
				} else {
					viewmode = amplify.store(settings.store.viewmode);
				}
				viewmode = $.inArray(viewmode, settings.viewmodes) >= 0 ? viewmode : settings.viewmodes[0];
				H5AI.core.hash({view: viewmode});

				$viewDetails.add($viewIcons).removeClass("current");
				if (viewmode === "details") {
					$viewDetails.addClass("current");
					$extended.addClass("details-view").removeClass("icons-view").show();
				} else if (viewmode === "icons") {
					$viewIcons.addClass("current");
					$extended.removeClass("details-view").addClass("icons-view").show();
				} else {
					$extended.hide();
				}
			},
			initTopSpace = function () {

				var $body = $("body"),
					$tree = $("#tree"),
					adjustTopSpace = function () {

						var winHeight = $window.height(),
							navHeight = $("body > nav").outerHeight(),
							footerHeight = $("body > footer").outerHeight(),
							contentSpacing = 50,
							treeSpacing = 0;

						$body.css({
							"margin-top": navHeight + contentSpacing,
							"margin-bottom": footerHeight + contentSpacing
						});

						$tree.css({
							top: navHeight + treeSpacing,
							height: winHeight - navHeight - footerHeight - 16 - 2 * treeSpacing
						});

						try {
							$tree.get(0).updateScrollbar();
						} catch (err) {}
					};

				$window.resize(function () {
					adjustTopSpace();
				});
				adjustTopSpace();
			},
			initViews = function () {

				var $navbar = $("#navbar"),
					$extended = $("#extended");

				$("#table").remove();

				if (settings.viewmodes.length > 1) {
					if ($.inArray("icons", settings.viewmodes) >= 0) {
						$("
icons
")
							.find("img").attr("src", image("view-icons")).end()
							.find("a").click(function (event) {
								viewmode("icons");
								event.preventDefault();
							}).end()
							.appendTo($navbar);
					}
					if ($.inArray("details", settings.viewmodes) >= 0) {
						$("
details
")
							.find("img").attr("src", image("view-details")).end()
							.find("a").click(function (event) {
								viewmode("details");
								event.preventDefault();
							}).end()
							.appendTo($navbar);
					}
				}

				// status update
				$extended.find(".entry a").hover(
					function () {
						if ($extended.hasClass("icons-view")) {
							var $this = $(this);
							$(".status.default").hide();
							$(".status.dynamic")
								.empty()
								.append($this.find(".label").clone())
								.append($("·"))
								.append($this.find(".date").clone())
								.show();

							if (!$this.closest(".entry").hasClass("folder")) {
								$(".status.dynamic")
									.append($("·"))
									.append($this.find(".size").clone());
							}
						}
					},
					function () {
						$(".status.default").show();
						$(".status.dynamic").empty().hide();
					}
				);
			},
			shiftTree = function (forceVisible, dontAnimate) {

				var $tree = $("#tree"),
					$extended = $("#extended");

				if ((settings.slideTree && $tree.outerWidth() < $extended.offset().left) || forceVisible) {
					if (dontAnimate) {
						$tree.stop().css({ left: 0 });
					} else {
						$tree.stop().animate({ left: 0 });
					}
				} else {
					if (dontAnimate) {
						$tree.stop().css({ left: 18 - $tree.outerWidth() });
					} else {
						$tree.stop().animate({ left: 18 - $tree.outerWidth() });
					}
				}
			},
			initTree = function () {

				$("#tree").hover(
					function () { shiftTree(true); },
					function () { shiftTree(); }
				);
				$window.resize(function () { shiftTree(); });
				shiftTree(false, true);
			},
			selectLinks = function (href) {

				var elements = [];
				$("a[href^='/']").each(function () {

					if ($(this).attr("href") === href) {
						elements.push(this);
					}
				});
				return $(elements);
			},
			linkHoverStates = function () {

				if (settings.linkHoverStates) {
					$("a[href^='/']:not(.linkedHoverStates)").each(function () {

						var $a = $(this).addClass("linkedHoverStates"),
							href = $a.attr("href");

						$a.hover(
							function () { selectLinks(href).addClass("hover"); },
							function () { selectLinks(href).removeClass("hover"); }
						);
					});
				}
			},
			formatDates = function (dateFormat) {

				if (dateFormat) {
					currentDateFormat = dateFormat;
				}

				$("#extended .entry .date").each(function () {

					var $this = $(this),
						time = $this.data("time"),
						formattedDate = time ? new Date(time).toString(currentDateFormat) : "";

					$this.text(formattedDate);
				});
			},
			localize = function (langs, lang, useBrowserLang) {

				var storedLang = amplify.store(settings.store.lang),
					browserLang, selected, key;

				if (langs[storedLang]) {
					lang = storedLang;
				} else if (useBrowserLang) {
					browserLang = navigator.language;
					if (langs[browserLang]) {
						lang = browserLang;
					} else if (browserLang.length > 2 && langs[browserLang.substr(0, 2)]) {
						lang = browserLang.substr(0, 2);
					}
				}

				if (!langs[lang]) {
					lang = "en";
				}

				selected = langs[lang];
				if (selected) {
					$.each(selected, function (key, value) {
						$(".l10n-" + key).text(value);
					});
					$(".lang").text(lang);
					$(".langOption").removeClass("current");
					$(".langOption." + lang).addClass("current");
					H5AI.core.hash({lang: lang});
				}

				formatDates(selected.dateFormat || settings.dateFormat);
			},
			initLangSelector = function (langs) {

				var $langOptions = $("#langSelector .langOptions"),
					sortedLangsKeys = [],
					$ul;

				$.each(langs, function (lang) {
					sortedLangsKeys.push(lang);
				});
				sortedLangsKeys.sort();

				$ul = $("
");
				$.each(sortedLangsKeys, function (idx, lang) {
					$("
")
						.addClass(lang)
						.text(lang + " - " + langs[lang].lang)
						.appendTo($ul)
						.click(function () {
							amplify.store(settings.store.lang, lang);
							localize(langs, lang, false);
						});
				});
				$langOptions
					.append($ul)
					.scrollpanel();

				$("#langSelector").hover(
					function () {
						$langOptions
							.css("top", "-" + $langOptions.outerHeight() + "px")
							.stop(true, true)
							.fadeIn();
						$langOptions.get(0).updateScrollbar();
					},
					function () {
						$langOptions
							.stop(true, true)
							.fadeOut();
					}
				);
			},
			onIndicatorClick = function (event) {

				var $indicator = $(this),
					$entry = $indicator.closest(".entry"),
					updateTreeScrollbar = $("#tree").get(0).updateScrollbar;

				if ($indicator.hasClass("unknown")) {
					$.get(api(), { "action": "tree", "href": $entry.find("> a").attr("href") }, function (html) {

						var $content = $(html);

						$indicator.removeClass("unknown");
						if ($content.find("> li").size() === 0) {
							$indicator.replaceWith($(""));
						} else {
							$indicator.addClass("open");
							$entry.find("> .content").replaceWith($content);
							updateTreeScrollbar();
							$content.find(".indicator:not(.initiated)")
								.click(onIndicatorClick)
								.addClass("initiated");
						}
					});
				} else if ($indicator.hasClass("open")) {
					$indicator.removeClass("open");
					updateTreeScrollbar(true);
					$entry.find("> .content").slideUp(function () {
						updateTreeScrollbar();
					});
				} else {
					$indicator.addClass("open");
					updateTreeScrollbar(true);
					$entry.find("> .content").slideDown(function () {
						updateTreeScrollbar();
					});
				}
			},
			initIndicators = function () {

				$("#tree .entry.folder .indicator:not(.initiated)")
					.click(onIndicatorClick)
					.addClass("initiated");
			},
			getFileType = function (filename) {

				var dotidx = filename.lastIndexOf('.'),
					ext = dotidx >= 0 ? filename.substr(dotidx) : filename;

				return extToFileType[ext.toLowerCase()] || "unknown";
			},
			formatSizes = function () {

				$("#extended .entry .size").each(function () {

					var $this = $(this),
						bytes = $this.data("bytes"),
						formattedSize = bytes >= 0 ? H5AI.util.formatSize(bytes) : "";

					$this.text(formattedSize);
				});
			},
			setTotals = function () {

				var $extended = $("#extended");

				$(".folderTotal").text($extended.find(".entry.folder:not(.folder-parent)").length);
				$(".fileTotal").text($extended.find(".entry.file").length);
			},
			init = function () {

				initViews();
				viewmode();
				initTopSpace();
				initTree();
				linkHoverStates();
				initLangSelector(config.langs);
				localize(config.langs, settings.lang, settings.useBrowserLang);
				formatSizes();
				setTotals();
				initIndicators();
			};

		return {
			settings: settings,
			hash: hash,
			api: api,
			image: image,
			icon: icon,
			shiftTree: shiftTree,
			linkHoverStates: linkHoverStates,
			initIndicators: initIndicators,
			formatDates: formatDates,
			getFileType: getFileType,
			init: init
		};
	}());

}(window, jQuery, H5AI, H5AI_CONFIG));
<commit_msg>Adds en- and decoding for URL hashes.<commit_after>
(function (window, $, H5AI, config) {

	H5AI.core = (function () {

		var $window = $(window),
			defaults = {
				store: {
					viewmode: "h5ai.pref.viewmode",
					lang: "h5ai.pref.lang"
				},
				callbacks: {
					pathClick: []
				},

				rootAbsHref: "/",
				h5aiAbsHref: "/_h5ai/",
				customHeader: null,
				customFooter: null,
				viewmodes: ["details", "icons"],
				sortorder: "na",
				showTree: true,
				slideTree: true,
				folderStatus: {},
				lang: "en",
				useBrowserLang: true,
				setParentFolderLabels: true,
				linkHoverStates: true,
				dateFormat: "yyyy-MM-dd HH:mm",
				showThumbs: false,
				thumbTypes: ["bmp", "gif", "ico", "image", "jpg", "png", "tiff"],
				zippedDownload: false,
				qrCodesSize: null,
				showFilter: false
			},
			settings = $.extend({}, defaults, config.options),
			currentDateFormat = settings.dateFormat,
			extToFileType = (function (types) {
				var map = {};
				$.each(types, function (type, exts) {
					$.each(exts, function (idx, ext) {
						map[ext] = type;
					});
				});
				return map;
			}(config.types)),
			hash = function (obj) {

				if ($.isPlainObject(obj)) {
					var hashStr = '';
					$.each($.extend({}, hash(), obj), function (key, value) {
						if (value) {
							hashStr += '/' + encodeURIComponent(key) + '=' + encodeURIComponent(value);
						}
					});
					hashStr = '#!' + hashStr;
					window.location.hash = hashStr;
					return hashStr;
				} else {
					var result = {},
						parts = document.location.hash.split('/');

					if (parts.length >= 2 || parts[0] === '#!') {
						parts.shift();
						$.each(parts, function (idx, part) {

							var match = /^([^=]*)=(.*?)$/.exec(part);
							if (match) {
								result[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
							}
						});
					}
					return typeof obj === 'string' ? result[obj] : result;
				}
			},
			api = function () {

				return settings.h5aiAbsHref + "php/api.php";
			},
			image = function (id, noPngExt) {

				return settings.h5aiAbsHref + "images/" + id + (noPngExt ? "" : ".png");
			},
			icon = function (id, big) {

				return settings.h5aiAbsHref + "icons/" + (big ? "48x48" : "16x16") + "/" + id + ".png";
			},
			viewmode = function (viewmode) {

				var $viewDetails = $("#viewdetails"),
					$viewIcons = $("#viewicons"),
					$extended = $("#extended");

				if (viewmode) {
					amplify.store(settings.store.viewmode, viewmode);
				} else {
					viewmode = amplify.store(settings.store.viewmode);
				}
				viewmode = $.inArray(viewmode, settings.viewmodes) >= 0 ? viewmode : settings.viewmodes[0];
				H5AI.core.hash({view: viewmode});

				$viewDetails.add($viewIcons).removeClass("current");
				if (viewmode === "details") {
					$viewDetails.addClass("current");
					$extended.addClass("details-view").removeClass("icons-view").show();
				} else if (viewmode === "icons") {
					$viewIcons.addClass("current");
					$extended.removeClass("details-view").addClass("icons-view").show();
				} else {
					$extended.hide();
				}
			},
			initTopSpace = function () {

				var $body = $("body"),
					$tree = $("#tree"),
					adjustTopSpace = function () {

						var winHeight = $window.height(),
							navHeight = $("body > nav").outerHeight(),
							footerHeight = $("body > footer").outerHeight(),
							contentSpacing = 50,
							treeSpacing = 0;

						$body.css({
							"margin-top": navHeight + contentSpacing,
							"margin-bottom": footerHeight + contentSpacing
						});

						$tree.css({
							top: navHeight + treeSpacing,
							height: winHeight - navHeight - footerHeight - 16 - 2 * treeSpacing
						});

						try {
							$tree.get(0).updateScrollbar();
						} catch (err) {}
					};

				$window.resize(function () {
					adjustTopSpace();
				});
				adjustTopSpace();
			},
			initViews = function () {

				var $navbar = $("#navbar"),
					$extended = $("#extended");

				$("#table").remove();

				if (settings.viewmodes.length > 1) {
					if ($.inArray("icons", settings.viewmodes) >= 0) {
						$("
icons
")
							.find("img").attr("src", image("view-icons")).end()
							.find("a").click(function (event) {
								viewmode("icons");
								event.preventDefault();
							}).end()
							.appendTo($navbar);
					}
					if ($.inArray("details", settings.viewmodes) >= 0) {
						$("
details
")
							.find("img").attr("src", image("view-details")).end()
							.find("a").click(function (event) {
								viewmode("details");
								event.preventDefault();
							}).end()
							.appendTo($navbar);
					}
				}

				// status update
				$extended.find(".entry a").hover(
					function () {
						if ($extended.hasClass("icons-view")) {
							var $this = $(this);
							$(".status.default").hide();
							$(".status.dynamic")
								.empty()
								.append($this.find(".label").clone())
								.append($("·"))
								.append($this.find(".date").clone())
								.show();

							if (!$this.closest(".entry").hasClass("folder")) {
								$(".status.dynamic")
									.append($("·"))
									.append($this.find(".size").clone());
							}
						}
					},
					function () {
						$(".status.default").show();
						$(".status.dynamic").empty().hide();
					}
				);
			},
			shiftTree = function (forceVisible, dontAnimate) {

				var $tree = $("#tree"),
					$extended = $("#extended");

				if ((settings.slideTree && $tree.outerWidth() < $extended.offset().left) || forceVisible) {
					if (dontAnimate) {
						$tree.stop().css({ left: 0 });
					} else {
						$tree.stop().animate({ left: 0 });
					}
				} else {
					if (dontAnimate) {
						$tree.stop().css({ left: 18 - $tree.outerWidth() });
					} else {
						$tree.stop().animate({ left: 18 - $tree.outerWidth() });
					}
				}
			},
			initTree = function () {

				$("#tree").hover(
					function () { shiftTree(true); },
					function () { shiftTree(); }
				);
				$window.resize(function () { shiftTree(); });
				shiftTree(false, true);
			},
			selectLinks = function (href) {

				var elements = [];
				$("a[href^='/']").each(function () {

					if ($(this).attr("href") === href) {
						elements.push(this);
					}
				});
				return $(elements);
			},
			linkHoverStates = function () {

				if (settings.linkHoverStates) {
					$("a[href^='/']:not(.linkedHoverStates)").each(function () {

						var $a = $(this).addClass("linkedHoverStates"),
							href = $a.attr("href");

						$a.hover(
							function () { selectLinks(href).addClass("hover"); },
							function () { selectLinks(href).removeClass("hover"); }
						);
					});
				}
			},
			formatDates = function (dateFormat) {

				if (dateFormat) {
					currentDateFormat = dateFormat;
				}

				$("#extended .entry .date").each(function () {

					var $this = $(this),
						time = $this.data("time"),
						formattedDate = time ? new Date(time).toString(currentDateFormat) : "";

					$this.text(formattedDate);
				});
			},
			localize = function (langs, lang, useBrowserLang) {

				var storedLang = amplify.store(settings.store.lang),
					browserLang, selected, key;

				if (langs[storedLang]) {
					lang = storedLang;
				} else if (useBrowserLang) {
					browserLang = navigator.language;
					if (langs[browserLang]) {
						lang = browserLang;
					} else if (browserLang.length > 2 && langs[browserLang.substr(0, 2)]) {
						lang = browserLang.substr(0, 2);
					}
				}

				if (!langs[lang]) {
					lang = "en";
				}

				selected = langs[lang];
				if (selected) {
					$.each(selected, function (key, value) {
						$(".l10n-" + key).text(value);
					});
					$(".lang").text(lang);
					$(".langOption").removeClass("current");
					$(".langOption." + lang).addClass("current");
					H5AI.core.hash({lang: lang});
				}

				formatDates(selected.dateFormat || settings.dateFormat);
			},
			initLangSelector = function (langs) {

				var $langOptions = $("#langSelector .langOptions"),
					sortedLangsKeys = [],
					$ul;

				$.each(langs, function (lang) {
					sortedLangsKeys.push(lang);
				});
				sortedLangsKeys.sort();

				$ul = $("
");
				$.each(sortedLangsKeys, function (idx, lang) {
					$("
")
						.addClass(lang)
						.text(lang + " - " + langs[lang].lang)
						.appendTo($ul)
						.click(function () {
							amplify.store(settings.store.lang, lang);
							localize(langs, lang, false);
						});
				});
				$langOptions
					.append($ul)
					.scrollpanel();

				$("#langSelector").hover(
					function () {
						$langOptions
							.css("top", "-" + $langOptions.outerHeight() + "px")
							.stop(true, true)
							.fadeIn();
						$langOptions.get(0).updateScrollbar();
					},
					function () {
						$langOptions
							.stop(true, true)
							.fadeOut();
					}
				);
			},
			onIndicatorClick = function (event) {

				var $indicator = $(this),
					$entry = $indicator.closest(".entry"),
					updateTreeScrollbar = $("#tree").get(0).updateScrollbar;

				if ($indicator.hasClass("unknown")) {
					$.get(api(), { "action": "tree", "href": $entry.find("> a").attr("href") }, function (html) {

						var $content = $(html);

						$indicator.removeClass("unknown");
						if ($content.find("> li").size() === 0) {
							$indicator.replaceWith($(""));
						} else {
							$indicator.addClass("open");
							$entry.find("> .content").replaceWith($content);
							updateTreeScrollbar();
							$content.find(".indicator:not(.initiated)")
								.click(onIndicatorClick)
								.addClass("initiated");
						}
					});
				} else if ($indicator.hasClass("open")) {
					$indicator.removeClass("open");
					updateTreeScrollbar(true);
					$entry.find("> .content").slideUp(function () {
						updateTreeScrollbar();
					});
				} else {
					$indicator.addClass("open");
					updateTreeScrollbar(true);
					$entry.find("> .content").slideDown(function () {
						updateTreeScrollbar();
					});
				}
			},
			initIndicators = function () {

				$("#tree .entry.folder .indicator:not(.initiated)")
					.click(onIndicatorClick)
					.addClass("initiated");
			},
			getFileType = function (filename) {

				var dotidx = filename.lastIndexOf('.'),
					ext = dotidx >= 0 ? filename.substr(dotidx) : filename;

				return extToFileType[ext.toLowerCase()] || "unknown";
			},
			formatSizes = function () {

				$("#extended .entry .size").each(function () {

					var $this = $(this),
						bytes = $this.data("bytes"),
						formattedSize = bytes >= 0 ? H5AI.util.formatSize(bytes) : "";

					$this.text(formattedSize);
				});
			},
			setTotals = function () {

				var $extended = $("#extended");

				$(".folderTotal").text($extended.find(".entry.folder:not(.folder-parent)").length);
				$(".fileTotal").text($extended.find(".entry.file").length);
			},
			init = function () {

				initViews();
				viewmode();
				initTopSpace();
				initTree();
				linkHoverStates();
				initLangSelector(config.langs);
				localize(config.langs, settings.lang, settings.useBrowserLang);
				formatSizes();
				setTotals();
				initIndicators();
			};

		return {
			settings: settings,
			hash: hash,
			api: api,
			image: image,
			icon: icon,
			shiftTree: shiftTree,
			linkHoverStates: linkHoverStates,
			initIndicators: initIndicators,
			formatDates: formatDates,
			getFileType: getFileType,
			init: init
		};
	}());

}(window, jQuery, H5AI, H5AI_CONFIG));
<|endoftext|>


<commit_before>/* eslint-disable react-native/no-color-literals */
// @flow

import { useNavigation, useIsFocused } from '@react-navigation/native';
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';

import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants';
import { getUnreadPollCount } from '../../functions';
import AbstractPollsPane from '../AbstractPollsPane';
import type { AbstractProps } from '../AbstractPollsPane';

import PollCreate from './PollCreate';
import PollsList from './PollsList';
import { chatStyles } from './styles';

const PollsPane = (props: AbstractProps) => {
    const { createMode, onCreate, setCreateMode, t } = props;
    const isPollsScreenFocused = useIsFocused();
    const navigation = useNavigation();
    const nbUnreadPolls = useSelector(getUnreadPollCount);

    const nrUnreadPolls = !isPollsScreenFocused && nbUnreadPolls > 0
        ? `(${nbUnreadPolls})`
        : '';

    useEffect(() => {
        navigation.setOptions({
            tabBarLabel: `${t('chat.tabs.polls')} ${nrUnreadPolls}`
        });
    }, [ nrUnreadPolls ]);

    return (
        <JitsiScreen
            contentContainerStyle = { chatStyles.pollPane }
            hasTabNavigator = { true }
            style = { chatStyles.pollPaneContainer }>
            {
                createMode
                    ? <PollCreate setCreateMode = { setCreateMode } />
                    : <PollsList />

            }
            {
                !createMode && <Button
                    accessibilityLabel = 'polls.create.create'
                    labelKey = 'polls.create.create'
                    onClick = { onCreate }
                    style = { chatStyles.createPollButton }
                    type = { BUTTON_TYPES.PRIMARY } />
            }
        </JitsiScreen>
    );
};

/*
 * We apply AbstractPollsPane to fill in the AbstractProps common
 * to both the web and native implementations.
 */
// eslint-disable-next-line new-cap
export default AbstractPollsPane(PollsPane);
<commit_msg>feat(polls/native): fixed scroll inside screen<commit_after>/* eslint-disable react-native/no-color-literals */
// @flow

import { useNavigation, useIsFocused } from '@react-navigation/native';
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';

import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants';
import { getUnreadPollCount } from '../../functions';
import AbstractPollsPane from '../AbstractPollsPane';
import type { AbstractProps } from '../AbstractPollsPane';

import PollCreate from './PollCreate';
import PollsList from './PollsList';
import { chatStyles } from './styles';

const PollsPane = (props: AbstractProps) => {
    const { createMode, onCreate, setCreateMode, t } = props;
    const isPollsScreenFocused = useIsFocused();
    const navigation = useNavigation();
    const nbUnreadPolls = useSelector(getUnreadPollCount);

    const nrUnreadPolls = !isPollsScreenFocused && nbUnreadPolls > 0
        ? `(${nbUnreadPolls})`
        : '';

    useEffect(() => {
        navigation.setOptions({
            tabBarLabel: `${t('chat.tabs.polls')} ${nrUnreadPolls}`
        });
    }, [ nrUnreadPolls ]);

    return (
        <JitsiScreen
            contentContainerStyle = { chatStyles.pollPane }
            disableForcedKeyboardDismiss = { !createMode }
            hasTabNavigator = { true }
            style = { chatStyles.pollPaneContainer }>
            {
                createMode
                    ? <PollCreate setCreateMode = { setCreateMode } />
                    : <PollsList />

            }
            {
                !createMode && <Button
                    accessibilityLabel = 'polls.create.create'
                    labelKey = 'polls.create.create'
                    onClick = { onCreate }
                    style = { chatStyles.createPollButton }
                    type = { BUTTON_TYPES.PRIMARY } />
            }
        </JitsiScreen>
    );
};

/*
 * We apply AbstractPollsPane to fill in the AbstractProps common
 * to both the web and native implementations.
 */
// eslint-disable-next-line new-cap
export default AbstractPollsPane(PollsPane);
<|endoftext|>


<commit_before>user_pref("browser.backspace_action", 2);
user_pref("browser.bookmarks.max_backups", 2);
user_pref("browser.gesture.tap", "");
user_pref("browser.tabs.insertRelatedAfterCurrent", false);
user_pref("browser.tabs.selectOwnerOnClose", false);
user_pref("browser.urlbar.clickSelectsAll", false);
user_pref("browser.urlbar.trimURLs", false);
user_pref("devtools.inspector.enabled", true);
user_pref("devtools.inspector.showAllAnonymousContent", false);
user_pref("devtools.styleinspector.enabled", true);
user_pref("dom.popup_maximum", 4);
user_pref("dom.targetBlankNoOpener.enabled", true);
user_pref("extensions.pocket.enabled", false);
user_pref("layout.spellcheckDefault", 2);
user_pref("layout.word_select.eat_space_to_next_word", true);
user_pref("media.autoplay.enabled", false);
user_pref("mousewheel.with_alt.action", 1);
user_pref("mousewheel.with_control.action", 1);
user_pref("mousewheel.with_meta.action", 1);
user_pref("network.dnsCacheEntries", 128);
user_pref("network.dnsCacheExpriation", 3600);
user_pref("network.http.pipelining", true);
user_pref("network.http.pipelining.ssl", true);
user_pref("network.http.proxy.pipelining", true);
user_pref("network.prefetch-next", false);
user_pref("network.protocol-handler.expose.magnet", false);
user_pref("plugins.click_to_play", true);
user_pref("privacy.trackingprotection.enabled", true);
user_pref("services.sync.prefs.sync.lightweightThemes.selectedThemeID", false);
<commit_msg>Disable autoplay in firefox for muted videos.<commit_after>user_pref("browser.backspace_action", 2);
user_pref("browser.bookmarks.max_backups", 2);
user_pref("browser.gesture.tap", "");
user_pref("browser.tabs.insertRelatedAfterCurrent", false);
user_pref("browser.tabs.selectOwnerOnClose", false);
user_pref("browser.urlbar.clickSelectsAll", false);
user_pref("browser.urlbar.trimURLs", false);
user_pref("devtools.inspector.enabled", true);
user_pref("devtools.inspector.showAllAnonymousContent", false);
user_pref("devtools.styleinspector.enabled", true);
user_pref("dom.popup_maximum", 4);
user_pref("dom.targetBlankNoOpener.enabled", true);
user_pref("extensions.pocket.enabled", false);
user_pref("layout.spellcheckDefault", 2);
user_pref("layout.word_select.eat_space_to_next_word", true);
user_pref("media.autoplay.allow-extension-background-pages", false);
user_pref("media.autoplay.allow-muted", false);
user_pref("media.autoplay.block-webaudio", true);
user_pref("media.autoplay.default", 1);
user_pref("media.autoplay.enabled", false);
user_pref("mousewheel.with_alt.action", 1);
user_pref("mousewheel.with_control.action", 1);
user_pref("mousewheel.with_meta.action", 1);
user_pref("network.dnsCacheEntries", 128);
user_pref("network.dnsCacheExpriation", 3600);
user_pref("network.http.pipelining", true);
user_pref("network.http.pipelining.ssl", true);
user_pref("network.http.proxy.pipelining", true);
user_pref("network.prefetch-next", false);
user_pref("network.protocol-handler.expose.magnet", false);
user_pref("plugins.click_to_play", true);
user_pref("privacy.trackingprotection.enabled", true);
user_pref("services.sync.prefs.sync.lightweightThemes.selectedThemeID", false);
<|endoftext|>


<commit_before>(function(window,document,undefined) {
'use strict';

var g = {}; //Globals
g.debug = true; //Debug mode
g.vendors = {
  gist : /https?:\/\/gist.github.com/  //Github gists
};
g.vendorDefault = "readability";
g.baseUrl = g.debug ? '//localhost:8080' : '//review.steamedpears.com';
g.bookmarkletUri =  '/bookmarklet/';
g.vendorUri = g.debug ? '/vendors/' : '/bookmarklet/vendors/';
g.newCodeApi = '/do/newcode';

//Will be the exposed API
var that,
    codeReview;

codeReview = that = {};

function dbg() { if (g.debug) console.log.apply(console,arguments); }

var assetLoader = (function() {
  var assets = {},
      head = document.getElementsByTagName('head')[0];

  var ext_re= /\.[0-9a-zA-Z]+$/; // matches a URL's extension

  /*
   * Create tag that will be appended to head
   * Returns an HTML element
   * Usage:
   *  var tag = createTag("http://example.com/style.css");
   *  var tag = createTag("http://example.com/someJSfile", "js");
   */
  var createTag = function createTag(url, t) {
    var tag, type;

    var matches = url.match(ext_re);
    type = t || matches && matches[0].substr(1) || "default";

    switch (type) {
      case 'css' :
        tag = document.createElement('link');
        tag.type = 'text/css';
        tag.rel = 'stylesheet';
        tag.href = url;
        break;

      case 'js' : // FALLTHROUGH
      case 'javascript' :
        tag = document.createElement('script');
        tag.src = url;
        break;

      default :
        tag = document.createElement('link');
        tag.href = url;
        break;
    }
    return tag;
  };

  var addToHead = function(tag) {
    head.appendChild(tag);
  };

  //API
  return {
    /* Loads assets
     * USAGE :
     * Just load asset
     *  assetLoader.load('//example.ca/st.css');
     *
     * Call callback when loaded
     *  assetLoader.load('//example.ca/script.js',callback)
     */
    load : function (url, callback) {

      if (assets[url]) return;

      var tag = createTag(url);
      dbg("assetLoader.load: ", tag);
      assets[url] = tag;
      if (callback !== undefined) this.runOnLoad(tag, callback);
      addToHead(tag);
    },
    /* Invoke callback when asset is loaded
    * USAGE:
    * runOnLoad(someTag, function() { //do stuff });
    */
    runOnLoad : function (asset, callback) {
      if (asset.readyState){ //IE
        asset.onreadystatechange = function(){
          if (asset.readyState == "loaded" ||asset.readyState == "complete"){
            asset.onreadystatechange = null;
            return callback();
          }
        };
      } else { //W3C
        asset.addEventListener('load',callback);
      }
    }
  };
})();

var helpers = {
  //Figure out if this url uses a known vendor
  vendorGetFromUrl : function(url) {
    var matches,
    regex;

    for (var vendor in g.vendors) {
      regex = g.vendors[vendor];
      matches = regex.test(url);
      if (matches) return vendor;
    }
    return null;
  },
  //Load a given vendor
  vendorLoad: function (vendor, callback) {
    dbg("helpers.vendorLoad: " + vendor);
    assetLoader.load(g.baseUrl + g.vendorUri + vendor + ".js", callback);
  },
  //Cors Request
  Request : function (method, url, type){
    var xhr = new XMLHttpRequest();
    xhr.open(method || 'POST', url, true);
    xhr.setRequestHeader("Content-type", type || "application/json");
    return xhr;
  }
};

//Expose API
that.dbg = dbg;
window.codeReview = that;

//Sketch of what's to come
helpers.vendorLoad("readability", function () {
  var content = that.vendor.getContent();

  var req = new helpers.Request(null,g.baseUrl + g.newCodeApi);

  var obj = JSON.stringify({
    language_id : 1,
    text : content.text
  });
  req.onreadystatechange = function() {
    if (req.readyState === 4){
      console.log(req.responseText);
    }
  };
  req.send(obj);

});

})(window,document);
/* vim: set softtabstop=2 shiftwidth=2 tabstop=8 expandtab textwidth=80: */
<commit_msg>added hasOwnProperty guard<commit_after>(function(window,document,undefined) {
'use strict';

var g = {}; //Globals
g.debug = true; //Debug mode
g.vendors = {
  gist : /https?:\/\/gist.github.com/  //Github gists
};
g.vendorDefault = "readability";
g.baseUrl = g.debug ? '//localhost:8080' : '//review.steamedpears.com';
g.bookmarkletUri =  '/bookmarklet/';
g.vendorUri = g.debug ? '/vendors/' : '/bookmarklet/vendors/';
g.newCodeApi = '/do/newcode';

//Will be the exposed API
var that,
    codeReview;

codeReview = that = {};

function dbg() { if (g.debug) console.log.apply(console,arguments); }

var assetLoader = (function() {
  var assets = {},
      head = document.getElementsByTagName('head')[0];

  var ext_re= /\.[0-9a-zA-Z]+$/; // matches a URL's extension

  /*
   * Create tag that will be appended to head
   * Returns an HTML element
   * Usage:
   *  var tag = createTag("http://example.com/style.css");
   *  var tag = createTag("http://example.com/someJSfile", "js");
   */
  var createTag = function createTag(url, t) {
    var tag, type;

    var matches = url.match(ext_re);
    type = t || matches && matches[0].substr(1) || "default";

    switch (type) {
      case 'css' :
        tag = document.createElement('link');
        tag.type = 'text/css';
        tag.rel = 'stylesheet';
        tag.href = url;
        break;

      case 'js' : // FALLTHROUGH
      case 'javascript' :
        tag = document.createElement('script');
        tag.src = url;
        break;

      default :
        tag = document.createElement('link');
        tag.href = url;
        break;
    }
    return tag;
  };

  var addToHead = function(tag) {
    head.appendChild(tag);
  };

  //API
  return {
    /* Loads assets
     * USAGE :
     * Just load asset
     *  assetLoader.load('//example.ca/st.css');
     *
     * Call callback when loaded
     *  assetLoader.load('//example.ca/script.js',callback)
     */
    load : function (url, callback) {

      if (assets[url]) return;

      var tag = createTag(url);
      dbg("assetLoader.load: ", tag);
      assets[url] = tag;
      if (callback !== undefined) this.runOnLoad(tag, callback);
      addToHead(tag);
    },
    /* Invoke callback when asset is loaded
    * USAGE:
    * runOnLoad(someTag, function() { //do stuff });
    */
    runOnLoad : function (asset, callback) {
      if (asset.readyState){ //IE
        asset.onreadystatechange = function(){
          if (asset.readyState == "loaded" ||asset.readyState == "complete"){
            asset.onreadystatechange = null;
            return callback();
          }
        };
      } else { //W3C
        asset.addEventListener('load',callback);
      }
    }
  };
})();

var helpers = {
  //Figure out if this url uses a known vendor
  vendorGetFromUrl : function(url) {
    var matches,
    regex;

    for (var vendor in g.vendors) {
      if (g.vendors.hasOwnProperty(vendor)) {
        regex = g.vendors[vendor];
        matches = regex.test(url);
        if (matches) return vendor;
      }
    }
    return null;
  },
  //Load a given vendor
  vendorLoad: function (vendor, callback) {
    dbg("helpers.vendorLoad: " + vendor);
    assetLoader.load(g.baseUrl + g.vendorUri + vendor + ".js", callback);
  },
  //Cors Request
  Request : function (method, url, type){
    var xhr = new XMLHttpRequest();
    xhr.open(method || 'POST', url, true);
    xhr.setRequestHeader("Content-type", type || "application/json");
    return xhr;
  }
};

//Expose API
that.dbg = dbg;
window.codeReview = that;

//Sketch of what's to come
helpers.vendorLoad("readability", function () {
  var content = that.vendor.getContent();

  var req = new helpers.Request(null,g.baseUrl + g.newCodeApi);

  var obj = JSON.stringify({
    language_id : 1,
    text : content.text
  });
  req.onreadystatechange = function() {
    if (req.readyState === 4){
      console.log(req.responseText);
    }
  };
  req.send(obj);

});

})(window,document);
/* vim: set softtabstop=2 shiftwidth=2 tabstop=8 expandtab textwidth=80: */
<|endoftext|>


<commit_before>/* ============================================================
 * boot-select.js v2.0.1
 * http://github.com/mitris/boot-select
 * ============================================================ */

!function ($) {
    "use strict"; // jshint ;_;

    var cache = {};
    var Select = function (element, settings) {
        this.element = $(element);
        this.settings = $.extend(true, {}, $.fn.bootSelect.defaults, typeof settings == 'object' && settings, this.element.data());
        this.value = false;
        this.init();
    };

    Select.prototype = {
        constructor: Select,
        init: function () {
            this.visible = false;
            this._generateView();
            this._applySettings();
            this._fixWidth();
            this._updateOptions();
            this._updateSelected();
            this._attachEvents();
        },
        _generateView: function () {
            this.view = $('

');
            this.button = $('');
    		this.text = $('');
            this.current = $('');
            this.placeholder = $('' + this.settings.placeholder + '');
            this.actions = $('');
            this.clearButton = $('' + this.settings.clearButton + '');
            this.toggleButton = $('' + this.settings.toggleButton + '');
            this.dropdown = $('

');
            this.view.append(this.button, this.dropdown);
            this.button.append(this.text, this.actions);
			this.text.append(this.current, this.placeholder);
            this.actions.append(this.clearButton, this.toggleButton);
            this.element.hide().before(this.view);
        },
        _updateOptions: function () {
            var self = this;
            self.options = {};
            self.dropdown.empty();
            self.elementOptionsLength = this.element.get(0).options.length;
            self.element.find('option[value][value!=""]').each(function () {
                var option = $('
' + $(this).text() + '
');
                option.data({
					'button-class': $(this).data('button-class'),
					'current-class': $(this).data('current-class')
				});
				option.addClass($(this).data('li-class'));
				option.find('a').addClass($(this).data('a-class'));
				option.find('span').addClass($(this).data('span-class'));
                self.dropdown.append(option);
                self.options[$(this).val()] = option;
                if ($(this).is(':disabled')) {
                    option.addClass('disabled');
                }
                option.data('value', $(this).val());
            });
            this._scrollToCurrent();
        },
        _updateSelected: function () {
            var currentValue = this._select(this.element.find(':selected'));
            this.settings.onInit.apply(this.element, [currentValue, this]);
        },
        _fixWidth: function() {
            var width = this.button.width() - this.clearButton.outerWidth() - this.toggleButton.outerWidth();
            this.text.width(width);
        },
        _applySettings: function () {
            if (this.element.is(':disabled')) {
                this.button.addClass('disabled')
            }
            if (!this.settings.enableClear) {
                this.clearButton.remove();
            }
            if (this.element.data('class')) {
                this.view.addClass(this.element.data('class'));
            }
            if (!this.button.data('original-class')) {
                this.button.data('original-class', this.button.attr('class'));
            }
            if (!this.current.data('original-class')) {
                this.current.data('original-class', this.current.attr('class'));
            }
        },
        _attachEvents: function () {
            var self = this;
            self.view.on('click.boot-select', function (e) {
                e.stopPropagation();
            });
            self.button.on('click.boot-select', function () {
                self.toggle();
            });
            self.clearButton.on('click.boot-select', function (e) {
                e.stopPropagation();
                self.clear();
            });
            self.dropdown.on('click.boot-select', 'li', function () {
                if (!$(this).hasClass('disabled')) {
                    self.select($(this).data('value'));
                    self.hide();
                }
            });
            self.element.on('change.boot-select', function () {
                self.select(this.value);
            });
            $(window).on('resize.boot-select', function() {
                self._fixWidth();
            });
            if (self.settings.keyboardNavigation) {
                $(document).on('keypress.boot-select', function (e) {
                    if (self.visible && /(13|27|38|40)/.test(e.keyCode)) {
						e.stopPropagation();
						e.preventDefault();
                        if (e.keyCode == 27 || e.keyCode == 13) {
                            self.hide();
                        }
                        if (e.keyCode == 38) {
                            var option = self.element.find('option:selected').prevAll('[value][value!=""]:not(:disabled):first');
                            option.index() >= 0 &&  self.select(option);
                        }
                        if (e.keyCode == 40) {
                            var option = self.element.find('option:selected').nextAll('[value][value!=""]:not(:disabled):first');
                            option.index() >= 0 && self.select(option);
                        }
                    }
                });
            }
        },
        _scrollToCurrent: function () {
            this.dropdown.scrollTop(this.dropdown.find('.active').index() * this.dropdown.find('.active').outerHeight() - this.dropdown.outerHeight() / 2);
        },
        _select: function (value) {
            if (value instanceof jQuery) {
                var option = value;
            } else if (value instanceof HTMLElement) {
                var option = $(value);
            } else {
                var option = this.element.find('option[value="' + value + '"]');
            }
            if (!option.val()) {
                this.clear();
            } else if (option.not(':disabled').prop('selected', true).is('option')) {
                if (this.value) {
                    this.options[this.value].removeClass('active');
                }
                this.value = option.val();
                this.options[this.value].addClass('active');
                this.current.text(this.options[this.value].text()).show();
                this.placeholder.hide();
                this.button.attr('class', this.button.data('original-class'));
                if (this.options[this.value].data('button-class')) {
                    this.button.addClass(this.options[this.value].data('button-class'));
                }
                this.current.attr('class', this.current.data('original-class'));
                if (this.options[this.value].data('current-class')) {
                    this.current.addClass(this.options[this.value].data('current-class'));
                }
            }
            this._scrollToCurrent();
			return this.element.val();
        },
        select: function (value) {
			var currentValue = this._select(value);
            this.settings.onChange.apply(this.element, [currentValue, this]);
        },
        clear: function () {
            var empty = this.element.find('option:not([value])');
            if (empty) {
                empty.prop('selected', true);
            } else {
                this.element.prop('selectedIndex', -1);
            }
            this.dropdown.find('.active').removeClass('active');
            this.current.hide();
            this.placeholder.show();
            this.button.attr('class', this.button.data('original-class'));
            this._scrollToCurrent();
        },
        update: function () {
            return this._updateOptions();
        },
        toggle: function () {
            if (this.button.hasClass('disabled')) {
                return;
            }
            if (this.visible) {
                this.hide();
            } else {
                this.show();
            }
        },
        show: function () {
            var self = this;
            this._scrollToCurrent();
            this.button.addClass('active');
            this.dropdown.show();
            this.visible = true;
            $(document).one('click.boot-select', function (e) {
                self.visible && self.hide();
            });
        },
        hide: function () {
            this._scrollToCurrent();
            this.button.removeClass('active');
            this.dropdown.hide();
            this.visible = false;
        }
    };

    /* PLUGIN DEFINITION */
    $.fn.bootSelect = function (setting) {
        var args = Array.apply(null, arguments);
        args.shift();
        return this.each(function () {
            var $this = $(this), data = $this.data('bootSelect'), settings = typeof setting == 'object' && setting;
            if (!data || typeof data != 'object') {
                $this.data('bootSelect', (data = new Select(this, settings)));
            }
            if (typeof setting == 'string' && typeof data[setting] == 'function' && setting.charAt(0) != '_') {
                return data[setting].apply(data, args);
            } else if (typeof setting == 'string' && typeof data[setting] == 'undefined') {
                jQuery.error("BootSelect: Method \"" + setting + "\" does not exist.");
            }
        });
    };

    $.fn.bootSelect.defaults = {
        enableClear: true,
        keyboardNavigation: true,
        placeholder: 'Выберите из списка',
        clearButton: '×',
        toggleButton: '',
        onInit: function () {
        },
        onChange: function () {
        }
    };

}(window.jQuery);
<commit_msg>v2.0.2 - Integrate nanoScroller<commit_after>/* ============================================================
 * boot-select.js v2.0.2
 * http://github.com/mitris/boot-select
 * ============================================================ */

!function ($) {
    "use strict"; // jshint ;_;

    var cache = {};
    var Select = function (element, settings) {
        this.element = $(element);
        this.settings = $.extend(true, {}, $.fn.bootSelect.defaults, typeof settings == 'object' && settings, this.element.data());
        this.value = false;
        this.init();
    };

    Select.prototype = {
        constructor: Select,
        init: function () {
            this.visible = false;
            this._generateView();
            this._applySettings();
            this._fixWidth();
            this._updateOptions();
            this._updateSelected();
            this._attachEvents();
        },
        _generateView: function () {
            this.view = $('

');
            this.button = $('');
			this.text = $('');
            this.current = $('');
            this.placeholder = $('' + this.settings.placeholder + '');
            this.actions = $('');
            this.clearButton = $('' + this.settings.clearButton + '');
            this.toggleButton = $('' + this.settings.toggleButton + '');
            this.dropdown = $('

');
			this.dropdown_list = this.dropdown.find('ul');
            this.view.append(this.button, this.dropdown);
            this.button.append(this.text, this.actions);
			this.text.append(this.current, this.placeholder);
            this.actions.append(this.clearButton, this.toggleButton);
            this.element.hide().before(this.view);
        },
        _updateOptions: function () {
            var self = this;
            self.options = {};
            self.dropdown_list.empty();
            self.elementOptionsLength = this.element.get(0).options.length;
            self.element.find('option[value][value!=""]').each(function () {
                var option = $('
' + $(this).text() + '
');
                option.data({
					'button-class': $(this).data('button-class'),
					'current-class': $(this).data('current-class')
				});
				option.addClass($(this).data('li-class'));
				option.find('a').addClass($(this).data('a-class'));
				option.find('span').addClass($(this).data('span-class'));
                self.dropdown_list.append(option);
                self.options[$(this).val()] = option;
                if ($(this).is(':disabled')) {
                    option.addClass('disabled');
                }
                option.data('value', $(this).val());
            });
			this._fixHeight();
            this._scrollToCurrent();
        },
        _updateSelected: function () {
            var currentValue = this._select(this.element.find(':selected'));
            this.settings.onInit.apply(this.element, [currentValue, this]);
        },
        _fixWidth: function() {
            var width = this.button.width() - this.clearButton.outerWidth() - this.toggleButton.outerWidth();
            this.text.width(width);
        },
        _fixHeight: function() {
			var li = this.dropdown_list.find('li'), items = li.size() <= 5 ? li.size(): 5;
			this.dropdown.height(items * li.outerHeight());
        },
        _applySettings: function () {
            if (this.element.is(':disabled')) {
                this.button.addClass('disabled')
            }
            if (!this.settings.enableClear) {
                this.clearButton.remove();
            }
            if (this.element.data('class')) {
                this.view.addClass(this.element.data('class'));
            }
            if (!this.button.data('original-class')) {
                this.button.data('original-class', this.button.attr('class'));
            }
            if (!this.current.data('original-class')) {
                this.current.data('original-class', this.current.attr('class'));
            }
        },
        _attachEvents: function () {
            var self = this;
            self.view.on('click.boot-select', function (e) {
                e.stopPropagation();
            });
            self.button.on('click.boot-select', function () {
                self.toggle();
            });
            self.clearButton.on('click.boot-select', function (e) {
                e.stopPropagation();
                self.clear();
            });
            self.dropdown.on('click.boot-select', 'li', function () {
                if (!$(this).hasClass('disabled')) {
                    self.select($(this).data('value'));
                    self.hide();
                }
            });
            self.element.on('change.boot-select', function () {
                self.select(this.value);
            });
            $(window).on('resize.boot-select', function() {
                self._fixWidth();
            });
            if (self.settings.keyboardNavigation) {
                $(document).on('keypress.boot-select', function (e) {
                    if (self.visible && /(13|27|38|40)/.test(e.keyCode)) {
						e.stopPropagation();
						e.preventDefault();
                        if (e.keyCode == 27 || e.keyCode == 13) {
                            self.hide();
                        }
                        if (e.keyCode == 38) {
                            var option = self.element.find('option:selected').prevAll('[value][value!=""]:not(:disabled):first');
                            option.index() >= 0 &&  self.select(option);
                        }
                        if (e.keyCode == 40) {
                            var option = self.element.find('option:selected').nextAll('[value][value!=""]:not(:disabled):first');
                            option.index() >= 0 && self.select(option);
                        }
                    }
                });
            }
        },
        _scrollToCurrent: function () {
            this.dropdown.scrollTop(this.dropdown.find('.active').index() * this.dropdown.find('.active').outerHeight() - this.dropdown.outerHeight() / 2);
        },
        _select: function (value) {
            if (value instanceof jQuery) {
                var option = value;
            } else if (value instanceof HTMLElement) {
                var option = $(value);
            } else {
                var option = this.element.find('option[value="' + value + '"]');
            }
            if (!option.val()) {
                this.clear();
            } else if (option.not(':disabled').prop('selected', true).is('option')) {
                if (this.value) {
                    this.options[this.value].removeClass('active');
                }
                this.value = option.val();
                this.options[this.value].addClass('active');
                this.current.text(this.options[this.value].text()).show();
                this.placeholder.hide();
                this.button.attr('class', this.button.data('original-class'));
                if (this.options[this.value].data('button-class')) {
                    this.button.addClass(this.options[this.value].data('button-class'));
                }
                this.current.attr('class', this.current.data('original-class'));
                if (this.options[this.value].data('current-class')) {
                    this.current.addClass(this.options[this.value].data('current-class'));
                }
            }
            this._scrollToCurrent();
			return this.element.val();
        },
        select: function (value) {
			var currentValue = this._select(value);
            this.settings.onChange.apply(this.element, [currentValue, this]);
        },
        clear: function () {
            var empty = this.element.find('option:not([value])');
            if (empty) {
                empty.prop('selected', true);
            } else {
                this.element.prop('selectedIndex', -1);
            }
            this.dropdown.find('.active').removeClass('active');
            this.current.hide();
            this.placeholder.show();
            this.button.attr('class', this.button.data('original-class'));
            this._scrollToCurrent();
        },
        update: function () {
            return this._updateOptions();
        },
        toggle: function () {
            if (this.button.hasClass('disabled')) {
                return;
            }
            if (this.visible) {
                this.hide();
            } else {
                this.show();
            }
        },
        show: function () {
            var self = this;
            this._scrollToCurrent();
            this.button.addClass('active');
            this.dropdown.css('visibility', 'visible').show();
            this.visible = true;
			if('undefined' != typeof $.fn.nanoScroller) {
				this.dropdown.find('.nano').nanoScroller({
					iOSNativeScrolling: true,
					preventPageScrolling: true
				});
			}
            $(document).one('click.boot-select', function (e) {
                self.visible && self.hide();
            });
        },
        hide: function () {
            this._scrollToCurrent();
            this.button.removeClass('active');
            this.dropdown.css('visibility', 'hidden').hide();
            this.visible = false;
        }
    };

    /* PLUGIN DEFINITION */
    $.fn.bootSelect = function (setting) {
        var args = Array.apply(null, arguments);
        args.shift();
        return this.each(function () {
            var $this = $(this), data = $this.data('bootSelect'), settings = typeof setting == 'object' && setting;
            if (!data || typeof data != 'object') {
                $this.data('bootSelect', (data = new Select(this, settings)));
            }
            if (typeof setting == 'string' && typeof data[setting] == 'function' && setting.charAt(0) != '_') {
                return data[setting].apply(data, args);
            } else if (typeof setting == 'string' && typeof data[setting] == 'undefined') {
                jQuery.error("BootSelect: Method \"" + setting + "\" does not exist.");
            }
        });
    };

    $.fn.bootSelect.defaults = {
        enableClear: true,
        keyboardNavigation: true,
        placeholder: 'Выберите из списка',
        clearButton: '×',
        toggleButton: '',
        onInit: function () {
        },
        onChange: function () {
        }
    };

}(window.jQuery);
<|endoftext|>


<commit_before>;
(function(angular) {
  var indexOf = [].indexOf || function(item) {
    for (var i = 0, l = this.length; i < l; i++) {
      if (i in this && this[i] === item) return i;
    }
    return -1;
  };

  angular.module('pickadate.utils', [])
    .factory('pickadateUtils', ['dateFilter',
      function(dateFilter) {
        return {
          isDate: function(obj) {
            return Object.prototype.toString.call(obj) === '[object Date]';
          },

          stringToDate: function(dateString) {
            if (this.isDate(dateString)) return new Date(dateString);
            var dateParts = dateString.split('-'),
              year = dateParts[0],
              month = dateParts[1],
              day = dateParts[2];

            // set hour to 3am to easily avoid DST change
            return new Date(year, month - 1, day, 3);
          },

          dateRange: function(first, last, initial, format) {
            var date, i, _i, dates = [];

            if (!format) format = 'yyyy-MM-dd';

            for (i = _i = first; first <= last ? _i < last : _i > last; i = first <= last ? ++_i : --_i) {
              date = this.stringToDate(initial);
              date.setDate(date.getDate() + i);
              dates.push(dateFilter(date, format));
            }
            return dates;
          }
        };
      }
    ]);

  angular.module('pickadate', ['pickadate.utils'])

  .directive('type', ['$compile', '$timeout',
    function($compile, $timeout) {

      return function($scope, $element, attrs) {
        if (attrs.type !== 'date' || /chrome|ipad/i.test(navigator.userAgent)) {
          return angular.noop;
        }
        var datePickerTemp = '

'
        var $div = angular.element(datePickerTemp);

        angular.element(document.body).append($div);

        $compile($div)($scope);

        setPosition();

        angular.element(window).on('resize', function(){
          setPosition();
        });

        $element.on('click', function(ev) {
          ev.stopPropagation();

          $timeout(function() {
              $scope.dateShow = !$scope.dateShow;
            }, 0);
        });

        angular.element(document).on('click', function(ev){
          $timeout(function() {
              $scope.dateShow = false;
            }, 0);
        });

        function setPosition(){
          var offset = tools.offset($element[0], window);
          var top = (offset.top+$element[0].offsetHeight+2)+'px';
          var left = offset.left+'px';

          $div.css({ left: left, top: top });
        }
      }
    }
  ])
    .directive('pickadate', ['$locale', 'pickadateUtils', 'dateFilter', '$compile',
      function($locale, dateUtils, dateFilter, $compile) {

        return {
          require: 'ngModel',
          scope: {
            date: '=ngModel',
            minDate: '=',
            maxDate: '=',
            disabledDates: '='
          },
          template: '
' +
            '
' +
            '
' +
            '上月' +
            '下月' +
            '
' +
            '
' +
            '{{currentDate | date:"MM yyyy"}}' +
            '
' +
            '
' +
            '
' +
            '
' +
            '
' +
            '
' +
            '{{dayName}}' +
            '
' +
            '
' +
            '
' +
            '
' +
            '{{d.date | date:"d"}}' +
            '
' +
            '
' +
            '
' +
            '
' +
            '
',

          link: function(scope, element, attrs, ngModel) {
            var minDate = scope.minDate && dateUtils.stringToDate(scope.minDate),
              maxDate = scope.maxDate && dateUtils.stringToDate(scope.maxDate),
              disabledDates = scope.disabledDates || [],
              currentDate = new Date();

            // scope.dayNames = $locale.DATETIME_FORMATS['SHORTDAY'];
            scope.dayNames = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
            scope.currentDate = currentDate;

            scope.render = function(initialDate) {

              initialDate = new Date(initialDate.getFullYear(), initialDate.getMonth(), 1, 3);

              var currentMonth = initialDate.getMonth() + 1;
              var dayCount = new Date(initialDate.getFullYear(), initialDate.getMonth() + 1, 0, 3).getDate();

              var prevDates = dateUtils.dateRange(-initialDate.getDay(), 0, initialDate);
              var currentMonthDates = dateUtils.dateRange(0, dayCount, initialDate);

              var lastDate = dateUtils.stringToDate(currentMonthDates[currentMonthDates.length - 1]);
              var nextMonthDates = dateUtils.dateRange(1, 7 - lastDate.getDay(), lastDate);
              var allDates = prevDates.concat(currentMonthDates, nextMonthDates);
              var dates = [];
              var today = dateFilter(new Date(), 'yyyy-MM-dd');

              // Add an extra row if needed to make the calendar to have 6 rows
              if (allDates.length / 7 < 6) {
                allDates = allDates.concat(dateUtils.dateRange(1, 8, allDates[allDates.length - 1]));
              }

              var nextMonthInitialDate = new Date(initialDate);
              nextMonthInitialDate.setMonth(currentMonth);

              scope.allowPrevMonth = !minDate || initialDate > minDate;
              scope.allowNextMonth = !maxDate || nextMonthInitialDate < maxDate;

              for (var i = 0; i < allDates.length; i++) {
                var className = "",
                  date = allDates[i];

                if (date < scope.minDate || date > scope.maxDate || dateFilter(date, 'M') !== currentMonth.toString()) {
                  className = 'pickadate-disabled';
                } else if (indexOf.call(disabledDates, date) >= 0) {
                  className = 'pickadate-disabled pickadate-unavailable';
                } else {
                  className = 'pickadate-enabled';
                }

                if (date === today) {
                  className += ' pickadate-today';
                }

                dates.push({
                  date: date,
                  className: className
                });
              }

              scope.dates = dates;
            };

            scope.setDate = function(dateObj) {

              if (isDateDisabled(dateObj)) return;
              ngModel.$setViewValue(dateObj.date);
            };

            ngModel.$render = function() {
              // console.log(ngModel)
              if ((date = ngModel.$modelValue) && (indexOf.call(disabledDates, date) === -1)) {
                scope.currentDate = currentDate = dateUtils.stringToDate(date);
              } else if (date) {
                // if the initial date set by the user is in the disabled dates list, unset it
                scope.setDate({});
              }
              scope.render(currentDate);
            };

            scope.changeMonth = function(offset) {
              // If the current date is January 31th, setting the month to date.getMonth() + 1
              // sets the date to March the 3rd, since the date object adds 30 days to the current
              // date. Settings the date to the 2nd day of the month is a workaround to prevent this
              // behaviour
              currentDate.setDate(1);
              currentDate.setMonth(currentDate.getMonth() + offset);
              scope.render(currentDate);
            };

            function isDateDisabled(dateObj) {
              return (/pickadate-disabled/.test(dateObj.className));
            }
          }
        };
      }
    ]);
})(window.angular);<commit_msg>first<commit_after>;
(function(angular) {
  var indexOf = [].indexOf || function(item) {
    for (var i = 0, l = this.length; i < l; i++) {
      if (i in this && this[i] === item) return i;
    }
    return -1;
  };

  angular.module('pickadate.utils', [])
    .factory('pickadateUtils', ['dateFilter',
      function(dateFilter) {
        return {
          isDate: function(obj) {
            return Object.prototype.toString.call(obj) === '[object Date]';
          },

          stringToDate: function(dateString) {
            if (this.isDate(dateString)) return new Date(dateString);
            var dateParts = dateString.split('-'),
              year = dateParts[0],
              month = dateParts[1],
              day = dateParts[2];

            // set hour to 3am to easily avoid DST change
            return new Date(year, month - 1, day, 3);
          },

          dateRange: function(first, last, initial, format) {
            var date, i, _i, dates = [];

            if (!format) format = 'yyyy-MM-dd';

            for (i = _i = first; first <= last ? _i < last : _i > last; i = first <= last ? ++_i : --_i) {
              date = this.stringToDate(initial);
              date.setDate(date.getDate() + i);
              dates.push(dateFilter(date, format));
            }
            return dates;
          }
        };
      }
    ]);

  angular.module('pickadate', ['pickadate.utils'])

  .directive('type', ['$compile', '$timeout',
    function($compile, $timeout) {

      return function($scope, $element, attrs) {
        if (attrs.type !== 'date' || /chrome|ipad|iphone/i.test(navigator.userAgent)) {
          return angular.noop;
        }
        var datePickerTemp = '

'
        var $div = angular.element(datePickerTemp);

        angular.element(document.body).append($div);

        $compile($div)($scope);

        setPosition();

        angular.element(window).on('resize', function(){
          setPosition();
        });

        $element.on('click', function(ev) {
          ev.stopPropagation();

          $timeout(function() {
              $scope.dateShow = !$scope.dateShow;
            }, 0);
        });

        angular.element(document).on('click', function(ev){
          $timeout(function() {
              $scope.dateShow = false;
            }, 0);
        });

        function setPosition(){
          var offset = tools.offset($element[0], window);
          var top = (offset.top+$element[0].offsetHeight+2)+'px';
          var left = offset.left+'px';

          $div.css({ left: left, top: top });
        }
      }
    }
  ])
    .directive('pickadate', ['$locale', 'pickadateUtils', 'dateFilter', '$compile',
      function($locale, dateUtils, dateFilter, $compile) {

        return {
          require: 'ngModel',
          scope: {
            date: '=ngModel',
            minDate: '=',
            maxDate: '=',
            disabledDates: '='
          },
          template: '
' +
            '
' +
            '
' +
            '上月' +
            '下月' +
            '
' +
            '
' +
            '{{currentDate | date:"MM yyyy"}}' +
            '
' +
            '
' +
            '
' +
            '
' +
            '
' +
            '
' +
            '{{dayName}}' +
            '
' +
            '
' +
            '
' +
            '
' +
            '{{d.date | date:"d"}}' +
            '
' +
            '
' +
            '
' +
            '
' +
            '
',

          link: function(scope, element, attrs, ngModel) {
            var minDate = scope.minDate && dateUtils.stringToDate(scope.minDate),
              maxDate = scope.maxDate && dateUtils.stringToDate(scope.maxDate),
              disabledDates = scope.disabledDates || [],
              currentDate = new Date();

            // scope.dayNames = $locale.DATETIME_FORMATS['SHORTDAY'];
            scope.dayNames = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
            scope.currentDate = currentDate;

            scope.render = function(initialDate) {

              initialDate = new Date(initialDate.getFullYear(), initialDate.getMonth(), 1, 3);

              var currentMonth = initialDate.getMonth() + 1;
              var dayCount = new Date(initialDate.getFullYear(), initialDate.getMonth() + 1, 0, 3).getDate();

              var prevDates = dateUtils.dateRange(-initialDate.getDay(), 0, initialDate);
              var currentMonthDates = dateUtils.dateRange(0, dayCount, initialDate);

              var lastDate = dateUtils.stringToDate(currentMonthDates[currentMonthDates.length - 1]);
              var nextMonthDates = dateUtils.dateRange(1, 7 - lastDate.getDay(), lastDate);
              var allDates = prevDates.concat(currentMonthDates, nextMonthDates);
              var dates = [];
              var today = dateFilter(new Date(), 'yyyy-MM-dd');

              // Add an extra row if needed to make the calendar to have 6 rows
              if (allDates.length / 7 < 6) {
                allDates = allDates.concat(dateUtils.dateRange(1, 8, allDates[allDates.length - 1]));
              }

              var nextMonthInitialDate = new Date(initialDate);
              nextMonthInitialDate.setMonth(currentMonth);

              scope.allowPrevMonth = !minDate || initialDate > minDate;
              scope.allowNextMonth = !maxDate || nextMonthInitialDate < maxDate;

              for (var i = 0; i < allDates.length; i++) {
                var className = "",
                  date = allDates[i];

                if (date < scope.minDate || date > scope.maxDate || dateFilter(date, 'M') !== currentMonth.toString()) {
                  className = 'pickadate-disabled';
                } else if (indexOf.call(disabledDates, date) >= 0) {
                  className = 'pickadate-disabled pickadate-unavailable';
                } else {
                  className = 'pickadate-enabled';
                }

                if (date === today) {
                  className += ' pickadate-today';
                }

                dates.push({
                  date: date,
                  className: className
                });
              }

              scope.dates = dates;
            };

            scope.setDate = function(dateObj) {

              if (isDateDisabled(dateObj)) return;
              ngModel.$setViewValue(dateObj.date);
            };

            ngModel.$render = function() {
              // console.log(ngModel)
              if ((date = ngModel.$modelValue) && (indexOf.call(disabledDates, date) === -1)) {
                scope.currentDate = currentDate = dateUtils.stringToDate(date);
              } else if (date) {
                // if the initial date set by the user is in the disabled dates list, unset it
                scope.setDate({});
              }
              scope.render(currentDate);
            };

            scope.changeMonth = function(offset) {
              // If the current date is January 31th, setting the month to date.getMonth() + 1
              // sets the date to March the 3rd, since the date object adds 30 days to the current
              // date. Settings the date to the 2nd day of the month is a workaround to prevent this
              // behaviour
              currentDate.setDate(1);
              currentDate.setMonth(currentDate.getMonth() + offset);
              scope.render(currentDate);
            };

            function isDateDisabled(dateObj) {
              return (/pickadate-disabled/.test(dateObj.className));
            }
          }
        };
      }
    ]);
})(window.angular);<|endoftext|>