<commit_before>/* https://github.com/vufind-org/autocomplete.js 1.0b2 */
(function autocomplete($) {
  var element = false,
    xhr = false;

  function Factory(_input, settings) {
    return function acClosure() {
      var input = $(this),
        cache = {},
        options;

      var _align = function _align() {
        var position = input.offset();
        element.css({
          top: position.top + input.outerHeight(),
          left: position.left,
          minWidth: input.width()
        });
      };

      var show = function show() {
        element.removeClass(options.hidingClass);
      };
      var hide = function hide() {
        element.addClass(options.hidingClass);
      };

      var _populate = function _populate(item, eventType) {
        input.trigger('ac:select', [item, eventType]);
        var ret;
        if (options.callback) {
          ret = options.callback(item, input, eventType);
          if (ret === true && typeof item.href !== 'undefined') {
            return window.location.assign(item.href);
          }
          if (ret === false) {
            return false;
          }
        } else if (typeof item.href !== 'undefined') {
          return window.location.assign(item.href);
        }
        input.val(typeof ret === 'undefined' ? item.value : ret);
        // Reset
        element.find('.ac-item.selected').removeClass('selected');
        $(this).data('ac-selected', -1);
        setTimeout(function acPopulateDelay() {
          input.focus();
          hide();
        }, 10);
      };

      var _listToHTML = function _listToHTML(list, regex) {
        var shell = $('
');
        for (var i = 0; i < list.length; i++) {
          if (typeof list[i] === 'string') {
            list[i] = { value: list[i] };
          }
          var content = list[i].label || list[i].value;
          if (options.highlight) {
            content = content.replace(regex, '$1');
          }
          var item = typeof list[i].href === 'undefined' ? $('
') : $('').attr('href', list[i].href);
          // list
          item
            .data(list[i])
            .addClass('ac-item')
            .html(content);
          if (typeof list[i].description !== 'undefined') {
            item.append(
              $('').html(
                options.highlight ? list[i].description.replace(regex, '$1') : list[i].description
              )
            );
          }
          shell.append(item);
        }
        input.trigger('ac:render', [shell[0]]);
        return shell;
      };
      var _createList = function _createList(data) {
        // highlighting setup
        // escape term for regex - https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js
        var escapedTerm = input.val().replace(/[|\\{}()\[\]\^$+*?.]/g, '\\$&');
        var regex = new RegExp('(' + escapedTerm + ')', 'ig');
        var shell;
        if (typeof data.groups === 'undefined') {
          shell = _listToHTML(data, regex);
        } else {
          shell = $('
');
          for (var i = 0; i < data.groups.length; i++) {
            if (typeof data.groups[i].label !== 'undefined' || i > 0) {
              shell.append($('
', { class: 'ac-section-divider' }));
            }
            if (typeof data.groups[i].label !== 'undefined') {
              shell.append(
                $('', {
                  class: 'ac-section-header',
                  html: data.groups[i].label
                })
              );
            }
            if (typeof data.groups[i].label !== 'undefined' && data.groups[i].items.length > 0) {
              shell.append(_listToHTML(data.groups[i].items, regex));
            } else if (data.groups[i].length > 0) {
              shell.append(_listToHTML(data.groups[i], regex));
            }
          }
        }
        element.html(shell);
        input.data('ac-length', shell.find('.ac-item').length);
        element.find('.ac-item').mousedown(function acItemClick() {
          _populate($(this).data(), { mouse: true });
        });
        _align();
      };

      var _handleResults = function _handleResults(term, _data) {
        // Limit results
        var data =
          typeof _data.groups === 'undefined'
            ? _data.slice(0, Math.min(options.maxResults, _data.length))
            : _data;
        var cid = input.data('cacheId');
        cache[cid][term] = data;
        if (data.length === 0 || (typeof data.groups !== 'undefined' && data.groups.length === 0)) {
          hide();
        } else {
          _createList(data);
        }
      };
      var _defaultStaticSort = function _defaultStaticSort(a, b) {
        // .bind(lcterm)
        return a.match.indexOf(this) - b.match.indexOf(this);
      };
      var _staticGroups = function _staticGroups(lcterm) {
        var matches = [];
        for (var i = 0; i < options.static.groups.length; i++) {
          if (typeof options.static.groups[i].label !== 'undefined') {
            var mitems = options.static.groups[i].items.filter(function staticLabelledGroupFilter(_item) {
              return _item.match.match(lcterm);
            });
            if (mitems.length > 0) {
              if (typeof options.staticSort === 'function') {
                mitems.sort(options.staticSort);
              } else {
                mitems.sort(_defaultStaticSort.bind(lcterm));
              }
              matches.push({
                label: options.static.groups[i].label,
                items: mitems
              });
            }
          } else {
            var ms = options.static.groups[i].filter(function staticGroupFilter(_item) {
              return _item.match.match(lcterm);
            });
            if (ms.length > 0) {
              if (typeof options.staticSort === 'function') {
                ms.sort(options.staticSort);
              } else {
                ms.sort(_defaultStaticSort.bind(lcterm));
              }
              matches.push(ms);
            }
          }
        }
        return matches;
      };
      var search = function search() {
        if (xhr) {
          xhr.abort();
        }
        if (input.val().length >= options.minLength) {
          element.html('' + options.loadingString + '');
          show();
          _align();
          input.data('ac-selected', -1);
          var term = input.val();
          // Check cache (only for handler-based setups)
          var cid = input.data('cacheId');
          if (options.cache && typeof cache[cid][term] !== 'undefined') {
            if (cache[cid][term].length === 0) {
              hide();
            } else {
              _createList(cache[cid][term]);
            }
            // Check for static list
          } else if (typeof options.static !== 'undefined') {
            var lcterm = term.toLowerCase();
            var matches;
            if (typeof options.static.groups !== 'undefined') {
              matches = { groups: _staticGroups(lcterm) };
            } else {
              matches = options.static.filter(function staticFilter(_item) {
                return _item.match.match(lcterm);
              });
              if (typeof options.staticSort === 'function') {
                matches.sort(options.staticSort);
              } else {
                matches.sort(_defaultStaticSort.bind(lcterm));
              }
            }
            _handleResults(term, matches);
            // Call handler
          } else {
            options.handler(input, function achandlerCallback(data) {
              _handleResults(term, data);
            });
          }
        } else {
          hide();
        }
      };

      function preprocessStatic(_item) {
        var item = typeof _item === 'string' ? { value: _item } : _item;
        item.match = (item.label || item.value).toLowerCase();
        return item;
      }
      var _setup = function _setup() {
        element = $('.autocomplete-results');
        if (element.length === 0) {
          element = $('
')
            .addClass('autocomplete-results ' + options.hidingClass)
            .html('' + options.loadingString + '');
          _align();
          $(document.body).append(element);
        }

        input.data('ac-selected', -1);
        input.data('ac-length', 0);

        if (options.cache) {
          var cid = Math.floor(Math.random() * 1000);
          input.data('cacheId', cid);
          cache[cid] = {};
        }

        input.blur(function acinputBlur(e) {
          if (e.target.acitem) {
            setTimeout(hide, 10);
          } else {
            hide();
          }
        });
        input.click(function acinputClick() {
          search();
        });
        input.focus(function acinputFocus() {
          search();
        });
        input.on('paste', function acinputPaste() {
          requestAnimationFrame(search);
        });
        input.keyup(function acinputKeyup(event) {
          // Ignore navigation keys
          // - Ignore control functions
          if (event.ctrlKey || event.which === 17) {
            return;
          }
          // - Function keys (F1 - F15)
          if (112 <= event.which && event.which <= 126) {
            return;
          }
          switch (event.which) {
            case 9: // tab
            case 13: // enter
            case 16: // shift
            case 20: // caps lock
            case 27: // esc
            case 33: // page up
            case 34: // page down
            case 35: // end
            case 36: // home
            case 37: // arrows
            case 38:
            case 39:
            case 40:
            case 45: // insert
            case 144: // num lock
            case 145: // scroll lock
            case 19: // pause/break
              return;
            default:
              search();
          }
        });
        input.keydown(function acinputKeydown(event) {
          // - Ignore control functions
          if (event.ctrlKey || event.which === 17) {
            return;
          }
          var position = $(this).data('ac-selected');
          switch (event.which) {
            // arrow keys through items
            case 38: // up key
              event.preventDefault();
              element.find('.ac-item.selected').removeClass('selected');
              if (position > -1) {
                if (position-- > 0) {
                  element.find('.ac-item:eq(' + position + ')').addClass('selected');
                }
                $(this).data('ac-selected', position);
              }
              break;
            case 40: // down key
              event.preventDefault();
              if (element.hasClass(options.hidingClass)) {
                search();
              } else if (position < input.data('ac-length') - 1) {
                position++;
                element.find('.ac-item.selected').removeClass('selected');
                element.find('.ac-item:eq(' + position + ')').addClass('selected');
                $(this).data('ac-selected', position);
              }
              break;
            // enter to nav or populate
            case 9:
            case 13:
              var selected = element.find('.ac-item.selected');
              if (selected.length > 0) {
                event.preventDefault();
                if (event.which === 13 && selected.attr('href') && options.callback === 'undefined') {
                  return window.location.assign(selected.attr('href'));
                } else {
                  _populate(selected.data(), $(this), { key: true });
                }
              }
              break;
            // hide on escape
            case 27:
              hide();
              $(this).data('ac-selected', -1);
              break;
          }
        });

        window.addEventListener('resize', hide, false);
      };

      if (typeof settings === 'string') {
        if (settings === 'show') {
          show();
          _align();
        } else if (settings === 'hide') {
          hide();
        } else if (options.cache && settings === 'clear cache') {
          var cid = parseInt(input.data('cacheId'), 10);
          console.log(JSON.encode(cache[cid]));
          cache[cid] = {};
          console.log(JSON.encode(cache[cid]));
        }
        return input;
      } else if (typeof settings.handler === 'undefined' && typeof settings.static === 'undefined') {
        console.error('Neither handler function nor static result list provided for autocomplete');
        return input;
      } else {
        if (typeof settings.static !== 'undefined') {
          // Preprocess strings into items
          if (typeof settings.static.groups !== 'undefined') {
            for (var i = 0; i < settings.static.groups.length; i++) {
              if (typeof settings.static.groups[i].label !== 'undefined') {
                settings.static.groups[i].items = settings.static.groups[i].items.map(preprocessStatic);
              } else {
                settings.static.groups[i] = settings.static.groups[i].map(preprocessStatic);
              }
            }
          } else {
            settings.static = settings.static.map(preprocessStatic);
          }
        }
        options = $.extend({}, $.fn.autocomplete.defaults, settings);
        _setup();
      }

      return item;
    }.bind(_input)();
  }

  $.fn.autocomplete = function acJQuery(settings) {
    return this.each(function acJQueryEach() {
      return Factory(this, settings);
    });
  };

  $.fn.autocomplete.defaults = {
    cache: true,
    hidingClass: 'hidden',
    highlight: true,
    loadingString: 'Loading...',
    maxResults: 20,
    minLength: 3
  };

  var timer = false;
  $.fn.autocomplete.ajax = function acAjax(ops) {
    if (timer) {
      clearTimeout(timer);
    }
    if (xhr) {
      xhr.abort();
    }
    timer = setTimeout(function acajaxDelay() {
      xhr = $.ajax(ops);
    }, 200);
  };
})(jQuery);
<commit_msg>Always add a data id (ac-id). Persistent options. Return object with common functions.<commit_after>/* https://github.com/vufind-org/autocomplete.js 1.0b2 */
(function autocomplete($) {
  var element = false,
    cache = {},
    optionStorage = {},
    xhr = false;

  function Factory(_input, settings) {
    return function acClosure() {
      var input = $(this);
      var options = optionStorage[input.data('ac-id')];

      var _align = function _align() {
        var position = input.offset();
        element.css({
          top: position.top + input.outerHeight(),
          left: position.left,
          minWidth: input.width()
        });
      };

      var show = function show() {
        element.removeClass(options.hidingClass);
      };
      var hide = function hide() {
        element.addClass(options.hidingClass);
      };

      var _populate = function _populate(item, eventType) {
        input.trigger('ac:select', [item, eventType]);
        var ret;
        if (options.callback) {
          ret = options.callback(item, input, eventType);
          if (ret === true && typeof item.href !== 'undefined') {
            return window.location.assign(item.href);
          }
          if (ret === false) {
            return false;
          }
        } else if (typeof item.href !== 'undefined') {
          return window.location.assign(item.href);
        }
        input.val(typeof ret === 'undefined' ? item.value : ret);
        // Reset
        element.find('.ac-item.selected').removeClass('selected');
        $(this).data('ac-selected', -1);
        setTimeout(function acPopulateDelay() {
          input.focus();
          hide();
        }, 10);
      };

      var _listToHTML = function _listToHTML(list, regex) {
        var shell = $('
');
        for (var i = 0; i < list.length; i++) {
          if (typeof list[i] === 'string') {
            list[i] = { value: list[i] };
          }
          var content = list[i].label || list[i].value;
          if (options.highlight) {
            content = content.replace(regex, '$1');
          }
          var item = typeof list[i].href === 'undefined' ? $('
') : $('').attr('href', list[i].href);
          // list
          item
            .data(list[i])
            .addClass('ac-item')
            .html(content);
          if (typeof list[i].description !== 'undefined') {
            item.append(
              $('').html(
                options.highlight ? list[i].description.replace(regex, '$1') : list[i].description
              )
            );
          }
          shell.append(item);
        }
        input.trigger('ac:render', [shell[0]]);
        return shell;
      };
      var _createList = function _createList(data) {
        // highlighting setup
        // escape term for regex - https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js
        var escapedTerm = input.val().replace(/[|\\{}()\[\]\^$+*?.]/g, '\\$&');
        var regex = new RegExp('(' + escapedTerm + ')', 'ig');
        var shell;
        if (typeof data.groups === 'undefined') {
          shell = _listToHTML(data, regex);
        } else {
          shell = $('
');
          for (var i = 0; i < data.groups.length; i++) {
            if (typeof data.groups[i].label !== 'undefined' || i > 0) {
              shell.append($('
', { class: 'ac-section-divider' }));
            }
            if (typeof data.groups[i].label !== 'undefined') {
              shell.append(
                $('', {
                  class: 'ac-section-header',
                  html: data.groups[i].label
                })
              );
            }
            if (typeof data.groups[i].label !== 'undefined' && data.groups[i].items.length > 0) {
              shell.append(_listToHTML(data.groups[i].items, regex));
            } else if (data.groups[i].length > 0) {
              shell.append(_listToHTML(data.groups[i], regex));
            }
          }
        }
        element.html(shell);
        input.data('ac-length', shell.find('.ac-item').length);
        element.find('.ac-item').mousedown(function acItemClick() {
          _populate($(this).data(), { mouse: true });
        });
        _align();
      };

      var _handleResults = function _handleResults(term, _data) {
        // Limit results
        var data =
          typeof _data.groups === 'undefined'
            ? _data.slice(0, Math.min(options.maxResults, _data.length))
            : _data;
        var cid = input.data('ac-id');
        cache[cid][term] = data;
        if (data.length === 0 || (typeof data.groups !== 'undefined' && data.groups.length === 0)) {
          hide();
        } else {
          _createList(data);
        }
      };
      var _defaultStaticSort = function _defaultStaticSort(a, b) {
        // .bind(lcterm)
        return a.match.indexOf(this) - b.match.indexOf(this);
      };
      var _staticGroups = function _staticGroups(lcterm) {
        var matches = [];
        for (var i = 0; i < options.static.groups.length; i++) {
          if (typeof options.static.groups[i].label !== 'undefined') {
            var mitems = options.static.groups[i].items.filter(function staticLabelledGroupFilter(_item) {
              return _item.match.match(lcterm);
            });
            if (mitems.length > 0) {
              if (typeof options.staticSort === 'function') {
                mitems.sort(options.staticSort);
              } else {
                mitems.sort(_defaultStaticSort.bind(lcterm));
              }
              matches.push({
                label: options.static.groups[i].label,
                items: mitems
              });
            }
          } else {
            var ms = options.static.groups[i].filter(function staticGroupFilter(_item) {
              return _item.match.match(lcterm);
            });
            if (ms.length > 0) {
              if (typeof options.staticSort === 'function') {
                ms.sort(options.staticSort);
              } else {
                ms.sort(_defaultStaticSort.bind(lcterm));
              }
              matches.push(ms);
            }
          }
        }
        return matches;
      };
      var search = function search() {
        if (xhr) {
          xhr.abort();
        }
        if (input.val().length >= options.minLength) {
          element.html('' + options.loadingString + '');
          show();
          _align();
          input.data('ac-selected', -1);
          var term = input.val();
          // Check cache (only for handler-based setups)
          var cid = input.data('ac-id');
          if (options.cache && typeof cache[cid][term] !== 'undefined') {
            if (cache[cid][term].length === 0) {
              hide();
            } else {
              _createList(cache[cid][term]);
            }
            // Check for static list
          } else if (typeof options.static !== 'undefined') {
            var lcterm = term.toLowerCase();
            var matches;
            if (typeof options.static.groups !== 'undefined') {
              matches = { groups: _staticGroups(lcterm) };
            } else {
              matches = options.static.filter(function staticFilter(_item) {
                return _item.match.match(lcterm);
              });
              if (typeof options.staticSort === 'function') {
                matches.sort(options.staticSort);
              } else {
                matches.sort(_defaultStaticSort.bind(lcterm));
              }
            }
            _handleResults(term, matches);
            // Call handler
          } else {
            options.handler(input, function achandlerCallback(data) {
              _handleResults(term, data);
            });
          }
        } else {
          hide();
        }
      };

      function preprocessStatic(_item) {
        var item = typeof _item === 'string' ? { value: _item } : _item;
        item.match = (item.label || item.value).toLowerCase();
        return item;
      }
      var _setup = function _setup(settings) {
        var cid = Math.floor(Math.random() * 1000);
        input.data('ac-id', cid);
        input.data('ac-selected', -1);
        input.data('ac-length', 0);

        options = $.extend({}, $.fn.autocomplete.defaults, settings);
        optionStorage[input.data('ac-id')] = options;

        if (options.cache) {
          cache[cid] = {};
        }

        element = $('.autocomplete-results');
        if (element.length === 0) {
          element = $('
')
            .addClass('autocomplete-results ' + options.hidingClass)
            .html('' + options.loadingString + '');
          _align();
          $(document.body).append(element);
        }

        input.blur(function acinputBlur(e) {
          if (e.target.acitem) {
            setTimeout(hide, 10);
          } else {
            hide();
          }
        });
        input.click(function acinputClick() {
          search();
        });
        input.focus(function acinputFocus() {
          search();
        });
        input.on('paste', function acinputPaste() {
          requestAnimationFrame(search);
        });
        input.keyup(function acinputKeyup(event) {
          // Ignore navigation keys
          // - Ignore control functions
          if (event.ctrlKey || event.which === 17) {
            return;
          }
          // - Function keys (F1 - F15)
          if (112 <= event.which && event.which <= 126) {
            return;
          }
          switch (event.which) {
            case 9: // tab
            case 13: // enter
            case 16: // shift
            case 20: // caps lock
            case 27: // esc
            case 33: // page up
            case 34: // page down
            case 35: // end
            case 36: // home
            case 37: // arrows
            case 38:
            case 39:
            case 40:
            case 45: // insert
            case 144: // num lock
            case 145: // scroll lock
            case 19: // pause/break
              return;
            default:
              search();
          }
        });
        input.keydown(function acinputKeydown(event) {
          // - Ignore control functions
          if (event.ctrlKey || event.which === 17) {
            return;
          }
          var position = $(this).data('ac-selected');
          switch (event.which) {
            // arrow keys through items
            case 38: // up key
              event.preventDefault();
              element.find('.ac-item.selected').removeClass('selected');
              if (position > -1) {
                if (position-- > 0) {
                  element.find('.ac-item:eq(' + position + ')').addClass('selected');
                }
                $(this).data('ac-selected', position);
              }
              break;
            case 40: // down key
              event.preventDefault();
              if (element.hasClass(options.hidingClass)) {
                search();
              } else if (position < input.data('ac-length') - 1) {
                position++;
                element.find('.ac-item.selected').removeClass('selected');
                element.find('.ac-item:eq(' + position + ')').addClass('selected');
                $(this).data('ac-selected', position);
              }
              break;
            // enter to nav or populate
            case 9:
            case 13:
              var selected = element.find('.ac-item.selected');
              if (selected.length > 0) {
                event.preventDefault();
                if (event.which === 13 && selected.attr('href') && options.callback === 'undefined') {
                  return window.location.assign(selected.attr('href'));
                } else {
                  _populate(selected.data(), $(this), { key: true });
                }
              }
              break;
            // hide on escape
            case 27:
              hide();
              $(this).data('ac-selected', -1);
              break;
          }
        });

        window.addEventListener('resize', hide, false);
      };

      // Setup
      if (!input.data('ac-id')) {
        if (typeof settings === 'undefined') {
          console.error('Autocomplete not initialized, please pass setup parameters.');
        }
        if (typeof settings.handler === 'undefined' && typeof settings.static === 'undefined') {
          console.error('Neither handler function nor static result list provided for autocomplete');
          return null;
        }
        if (typeof settings.static !== 'undefined') {
          // Preprocess strings into items
          if (typeof settings.static.groups !== 'undefined') {
            for (var i = 0; i < settings.static.groups.length; i++) {
              if (typeof settings.static.groups[i].label !== 'undefined') {
                settings.static.groups[i].items = settings.static.groups[i].items.map(preprocessStatic);
              } else {
                settings.static.groups[i] = settings.static.groups[i].map(preprocessStatic);
              }
            }
          } else {
            settings.static = settings.static.map(preprocessStatic);
          }
        }
        _setup(settings);
      }

      return {
        show: function publicShow() {
          show();
          _align();
        },
        hide: hide,
        clearCache: function clearCache() {
          cache[input.data('ac-id')] = {};
        }
      };
    }.bind(_input)();
  }

  $.fn.autocomplete = function acJQuery(settings) {
    var ac;
    this.each(function acJQueryEach() {
      ac = Factory(this, settings);
    });
    return ac;
  };

  $.fn.autocomplete.defaults = {
    cache: true,
    hidingClass: 'hidden',
    highlight: true,
    loadingString: 'Loading...',
    maxResults: 20,
    minLength: 3
  };

  var timer = false;
  $.fn.autocomplete.ajax = function acAjax(ops) {
    if (timer) {
      clearTimeout(timer);
    }
    if (xhr) {
      xhr.abort();
    }
    timer = setTimeout(function acajaxDelay() {
      xhr = $.ajax(ops);
    }, 200);
  };
})(jQuery);
<|endoftext|>


<commit_before>var LRU = require("lru-cache")
  , options = { max: process.env.MAX || 10000
              , length: function (n, key) { return n * 2 + key.length }
	      , dispose: function (key, n) { return key.length }
              , maxAge: 1000 * 60 * 60 }
  , cache = LRU(options)

// Data Management
var fs = require('fs');
var savePath = process.env.FILE;
    // Reload Cache
    if (savePath){
	if (fs.existsSync('./data.json')) {
	    console.log('Found backup');
		fs.readFile(savePath, 'utf8', function (err, data) {
			cache.load(JSON.parse(data));
		});
	}
    }

process.on('SIGINT', function() {
    // Save Cache
    if (savePath){
   	fs.writeFile (savePath, JSON.stringify(cache.dump()), function(err) {
                if (err) throw err;
                console.log('dump complete! Exiting...');
    		process.exit();
        });
    } else {
    		process.exit();
    }
});

module.exports = cache
<commit_msg>smooth out db proc<commit_after>var LRU = require("lru-cache")
  , options = { max: process.env.MAX || 10000
              , length: function (n, key) { return n * 2 + key.length }
	      , dispose: function (key, n) { return key.length }
              , maxAge: 1000 * 60 * 60 }
  , cache = LRU(options)

// Data Management
var fs = require('fs');
var savePath = process.env.FILE;
    // Reload Cache
    if (savePath){
	if (fs.existsSync(savePath)) {
	    console.log('FILE: Found backup!');
		fs.readFile(savePath, 'utf8', function (err, data) {
			if (!data) return;
			cache.load(JSON.parse(data));
		});
	}
    }

process.on('SIGINT', function() {
    // Save Cache
    if (savePath){
   	fs.writeFile (savePath, JSON.stringify(cache.dump()), function(err) {
                if (err) throw err;
                console.log('FILE: dump complete!');
		console.log('Exiting...');
    		process.exit();
        });
    } else {
		console.log('Exiting...');
    		process.exit();
    }
});

module.exports = cache
<|endoftext|>


<commit_before>var _ = require('lodash');
var crossfilter = require('crossfilter');
var d3 = window.d3;
var EventEmitter = require('events').EventEmitter;

var moment = require('moment-timezone');

var MS_IN_24 = 86400000;

d3.chart('Brush', {
  initialize: function() {
    var chart = this;

    this.width = this.base.attr('width');
    this.height = this.base.attr('height');

    this.base.append('g').attr('id', 'brushMainGroup');

    var xPosition = function(d) {
      return chart.xScale()(d);
    };

    this.layer('brushTicks', this.base.append('g').attr('id', 'brushTicks'), {
      dataBind: function() {
        return this.selectAll('line')
          .data(chart.ticks);
      },
      insert: function() {
        return this.append('line');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale();
          var margins = chart.margins().main;
          var tickLength = chart.tickLength();
          this.attr({
            x1: xPosition,
            x2: xPosition,
            y1: margins.top,
            y2: margins.top + tickLength
          });
        }
      }
    });

    this.layer('brushAxisText', this.base.append('g').attr('id', 'brushAxisText'), {
      dataBind: function() {
        return this.selectAll('text')
          .data(chart.textTicks || chart.ticks);
      },
      insert: function() {
        return this.append('text');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale(), tz = chart.timezone();
          var tickShift = chart.tickShift();
          if (chart.brushTickInterval() !== 'month') {
            tickShift.x = 0;
          }
          this.attr({
            x: function(d) {
              return xPosition(d) + tickShift.x;
            },
            y: tickShift.y
          })
          .classed('centered', chart.brushTickInterval() !== 'month')
          .text(function(d) {
            var format = chart.brushTickInterval() === 'month' ? 'MMM': 'MMM D';
            return moment.utc(d).tz(tz).format(format);
          });
        }
      }
    });
  },
  brushTickInterval: function(brushTickInterval) {
    if (!arguments.length) { return this._brushTickInterval; }
    this._brushTickInterval = brushTickInterval;
    return this;
  },
  cornerRadius: function(cornerRadius) {
    if (!arguments.length) { return this._cornerRadius; }
    this._cornerRadius = cornerRadius;
    return this;
  },
  emitter: function(emitter) {
    if (!arguments.length) { return this._emitter; }
    this._emitter = emitter;
    return this;
  },
  initialExtent: function(initialExtent) {
    if (!arguments.length) { return this._initialExtent; }
    this._initialExtent = initialExtent;
    return this;
  },
  margins: function(margins) {
    if (!arguments.length) { return this._margins; }
    this._margins = margins;
    return this;
  },
  tickLength: function(tickLength) {
    if (!arguments.length) { return this._tickLength; }
    this._tickLength = tickLength;
    return this;
  },
  tickShift: function(tickShift) {
    if (!arguments.length) { return this._tickShift; }
    this._tickShift = tickShift;
    return this;
  },
  timezone: function(timezone) {
    if (!arguments.length) { return this._timezone; }
    this._timezone = timezone;
    return this;
  },
  setExtent: function(newExtent) {
    var xScale = this.xScale(), timezone = this.timezone();
    var scaleDomain = xScale.domain();
    if (newExtent[0] < scaleDomain[0]) {
      var extentSize = (newExtent[1] - newExtent[0])/MS_IN_24;
      var s = moment.utc(scaleDomain[0]).tz(timezone).startOf('day');
      newExtent = [s, d3.time.day.utc.offset(s, extentSize)];
    }
    this.brushHandleGroup.call(this.brush.extent(newExtent));
    this.fixBrushHandlers(this.brushHandleGroup);
    return this;
  },
  xScale: function(xScale) {
    if (!arguments.length) { return this._xScale; }
    var w = this.width;
    var mainMargins = this.margins().main;
    this._xScale = xScale.range([
      mainMargins.left,
      w - mainMargins.right
    ]);
    var domain = xScale.domain();
    var domainDays = (domain[1] - domain[0])/MS_IN_24;
    var smallDaysLimit = 40, mediumDaysLimit = 90;
    this._brushTickInterval = domainDays < mediumDaysLimit ? 'week' : 'month';
    var tickJump = 1;
    if (domainDays > smallDaysLimit && domainDays < mediumDaysLimit) {
      tickJump = 2;
    }
    var ticks = [], current = domain[0];
    var tz = this.timezone();
    while (current < domain[1]) {
      current = moment(current).add(tickJump, this._brushTickInterval).startOf(this._brushTickInterval).tz(tz).toDate();
      ticks.push(current);
    }
    // final tick will go beyond the domain, so pop it
    ticks.pop();
    this.ticks = ticks;
    // don't want tick labels to appear too close to edge
    // so only show if > two weeks from start of floor of end-of-domain month
    var lastTick = ticks[ticks.length - 1];
    if (this._brushTickInterval === 'month' && (domain[1] - lastTick) / MS_IN_24 < 14) {
      this.textTicks = ticks.slice();
      this.textTicks.pop();
    }
    this.makeBrush();
    return this;
  },
  makeBrush: function() {
    var chart = this, emitter = this.emitter();
    function brushed() {

      var origExtent = chart.brush.extent(), newExtent;
      var timezone = chart.timezone();
      // preserve width of handle on drag
      if (d3.event.mode === 'move') {
        var s = moment.utc(origExtent[0]).tz(timezone).startOf('day');
        var e = moment(s).add(Math.round((origExtent[1] - origExtent[0])/MS_IN_24), 'days');
        newExtent = [s, e];
      }
      // on resize, round to midnights
      else {
        newExtent = origExtent.map(d3.time.day.utc.round);

        // if empty when rounded, use floor & ceil instead
        // i.e., enforce min of 1 day
        if (newExtent[0] >= newExtent[1]) {
          newExtent[0] = moment.utc(origExtent[0]).tz(timezone).startOf('day');
          newExtent[1] = moment.utc(origExtent[1]).tz(timezone).startOf('day');
        }
      }
      emitter.emit('brushed', [newExtent[0].toISOString(), newExtent[1].toISOString()]);
      d3.select(this).call(chart.brush.extent(newExtent));
      chart.fixBrushHandlers(d3.select(this));
    }

    var xScale = this.xScale();
    var initial = chart.initialExtent();

    var extentDates = [Date.parse(initial[0]), Date.parse(initial[1])];

    this.brush = d3.svg.brush()
      .x(xScale)
      .extent(extentDates)
      .on('brush', brushed);

    this.brushHandleGroup = this.base.append('g')
      .attr('id', 'brushHandleGroup')
      .call(this.brush);

    this.fixBrushHandlers(this.brushHandleGroup);

    var mainMargins = this.margins().main;

    var cornerRadius = this.cornerRadius();

    this.brushHandleGroup.select('rect.background')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      })
      .style('visibility', 'visible');

    this.brushHandleGroup.select('rect.extent')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      });
  },
  fixBrushHandlers: function(brushNode) {
    var oldMousedown = brushNode.on('mousedown.brush');
    brushNode.on('mousedown.brush', function() {
      brushNode.on('mouseup.brush', function() {
        clearHandlers();
      });

      brushNode.on('mousemove.brush', function() {
        clearHandlers();
        oldMousedown.call(this);
      });

      function clearHandlers() {
        brushNode.on('mousemove.brush', null);
        brushNode.on('mouseup.brush', null);
      }
    });
  },
  remove: function() {
    this.base.remove();
    return this;
  }
});

var chart;

module.exports = {
  create: function(el, dateDomain, opts) {
    opts = opts || {};
    var defaults = {
      baseMargin: opts.baseMargin || 10,
      brushHeight: el.offsetHeight,
      cornerRadius: 10,
      initialExtent: [d3.time.day.utc.offset(new Date(dateDomain[1]), -14), new Date(dateDomain[1])],
      tickLength: 10,
      tickShift: {x: 5, y: 3}
    };
    defaults.margins = {
      main: {
        top: defaults.baseMargin + 11,
        right: defaults.baseMargin + 30,
        bottom: defaults.baseMargin - 5,
        left: defaults.baseMargin + 30
      }
    };
    _.defaults(opts, defaults);

    var xScale = d3.time.scale.utc()
      .domain([
        moment.utc(dateDomain[0]).tz(opts.timezone).startOf('day'),
        moment.utc(dateDomain[1]).tz(opts.timezone).startOf('day').add(1, 'days')
      ]);

    chart = d3.select(el)
      .append('svg')
      .attr({
        width: el.offsetWidth,
        height: opts.brushHeight
      })
      .chart('Brush')
      .cornerRadius(opts.cornerRadius)
      .emitter(this.emitter)
      .initialExtent(opts.initialExtent)
      .margins(opts.margins)
      .tickLength(opts.tickLength)
      .tickShift(opts.tickShift)
      .timezone(opts.timezone)
      .xScale(xScale);

    return this;
  },
  getCurrentDay: function() {
    return new Date(chart.brush.extent()[1].valueOf() - MS_IN_24/2);
  },
  emitter: new EventEmitter(),
  render: function(data, opts) {
    opts = opts || {};
    var defaults = {};
    _.defaults(opts, defaults);

    chart.draw();

    return this;
  },
  setExtent: function(newExtent) {
    chart.setExtent(newExtent);
  },
  destroy: function() {
    this.emitter.removeAllListeners();
    chart.remove();

    return this;
  }
};<commit_msg>revert back to default d3.time.scale tick generation<commit_after>var _ = require('lodash');
var crossfilter = require('crossfilter');
var d3 = window.d3;
var EventEmitter = require('events').EventEmitter;

var moment = require('moment-timezone');

var MS_IN_24 = 86400000;

d3.chart('Brush', {
  initialize: function() {
    var chart = this;

    this.width = this.base.attr('width');
    this.height = this.base.attr('height');

    this.base.append('g').attr('id', 'brushMainGroup');

    var xPosition = function(d) {
      return chart.xScale()(d);
    };

    this.layer('brushTicks', this.base.append('g').attr('id', 'brushTicks'), {
      dataBind: function() {
        return this.selectAll('line')
          .data(chart.ticks);
      },
      insert: function() {
        return this.append('line');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale();
          var margins = chart.margins().main;
          var tickLength = chart.tickLength();
          this.attr({
            x1: xPosition,
            x2: xPosition,
            y1: margins.top,
            y2: margins.top + tickLength
          });
        }
      }
    });

    this.layer('brushAxisText', this.base.append('g').attr('id', 'brushAxisText'), {
      dataBind: function() {
        return this.selectAll('text')
          .data(chart.textTicks || chart.ticks);
      },
      insert: function() {
        return this.append('text');
      },
      events: {
        enter: function() {
          var xScale = chart.xScale(), tz = chart.timezone();
          var tickShift = chart.tickShift();
          if (chart.brushTickInterval() !== 'month') {
            tickShift.x = 0;
          }
          this.attr({
            x: function(d) {
              return xPosition(d) + tickShift.x;
            },
            y: tickShift.y
          })
          .classed('centered', chart.brushTickInterval() !== 'month')
          .text(function(d) {
            var format = chart.brushTickInterval() === 'month' ? 'MMM': 'MMM D';
            return moment.utc(d).tz(tz).format(format);
          });
        }
      }
    });
  },
  brushTickInterval: function(brushTickInterval) {
    if (!arguments.length) { return this._brushTickInterval; }
    this._brushTickInterval = brushTickInterval;
    return this;
  },
  cornerRadius: function(cornerRadius) {
    if (!arguments.length) { return this._cornerRadius; }
    this._cornerRadius = cornerRadius;
    return this;
  },
  emitter: function(emitter) {
    if (!arguments.length) { return this._emitter; }
    this._emitter = emitter;
    return this;
  },
  initialExtent: function(initialExtent) {
    if (!arguments.length) { return this._initialExtent; }
    this._initialExtent = initialExtent;
    return this;
  },
  margins: function(margins) {
    if (!arguments.length) { return this._margins; }
    this._margins = margins;
    return this;
  },
  tickLength: function(tickLength) {
    if (!arguments.length) { return this._tickLength; }
    this._tickLength = tickLength;
    return this;
  },
  tickShift: function(tickShift) {
    if (!arguments.length) { return this._tickShift; }
    this._tickShift = tickShift;
    return this;
  },
  timezone: function(timezone) {
    if (!arguments.length) { return this._timezone; }
    this._timezone = timezone;
    return this;
  },
  setExtent: function(newExtent) {
    var xScale = this.xScale(), timezone = this.timezone();
    var scaleDomain = xScale.domain();
    if (newExtent[0] < scaleDomain[0]) {
      var extentSize = (newExtent[1] - newExtent[0])/MS_IN_24;
      var s = moment.utc(scaleDomain[0]).tz(timezone).startOf('day');
      newExtent = [s, d3.time.day.utc.offset(s, extentSize)];
    }
    this.brushHandleGroup.call(this.brush.extent(newExtent));
    this.fixBrushHandlers(this.brushHandleGroup);
    return this;
  },
  xScale: function(xScale) {
    if (!arguments.length) { return this._xScale; }
    var w = this.width;
    var mainMargins = this.margins().main;
    this._xScale = xScale.range([
      mainMargins.left,
      w - mainMargins.right
    ]);
    var domain = xScale.domain();
    var domainDays = (domain[1] - domain[0])/MS_IN_24;
    var smallDaysLimit = 40, mediumDaysLimit = 90;
    this._brushTickInterval = domainDays < mediumDaysLimit ? 'week' : 'month';
    this.ticks = xScale.ticks(7);
    this.makeBrush();
    return this;
  },
  makeBrush: function() {
    var chart = this, emitter = this.emitter();
    function brushed() {

      var origExtent = chart.brush.extent(), newExtent;
      var timezone = chart.timezone();
      // preserve width of handle on drag
      if (d3.event.mode === 'move') {
        var s = moment.utc(origExtent[0]).tz(timezone).startOf('day');
        var e = moment(s).add(Math.round((origExtent[1] - origExtent[0])/MS_IN_24), 'days');
        newExtent = [s, e];
      }
      // on resize, round to midnights
      else {
        newExtent = origExtent.map(d3.time.day.utc.round);

        // if empty when rounded, use floor & ceil instead
        // i.e., enforce min of 1 day
        if (newExtent[0] >= newExtent[1]) {
          newExtent[0] = moment.utc(origExtent[0]).tz(timezone).startOf('day');
          newExtent[1] = moment.utc(origExtent[1]).tz(timezone).startOf('day');
        }
      }
      emitter.emit('brushed', [newExtent[0].toISOString(), newExtent[1].toISOString()]);
      d3.select(this).call(chart.brush.extent(newExtent));
      chart.fixBrushHandlers(d3.select(this));
    }

    var xScale = this.xScale();
    var initial = chart.initialExtent();

    var extentDates = [Date.parse(initial[0]), Date.parse(initial[1])];

    this.brush = d3.svg.brush()
      .x(xScale)
      .extent(extentDates)
      .on('brush', brushed);

    this.brushHandleGroup = this.base.append('g')
      .attr('id', 'brushHandleGroup')
      .call(this.brush);

    this.fixBrushHandlers(this.brushHandleGroup);

    var mainMargins = this.margins().main;

    var cornerRadius = this.cornerRadius();

    this.brushHandleGroup.select('rect.background')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      })
      .style('visibility', 'visible');

    this.brushHandleGroup.select('rect.extent')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: cornerRadius,
        ry: cornerRadius
      });
  },
  fixBrushHandlers: function(brushNode) {
    var oldMousedown = brushNode.on('mousedown.brush');
    brushNode.on('mousedown.brush', function() {
      brushNode.on('mouseup.brush', function() {
        clearHandlers();
      });

      brushNode.on('mousemove.brush', function() {
        clearHandlers();
        oldMousedown.call(this);
      });

      function clearHandlers() {
        brushNode.on('mousemove.brush', null);
        brushNode.on('mouseup.brush', null);
      }
    });
  },
  remove: function() {
    this.base.remove();
    return this;
  }
});

var chart;

module.exports = {
  create: function(el, dateDomain, opts) {
    opts = opts || {};
    var defaults = {
      baseMargin: opts.baseMargin || 10,
      brushHeight: el.offsetHeight,
      cornerRadius: 10,
      initialExtent: [d3.time.day.utc.offset(new Date(dateDomain[1]), -14), new Date(dateDomain[1])],
      tickLength: 10,
      tickShift: {x: 5, y: 3}
    };
    defaults.margins = {
      main: {
        top: defaults.baseMargin + 11,
        right: defaults.baseMargin + 30,
        bottom: defaults.baseMargin - 5,
        left: defaults.baseMargin + 30
      }
    };
    _.defaults(opts, defaults);

    var xScale = d3.time.scale.utc()
      .domain([
        moment.utc(dateDomain[0]).tz(opts.timezone).startOf('day'),
        moment.utc(dateDomain[1]).tz(opts.timezone).startOf('day').add(1, 'days')
      ]);

    chart = d3.select(el)
      .append('svg')
      .attr({
        width: el.offsetWidth,
        height: opts.brushHeight
      })
      .chart('Brush')
      .cornerRadius(opts.cornerRadius)
      .emitter(this.emitter)
      .initialExtent(opts.initialExtent)
      .margins(opts.margins)
      .tickLength(opts.tickLength)
      .tickShift(opts.tickShift)
      .timezone(opts.timezone)
      .xScale(xScale);

    return this;
  },
  getCurrentDay: function() {
    return new Date(chart.brush.extent()[1].valueOf() - MS_IN_24/2);
  },
  emitter: new EventEmitter(),
  render: function(data, opts) {
    opts = opts || {};
    var defaults = {};
    _.defaults(opts, defaults);

    chart.draw();

    return this;
  },
  setExtent: function(newExtent) {
    chart.setExtent(newExtent);
  },
  destroy: function() {
    this.emitter.removeAllListeners();
    chart.remove();

    return this;
  }
};<|endoftext|>


<commit_before>/*
# Test
Copyright ©2016-2017 Tonio Loewald

A very simple test library with support for async tests.

To test something:

		Test(*function-expression-that-may-return-promise* [, *description*]).
		shouldBe(*exapectedValue*);

Or sometimes:

		Test(*function-expression-that-may-return-promise* [, *description*]).
		shouldNotBe(*exapectedValue*);

To setup visible reporting:

		Test.
		setReportContainer(*destination_element*);

To set an error callback:

		Test.onError = *function*;
*/

/* globals module, console */

(function(module){
'use strict';

var report_container;
const tests = [];

function Test(fn, description) {
	if (!this || this === window) {
		return new Test(fn, description);
	} else if (typeof fn === 'function') {
		this.fn = fn;
		this.description = description || fn.toString();
		this.status = 'incomplete';
		tests.push(this);
		run(this);
	} else {
		console.error('Test expects a function, got', fn);
	}
}

Test.onError = () => {};

Test.tests = () => tests;

Test.reset = () => tests.splice(0);

Test.setReportContainer = (destination) => report_container = destination;

function trigger (event_type, target) {
	var targets;
	if (typeof target === 'string') {
		targets = document.querySelectorAll(target);
	} else if (!target.length) {
		targets = [target];
	}
	if (targets.length && !(targets instanceof Array)) {
		targets = [].slice.apply(targets);
	}
	targets.forEach(target => {
		target.dispatchEvent(new Event(event_type, {bubbles: true, view: window}));
	});
}

function report (message, _class_) {
	if (report_container) {
		var p = document.createElement('p');
		if (_class_) {
			p.classList.add(_class_);
		}
		p.textContent = message;
		report_container.appendChild(p);
	} else {
		console.error(message);
	}
}

function quote (x) {
	if (typeof x === 'string') {
		return '"' + x + '"';
	} else if (typeof x === 'number') {
		return x;
	} else if (x instanceof Array) {
		return '[...]';
	} else if (typeof x === 'object') {
		return '{...}';
	} else {
		return x;
	}
}

Test.trigger = trigger;
Test.report = report;

function run(test) {
	var result = test.fn();
	if (result instanceof Promise) {
		result.then(() => {
			if (!test._test(result)) {
				failure(test, result);
			} else {
				success(test, result);
			}
		}, () => {
			test.failure('Promise failed');
		});
	} else {
		setTimeout(() => {
			if (!test._test(result)) {
				failure(test, result);
			} else {
				success(test, result);
			}
		});
	}
}

function success(test, result) {
	test.status = 'success';
	report(`${test.description} == ${quote(result)}`, 'success');
}

function failure(test, result) {
	Test.onError();
	test.status = 'failure';
	report(`${test.description} == ${quote(result)}`, 'success');
}

Test.prototype = {
	shouldBe: function(value) {
		if(this._test) {
			throw 'cannot set a different expectation';
		}
		this._expected = `expected ${value}`;
		this._test = x => x === value;
	},

	shouldNotBe: function(value) {
		if(this._test) {
			throw 'cannot set a different expectation';
		}
		this._expected = `did not expect ${value}`;
		this._test = x => x !== value;
	}
};

module.exports = Test;
}(module));<commit_msg>Documented a couple of utility methods<commit_after>/*
# Test
Copyright ©2016-2017 Tonio Loewald

A very simple test library with support for async tests.

To test something:

		Test(*function-expression-that-may-return-promise* [, *description*]).
		shouldBe(*exapectedValue*);

Or sometimes:

		Test(*function-expression-that-may-return-promise* [, *description*]).
		shouldNotBe(*exapectedValue*);

To setup visible reporting:

		Test.
		setReportContainer(*destination_element*);

To set an error callback:

		Test.onError = *function*;

To get a list of tests (which will include descriptions and statuses):

		Test.tests();

To reset the list of tests:

		Test.reset();
*/

/* globals module, console */

(function(module){
'use strict';

var report_container;
const tests = [];

function Test(fn, description) {
	if (!this || this === window) {
		return new Test(fn, description);
	} else if (typeof fn === 'function') {
		this.fn = fn;
		this.description = description || fn.toString();
		this.status = 'incomplete';
		tests.push(this);
		run(this);
	} else {
		console.error('Test expects a function, got', fn);
	}
}

Test.onError = () => {};

Test.tests = () => tests;

Test.reset = () => tests.splice(0);

Test.setReportContainer = (destination) => report_container = destination;

function trigger (event_type, target) {
	var targets;
	if (typeof target === 'string') {
		targets = document.querySelectorAll(target);
	} else if (!target.length) {
		targets = [target];
	}
	if (targets.length && !(targets instanceof Array)) {
		targets = [].slice.apply(targets);
	}
	targets.forEach(target => {
		target.dispatchEvent(new Event(event_type, {bubbles: true, view: window}));
	});
}

function report (message, _class_) {
	if (report_container) {
		var p = document.createElement('p');
		if (_class_) {
			p.classList.add(_class_);
		}
		p.textContent = message;
		report_container.appendChild(p);
	} else {
		console.error(message);
	}
}

function quote (x) {
	if (typeof x === 'string') {
		return '"' + x + '"';
	} else if (typeof x === 'number') {
		return x;
	} else if (x instanceof Array) {
		return '[...]';
	} else if (typeof x === 'object') {
		return '{...}';
	} else {
		return x;
	}
}

Test.trigger = trigger;
Test.report = report;

function run(test) {
	var result = test.fn();
	if (result instanceof Promise) {
		result.then(() => {
			if (!test._test(result)) {
				failure(test, result);
			} else {
				success(test, result);
			}
		}, () => {
			test.failure('Promise failed');
		});
	} else {
		setTimeout(() => {
			if (!test._test(result)) {
				failure(test, result);
			} else {
				success(test, result);
			}
		});
	}
}

function success(test, result) {
	test.status = 'success';
	report(`${test.description} == ${quote(result)}`, 'success');
}

function failure(test, result) {
	Test.onError();
	test.status = 'failure';
	report(`${test.description} == ${quote(result)}`, 'success');
}

Test.prototype = {
	shouldBe: function(value) {
		if(this._test) {
			throw 'cannot set a different expectation';
		}
		this._expected = `expected ${value}`;
		this._test = x => x === value;
	},

	shouldNotBe: function(value) {
		if(this._test) {
			throw 'cannot set a different expectation';
		}
		this._expected = `did not expect ${value}`;
		this._test = x => x !== value;
	}
};

module.exports = Test;
}(module));<|endoftext|>


<commit_before>/* SDK Modules */
const simplePrefs = require('sdk/simple-prefs');

/* Constants */
const _24HOUR_PREF = '24hour';
const TIME_MSG = 'time';

/**
 * Initializes time by sending time options to the content scripts.
 */
exports.initTime = function(worker) {
    var options = {
        _24HOUR_PREF: simplePrefs.prefs[_24HOUR_PREF]
    };
    worker.port.emit(TIME_MSG, options);
}
<commit_msg>Fix 24-hour clock preference not working<commit_after>/* SDK Modules */
const simplePrefs = require('sdk/simple-prefs');

/* Constants */
const _24HOUR_PREF = '24hour';
const TIME_MSG = 'time';

/**
 * Initializes time by sending time options to the content scripts.
 */
exports.initTime = function(worker) {
    var options = {}
    options[_24HOUR_PREF] = simplePrefs.prefs[_24HOUR_PREF];
    worker.port.emit(TIME_MSG, options);
}
<|endoftext|>


<commit_before>gf.AssetLoader = function(resources) {
    //mixin the Event Target methods
    PIXI.EventTarget.call(this);

    /**
    * The array of asset URLs that are going to be loaded
    * @property assetURLs
    * @type Array
    */
    this.resources = resources;
    this.loadCount = 0;
    this.assets = {};

    this.exts = {
        imgs: ['jpeg', 'jpg', 'png', 'gif'],
        sound: ['mp3', 'ogg', 'wma', 'wav'],
        data: ['json']
    };
};

gf.inherits(gf.AssetLoader, Object, {
    load: function() {
        for(var i = 0, il = this.resources.length; i < il; ++i) {
            var name = typeof this.resources[i] === 'string' ? this.resources[i] : this.resources[i].name,
                url = typeof this.resources[i] === 'string' ? this.resources[i] : this.resources[i].src,
                ext = url.split('.').pop().toLowerCase();

            //load a texture
            if(this.exts.imgs.indexOf(ext) !== -1) {
                this.loadTexture(name, url);
            }
            //load a sound clip
            else if(this.exts.sound.indexOf(ext) !== -1) {
                this.loadAudio(name, url);
            }
            //load a data file (world, spritesheet, etc)
            else if(this.exts.data.indexOf(ext) !== -1) {
                this.loadData(name, url);
            }
        }
    },
    loadTexture: function(name, url) {
        this.loadCount++;

        var self = this,
            texture = PIXI.Texture.fromImage(url);

        this._storeAsset(name, texture);

        if(!texture.hasLoaded) {
            texture.baseTexture.on('loaded', function() {
                self.onAssetLoaded(null, 'texture', texture);
            });
        } else {
            self.onAssetLoaded(null, 'texture', texture);
        }

        return texture;
    },
    loadAudio: function(name, url) {
        this.loadCount++;

        var self = this,
            audio = new Audio(url);

        audio.preload = 'auto';

        this._storeAsset(name, audio);

        audio.addEventListener('canplaythrough', function() {
            self.onAssetLoaded(null, 'audio', audio);
        }, false);

        audio.addEventListener('error', function() {
            self.onAssetLoaded(new Error('Failed to load audio "' + name + '" at url: ' + url), 'audio');
        }, false);

        audio.load();

        return audio;
    },
    loadData: function(name, url) {
        var self = this,
            baseUrl = url.replace(/[^\/]*$/, '');

        gf.utils.ajax({
            method: 'GET',
            url: url,
            dataType: 'json',
            load: function(data) {
                //check some properties to see if this is a TiledMap Object
                if(data.orientation && data.layers && data.tilesets && data.version) {
                    self._storeAsset(name, data);

                    //TODO: How to tell if all these are loaded (how to count them?)
                    //loop through each layer and load the sprites (objectgroup types)
                    for(var i = 0, il = data.layers.length; i < il; ++i) {
                        var layer = data.layers[i];
                        if(layer.type !== gf.types.LAYER.OBJECT_GROUP) continue;

                        //loop through each object, and load the textures
                        for(var o = 0, ol = layer.objects.length; o < ol; ++o) {
                            var obj = layer.objects[o];
                            if(!obj.properties.spritesheet) continue;

                            self.loadTexture(layer.name + '_' + obj.name + '_texture', obj.properties.spritesheet);
                        }
                    }

                    //loop through each tileset and load the texture
                    for(var s = 0, sl = data.tilesets.length; s < sl; ++s) {
                        var set = data.tilesets[s];
                        if(!set.image) continue;

                        self.loadTexture(set.name + '_texture', baseUrl + set.image);
                    }
                }
                //this is a sprite sheet (published from TexturePacker)
                else if(data.frames && data.meta) {
                    this.loadCount++;

                    var textureUrl = baseUrl + data.meta.image,
                        texture =  PIXI.Texture.fromImage(textureUrl).baseTexture,
                        frames = data.frames,
                        assets = [];

                    for(var f in frames) {
                        var rect = frames[f].frame;

                        PIXI.TextureCache[f] = new PIXI.Texture(texture, { x: rect.x, y: rect.y, width: rect.w, height: rect.h });

                        if(frames[f].trimmed) {
                            PIXI.TextureCache[f].realSize = frames[f].spriteSourceSize;
                            PIXI.TextureCache[f].trim.x = 0;
                        }

                        assets.push(PIXI.TextureCache[f]);
                    }

                    self._storeAsset(name, assets);

                    if(texture.hasLoaded) {
                        self.onAssetLoaded(null, 'spritesheet', assets);
                    }
                    else {
                        texture.addEventListener('loaded', function() {
                            self.onAssetLoaded(null, 'spritesheet', assets);
                        });
                    }
                }
            },
            error: function(err) {
                self.onAssetLoaded(err);
            }
        });
    },
    onAssetLoaded: function(err, type, asset) {
        //texture (image)
        //audio
        //spritesheet (json sheet)
        //world (TiledEditor Json data)
        this.loadCount--;

        this.emit({ type: 'progress', error: err, kind: type, asset: asset });
        if(this.onProgress) this.onProgress(err, type, asset);

        if(this.loadCount === 0) {
            this.dispatchEvent({ type: 'complete' });
            if(this.onComplete) this.onComplete();
        }
    },
    _storeAsset: function(name, asset) {
        this.assets[name] = asset;
        gf.assetCache[name] = asset;
    }
});
<commit_msg>Fix some counting errors in loader<commit_after>gf.AssetLoader = function(resources) {
    //mixin the Event Target methods
    PIXI.EventTarget.call(this);

    /**
    * The array of asset URLs that are going to be loaded
    * @property assetURLs
    * @type Array
    */
    this.resources = resources;
    this.loadCount = 0;
    this.assets = {};

    this.exts = {
        imgs: ['jpeg', 'jpg', 'png', 'gif'],
        sound: ['mp3', 'ogg', 'wma', 'wav'],
        data: ['json']
    };
};

gf.inherits(gf.AssetLoader, Object, {
    load: function() {
        for(var i = 0, il = this.resources.length; i < il; ++i) {
            var name = typeof this.resources[i] === 'string' ? this.resources[i] : this.resources[i].name,
                url = typeof this.resources[i] === 'string' ? this.resources[i] : this.resources[i].src,
                ext = url.split('.').pop().toLowerCase();

            //load a texture
            if(this.exts.imgs.indexOf(ext) !== -1) {
                this.loadTexture(name, url);
            }
            //load a sound clip
            else if(this.exts.sound.indexOf(ext) !== -1) {
                this.loadAudio(name, url);
            }
            //load a data file (world, spritesheet, etc)
            else if(this.exts.data.indexOf(ext) !== -1) {
                this.loadData(name, url);
            }
        }
    },
    loadTexture: function(name, url) {
        this.loadCount++;

        var self = this,
            texture = PIXI.Texture.fromImage(url);

        this._storeAsset(name, texture);

        if(!texture.baseTexture.hasLoaded) {
            texture.baseTexture.on('loaded', function() {
                self.onAssetLoaded(null, 'texture', texture);
            });
        } else {
            self.onAssetLoaded(null, 'texture', texture);
        }

        return texture;
    },
    loadAudio: function(name, url) {
        this.loadCount++;

        var self = this,
            audio = new Audio(url);

        audio.preload = 'auto';

        this._storeAsset(name, audio);

        audio.addEventListener('canplaythrough', function() {
            self.onAssetLoaded(null, 'audio', audio);
        }, false);

        audio.addEventListener('error', function() {
            self.onAssetLoaded(new Error('Failed to load audio "' + name + '" at url: ' + url), 'audio');
        }, false);

        audio.load();

        return audio;
    },
    loadData: function(name, url) {
        this.loadCount++;

        var self = this,
            baseUrl = url.replace(/[^\/]*$/, '');

        gf.utils.ajax({
            method: 'GET',
            url: url,
            dataType: 'json',
            load: function(data) {
                //check some properties to see if this is a TiledMap Object
                if(data.orientation && data.layers && data.tilesets && data.version) {
                    self._storeAsset(name, data);

                    //TODO: How to tell if all these are loaded (how to count them?)
                    //loop through each layer and load the sprites (objectgroup types)
                    for(var i = 0, il = data.layers.length; i < il; ++i) {
                        var layer = data.layers[i];
                        if(layer.type !== gf.types.LAYER.OBJECT_GROUP) continue;

                        //loop through each object, and load the textures
                        for(var o = 0, ol = layer.objects.length; o < ol; ++o) {
                            var obj = layer.objects[o];
                            if(!obj.properties.spritesheet) continue;

                            self.loadTexture(layer.name + '_' + obj.name + '_texture', obj.properties.spritesheet);
                        }
                    }

                    //loop through each tileset and load the texture
                    for(var s = 0, sl = data.tilesets.length; s < sl; ++s) {
                        var set = data.tilesets[s];
                        if(!set.image) continue;

                        self.loadTexture(set.name + '_texture', baseUrl + set.image);
                    }

                    self.onAssetLoaded(null, 'world', data);
                }
                //this is a sprite sheet (published from TexturePacker)
                else if(data.frames && data.meta) {
                    var textureUrl = baseUrl + data.meta.image,
                        texture =  PIXI.Texture.fromImage(textureUrl).baseTexture,
                        frames = data.frames,
                        assets = [];

                    for(var f in frames) {
                        var rect = frames[f].frame;

                        PIXI.TextureCache[f] = new PIXI.Texture(texture, { x: rect.x, y: rect.y, width: rect.w, height: rect.h });

                        if(frames[f].trimmed) {
                            PIXI.TextureCache[f].realSize = frames[f].spriteSourceSize;
                            PIXI.TextureCache[f].trim.x = 0;
                        }

                        assets.push(PIXI.TextureCache[f]);
                    }

                    self._storeAsset(name, assets);

                    if(texture.hasLoaded) {
                        self.onAssetLoaded(null, 'spritesheet', assets);
                    }
                    else {
                        texture.addEventListener('loaded', function() {
                            self.onAssetLoaded(null, 'spritesheet', assets);
                        });
                    }
                }
            },
            error: function(err) {
                self.onAssetLoaded(err);
            }
        });
    },
    onAssetLoaded: function(err, type, asset) {
        //texture (image)
        //audio
        //spritesheet (json sheet)
        //world (TiledEditor Json data)
        this.loadCount--;

        this.emit({ type: 'progress', error: err, assetType: type, asset: asset });
        if(this.onProgress) this.onProgress(err, type, asset);

        if(this.loadCount === 0) {
            this.dispatchEvent({ type: 'complete' });
            if(this.onComplete) this.onComplete();
        }
    },
    _storeAsset: function(name, asset) {
        this.assets[name] = asset;
        gf.assetCache[name] = asset;
    }
});
<|endoftext|>


<commit_before>import Sequelize from 'sequelize';
import _ from 'lodash';
import PHPUnserialize from 'php-unserialize';

const viewer = {
  id: 1,
  name: 'Anonymous'
}

export default class WordExpressDatabase{
  constructor(connectionDetails){
    this.connectionDetails = connectionDetails;
    this.connection = this.connect(connectionDetails);
    this.queries = this.getQueries();
    this.models = this.getModels();
  }

  connect(){
    const { name, username, password, host} = this.connectionDetails;
    const Conn = new Sequelize(
      name,
      username,
      password,
      {
        dialect: 'mysql',
        host: host,
        define: {
          timestamps: false,
          freezeTableName: true,
        }
      }
    );

    return Conn;
  }

  getModels(){
    const prefix = 'wp_';
    const Conn = this.connection;

    return {
      Post: Conn.define(prefix + 'posts', {
        id: { type: Sequelize.INTEGER, primaryKey: true},
        post_author: { type: Sequelize.INTEGER },
        post_title: { type: Sequelize.STRING },
        post_content: { type: Sequelize.STRING },
        post_excerpt: { type: Sequelize.STRING },
        post_status:{ type: Sequelize.STRING },
        post_type:{ type: Sequelize.STRING },
        post_name:{ type: Sequelize.STRING},
        post_parent: { type: Sequelize.INTEGER},
        menu_order: { type: Sequelize.INTEGER}
      }),
      Postmeta: Conn.define(prefix + 'postmeta', {
        meta_id: { type: Sequelize.INTEGER, primaryKey: true, field: 'meta_id' },
        post_id: { type: Sequelize.INTEGER },
        meta_key: { type: Sequelize.STRING },
        meta_value: { type: Sequelize.INTEGER },
      }),
      Terms: Conn.define(prefix + 'terms', {
        term_id: { type: Sequelize.INTEGER, primaryKey: true },
        name: { type: Sequelize.STRING },
        slug: { type: Sequelize.STRING },
        term_group: { type: Sequelize.INTEGER },
      }),
      TermRelationships: Conn.define(prefix + 'term_relationships', {
        object_id: { type: Sequelize.INTEGER, primaryKey: true },
        term_taxonomy_id: { type: Sequelize.INTEGER },
        term_order: { type: Sequelize.INTEGER },
      }),
      TermTaxonomy: Conn.define(prefix + 'term_taxonomy', {
        term_taxonomy_id: { type: Sequelize.INTEGER, primaryKey: true },
        term_id: { type: Sequelize.INTEGER },
        taxonomy: { type: Sequelize.STRING },
        parent: { type: Sequelize.INTEGER },
        count: { type: Sequelize.INTEGER },
      })
    }
  }

  getQueries(){
    const { amazonS3, uploadDirectory } = this.connectionDetails;
    const { Post, Postmeta, Terms, TermRelationships, TermTaxonomy  } = this.getModels();

    Terms.hasMany(TermRelationships,  {foreignKey: 'term_taxonomy_id'});
    TermRelationships.belongsTo(Terms, {foreignKey: 'term_taxonomy_id'});

    TermRelationships.hasMany(Postmeta, {foreignKey: 'post_id'});
    Postmeta.belongsTo(TermRelationships, {foreignKey: 'post_id'});

    TermRelationships.belongsTo(Post, {foreignKey: 'object_id'});

    Post.hasMany(Postmeta, {foreignKey: 'post_id'});
    Postmeta.belongsTo(Post, {foreignKey: 'post_id'});

    return {
      getViewer(){
        return viewer
      },
      getPosts(args){
        const {post_type} = args;
        return Post.findAll({
          where: {
            post_type: post_type,
            post_status: 'publish',
          }
        })
      },
      getPostById(postId){
        return Post.findOne({
          where: {
            id: postId
          }
        })
      },
      getPostByName(name){
        return Post.findOne({
          where: {
            post_status: 'publish',
            post_name: name
          }
        })
      },
      getPostThumbnail(postId){
        return Postmeta.findOne({
          where: {
            post_id: postId,
            meta_key: '_thumbnail_id'
          }
        }).then( res => {
          if (res){
            let meta_key = amazonS3 ? 'amazonS3_info' : '_wp_attached_file';

            return Post.findOne({
              where: {
                id: Number(res.dataValues.meta_value)
              },
              include: {
                model: Postmeta,
                where: {
                  meta_key:meta_key
                },
                limit: 1
              }
            }).then( post => {
              if (post.wp_postmeta[0]){
                const thumbnail = post.wp_postmeta[0].dataValues.meta_value;
                const thumbnailSrc = amazonS3 ?
                  uploadDirectory + PHPUnserialize.unserialize(thumbnail).key :
                  uploadDirectory + thumbnail;

                return thumbnailSrc
              } else {
                return null;
              }
            })
          } else {
            return
          }
        })
      },
      getPostmetaById(metaId, keys){
        return Postmeta.findOne({
          where: {
            meta_id: metaId,
            meta_key: {
              $in: keys
            }
          }
        })
      },
      getPostmeta(postId, keys){
        return Postmeta.findAll({
          where: {
            post_id: postId,
            meta_key: {
              $in: keys
            }
          }
        })
      },
      getMenu(name){
        return Terms.findOne({
          where: {
            slug: name
          },
          include: [{
            model: TermRelationships,
            include: [{
              model: Post,
              include: [Postmeta]
            }]
          }]
        }).then ( res => {
          if (res){
            let menu = {
              id: null,
              name: name,
              items: null,
            };
            menu.id = res.term_id;
            const relationship = res.wp_term_relationships;
            const posts = _.map(_.pluck (relationship, 'wp_post'), 'dataValues');
            const navItems = [];

            const parentIds = _.pluck(_.filter(posts, post=>{
              return post.post_parent == 0
            }), 'id');

            _.map(_.sortBy(posts, 'post_parent'), post => {
              let navItem = {};
              let postmeta = _.pluck(post.wp_postmeta, 'dataValues');
              let isParent = _.includes( parentIds, post.id);
              let linkedId = Number(_.pluck(_.filter(postmeta, meta => {
                return meta.meta_key == '_menu_item_object_id'
              }), 'meta_value'));

              if (isParent){
                navItem.id = post.id;
                navItem.order = post.menu_order;
                navItem.linkedId = linkedId;
                navItem.children = [];
                navItems.push(navItem);
              } else {
                let parentId = Number(_.pluck(_.filter(postmeta, meta => {
                  return meta.meta_key == '_menu_item_menu_item_parent'
                }), 'meta_value'));
                let existing = _.findWhere(navItems, {'id' : parentId})

                if (existing){
                  existing.children.push({id: post.id, linkedId: linkedId })
                }
              }

              menu.items = navItems;
            });

            return menu;
          }
        });
      }
    }
  }
}
<commit_msg>removing db.js<commit_after><|endoftext|>