<commit_before>'use strict';

const path = require('path');
const fs = require('fs');
const expect = require('chai').expect;
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const tmp = require('tmp');
const Plugin = require('../');

describe('rsvg-brunch', function () {

  // Brunch will automatically supply the default public directory path if it is
  // not explicitly overridden by the user
  const defaultConfig = {paths: {public: 'public'}};

  function getLoggySpy() {
    return {
      info: sinon.spy(),
      warn: sinon.spy(),
      error: sinon.spy()
    };
  }

  it('should initialize with empty brunch config', function () {
    const plugin = new Plugin(defaultConfig);
    expect(plugin).to.be.ok;
  });

  it('should initialize with empty plugins config', function () {
    const plugin = new Plugin(
      Object.assign({}, defaultConfig, {plugins: {}}));
    expect(plugin).to.be.ok;
  });

  it('should initialize with empty plugin config', function () {
    const plugin = new Plugin(
        Object.assign({}, defaultConfig, {plugins: {rsvg: {}}}));
    expect(plugin).to.be.ok;
  });

  it('should require Rsvg module if installed', function () {
    const plugin = new Plugin(defaultConfig);
    expect(plugin).to.have.property('Rsvg');
  });

  it('should catch error if system librsvg is not installed', function () {
    const loggySpy = getLoggySpy();
    const ProxiedPlugin = proxyquire('../', {
      librsvg: null,
      loggy: loggySpy
    });
    const plugin = new ProxiedPlugin(defaultConfig);
    expect(plugin).not.to.have.property('Rsvg');
    sinon.assert.calledOnce(loggySpy.warn);
  });

  describe('extendOutputProps', function () {

    let conversion;
    beforeEach(function () {
      conversion = {
        input: 'input.svg',
        outputDefaults: {},
        output: [{width: 200, height: 100}]
      };
    });

    it('should apply global output defaults', function () {
      conversion.output[0].path = 'output.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('format', 'png');
    });

    it('should apply conversion output defaults', function () {
      conversion.outputDefaults.format = 'abc';
      conversion.outputDefaults.path = 'output.abc';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('format', 'abc');
    });

    it('should allow output file to override defaults', function () {
      conversion.outputDefaults.format = 'abc';
      conversion.output[0].format = 'def';
      conversion.output[0].path = 'output.def';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('format', 'def');
    });

    it('should prepend public directory to output file path', function () {
      conversion.output[0].path = 'output.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output.png');
    });

    it('should supply output file height if missing', function () {
      conversion.output[0].path = 'output.png';
      delete conversion.output[0].height;
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('height', 200);
    });

    it('should supply output file width if missing', function () {
      conversion.output[0].path = 'output.png';
      delete conversion.output[0].width;
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('width', 100);
    });

    it('should evaluate {width} path variable', function () {
      conversion.outputDefaults.path = 'output-{width}.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output-200.png');
    });

    it('should evaluate {height} path variable', function () {
      conversion.outputDefaults.path = 'output-{height}.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output-100.png');
    });

    it('should evaluate {format} path variable', function () {
      conversion.outputDefaults.path = 'output.{format}';
      conversion.output[0].format = 'abc';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output.abc');
    });

    it('should evaluate {id} path variable', function () {
      conversion.outputDefaults.path = 'output-{id}.png';
      conversion.output[0].id = 'foo';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output-foo.png');
    });

  });

  describe('convertSvg', function () {

    let outputFile;
    beforeEach(function () {
      outputFile = {
        format: 'png',
        width: 200,
        height: 200,
        path: path.join(
          tmp.dirSync().name,
          tmp.tmpNameSync({template: 'XXXXXX.png'})
        )
      };
    });

    it('should resolve with correct params', function (done) {
      const plugin = new Plugin(defaultConfig);
      const outputPromise = plugin.convertSvg('test/input.svg', outputFile);
      outputPromise.then(() => {
        expect(fs.existsSync(outputFile.path)).to.be.true;
        fs.unlinkSync(outputFile.path);
        done();
      }).catch((error) => {
        done(error);
      });
    });

    it('should reject with invalid params', function (done) {
      // width cannot be zero; will cause librsvg to throw an error
      outputFile.width = 0;
      const plugin = new Plugin(defaultConfig);
      const outputPromise = plugin.convertSvg('test/input.svg', outputFile);
      outputPromise.then(() => {
        done(new Error('expected promise to reject, but resolved instead'));
      }).catch(() => {
        expect(fs.existsSync(outputFile.path)).to.be.false;
        done();
      });
    });

  });

  describe('handleConversion', function () {

    let conversion;
    beforeEach(function () {
      conversion = {
        input: 'test/input.svg',
        outputDefaults: {
          path: path.join(
            tmp.dirSync().name,
            tmp.tmpNameSync({template: 'XXXXXX-{width}.png'})
          )
        },
        output: [
          {width: 32},
          {width: 64},
          {width: 128},
          {width: 256},
          {width: 384},
          {width: 512}
        ]
      };
    });

    it('should display success message after all outputs finish', function (done) {
      const loggySpy = getLoggySpy();
      const ProxiedPlugin = proxyquire('../', {loggy: loggySpy});
      const plugin = new ProxiedPlugin(defaultConfig);
      const conversionPromise = plugin.handleConversion(conversion);
      conversionPromise.then(() => {
        sinon.assert.calledOnce(loggySpy.info);
        sinon.assert.calledWith(loggySpy.info, sinon.match(/6 of 6/gi));
        done();
      }).catch((error) => {
        done(error);
      });
    });

    it('should display error for each unsuccessful output', function (done) {
      const loggySpy = getLoggySpy();
      const ProxiedPlugin = proxyquire('../', {loggy: loggySpy});
      const plugin = new ProxiedPlugin(defaultConfig);
      // Ensure that default extendOutputProps does not prepend /public
      // plugin.extendOutputProps;
      conversion.output[2].height = 0;
      conversion.output[4].height = 0;
      const conversionPromise = plugin.handleConversion(conversion);
      conversionPromise.then(() => {
        sinon.assert.calledTwice(loggySpy.error);
        sinon.assert.calledWith(loggySpy.error, sinon.match(/128/gi));
        sinon.assert.calledWith(loggySpy.error, sinon.match(/384/gi));
        done();
      }).catch((error) => {
        done(error);
      });
    });

  });

  it('should be registered as Brunch plugin', function () {
    expect(Plugin.prototype.brunchPlugin).to.be.true;
  });

});
<commit_msg>Add tests for onCompile()<commit_after>'use strict';

const path = require('path');
const fs = require('fs');
const expect = require('chai').expect;
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const tmp = require('tmp');
const Plugin = require('../');

describe('rsvg-brunch', function () {

  // Brunch will automatically supply the default public directory path if it is
  // not explicitly overridden by the user
  const defaultConfig = {paths: {public: 'public'}};

  function getLoggySpy() {
    return {
      info: sinon.spy(),
      warn: sinon.spy(),
      error: sinon.spy()
    };
  }

  it('should initialize with empty brunch config', function () {
    const plugin = new Plugin(defaultConfig);
    expect(plugin).to.be.ok;
  });

  it('should initialize with empty plugins config', function () {
    const plugin = new Plugin(
      Object.assign({}, defaultConfig, {plugins: {}}));
    expect(plugin).to.be.ok;
  });

  it('should initialize with empty plugin config', function () {
    const plugin = new Plugin(
        Object.assign({}, defaultConfig, {plugins: {rsvg: {}}}));
    expect(plugin).to.be.ok;
  });

  it('should require Rsvg module if installed', function () {
    const plugin = new Plugin(defaultConfig);
    expect(plugin).to.have.property('Rsvg');
  });

  it('should catch error if system librsvg is not installed', function () {
    const loggySpy = getLoggySpy();
    const ProxiedPlugin = proxyquire('../', {
      librsvg: null,
      loggy: loggySpy
    });
    const plugin = new ProxiedPlugin(defaultConfig);
    expect(plugin).not.to.have.property('Rsvg');
    sinon.assert.calledOnce(loggySpy.warn);
  });

  describe('extendOutputProps', function () {

    let conversion;
    beforeEach(function () {
      conversion = {
        input: 'input.svg',
        outputDefaults: {},
        output: [{width: 200, height: 100}]
      };
    });

    it('should apply global output defaults', function () {
      conversion.output[0].path = 'output.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('format', 'png');
    });

    it('should apply conversion output defaults', function () {
      conversion.outputDefaults.format = 'abc';
      conversion.outputDefaults.path = 'output.abc';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('format', 'abc');
    });

    it('should allow output file to override defaults', function () {
      conversion.outputDefaults.format = 'abc';
      conversion.output[0].format = 'def';
      conversion.output[0].path = 'output.def';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('format', 'def');
    });

    it('should prepend public directory to output file path', function () {
      conversion.output[0].path = 'output.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output.png');
    });

    it('should supply output file height if missing', function () {
      conversion.output[0].path = 'output.png';
      delete conversion.output[0].height;
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('height', 200);
    });

    it('should supply output file width if missing', function () {
      conversion.output[0].path = 'output.png';
      delete conversion.output[0].width;
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('width', 100);
    });

    it('should evaluate {width} path variable', function () {
      conversion.outputDefaults.path = 'output-{width}.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output-200.png');
    });

    it('should evaluate {height} path variable', function () {
      conversion.outputDefaults.path = 'output-{height}.png';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output-100.png');
    });

    it('should evaluate {format} path variable', function () {
      conversion.outputDefaults.path = 'output.{format}';
      conversion.output[0].format = 'abc';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output.abc');
    });

    it('should evaluate {id} path variable', function () {
      conversion.outputDefaults.path = 'output-{id}.png';
      conversion.output[0].id = 'foo';
      const plugin = new Plugin(defaultConfig);
      expect(plugin.extendOutputProps(conversion, conversion.output[0]))
        .to.have.property('path', 'public/output-foo.png');
    });

  });

  describe('convertSvg', function () {

    let outputFile;
    beforeEach(function () {
      outputFile = {
        format: 'png',
        width: 200,
        height: 200,
        path: path.join(
          tmp.dirSync().name,
          tmp.tmpNameSync({template: 'XXXXXX.png'})
        )
      };
    });

    it('should resolve with correct params', function (done) {
      const plugin = new Plugin(defaultConfig);
      const outputPromise = plugin.convertSvg('test/input.svg', outputFile);
      outputPromise.then(() => {
        expect(fs.existsSync(outputFile.path)).to.be.true;
        fs.unlinkSync(outputFile.path);
        done();
      }).catch((error) => {
        done(error);
      });
    });

    it('should reject with invalid params', function (done) {
      // width cannot be zero; will cause librsvg to throw an error
      outputFile.width = 0;
      const plugin = new Plugin(defaultConfig);
      const outputPromise = plugin.convertSvg('test/input.svg', outputFile);
      outputPromise.then(() => {
        done(new Error('expected promise to reject, but resolved instead'));
      }).catch(() => {
        expect(fs.existsSync(outputFile.path)).to.be.false;
        done();
      });
    });

  });

  describe('handleConversion', function () {

    let conversion;
    beforeEach(function () {
      conversion = {
        input: 'test/input.svg',
        outputDefaults: {
          path: path.join(
            tmp.dirSync().name,
            tmp.tmpNameSync({template: 'XXXXXX-{width}.png'})
          )
        },
        output: [
          {width: 32},
          {width: 64},
          {width: 128},
          {width: 256},
          {width: 384},
          {width: 512}
        ]
      };
    });

    it('should display success message after all outputs finish', function (done) {
      const loggySpy = getLoggySpy();
      const ProxiedPlugin = proxyquire('../', {loggy: loggySpy});
      const plugin = new ProxiedPlugin(defaultConfig);
      const conversionPromise = plugin.handleConversion(conversion);
      conversionPromise.then(() => {
        sinon.assert.calledOnce(loggySpy.info);
        sinon.assert.calledWith(loggySpy.info, sinon.match(/6 of 6/gi));
        done();
      }).catch((error) => {
        done(error);
      });
    });

    it('should display error for each unsuccessful output', function (done) {
      const loggySpy = getLoggySpy();
      const ProxiedPlugin = proxyquire('../', {loggy: loggySpy});
      const plugin = new ProxiedPlugin(defaultConfig);
      // Ensure that default extendOutputProps does not prepend /public
      // plugin.extendOutputProps;
      conversion.output[2].height = 0;
      conversion.output[4].height = 0;
      const conversionPromise = plugin.handleConversion(conversion);
      conversionPromise.then(() => {
        sinon.assert.calledTwice(loggySpy.error);
        sinon.assert.calledWith(loggySpy.error, sinon.match(/128/gi));
        sinon.assert.calledWith(loggySpy.error, sinon.match(/384/gi));
        done();
      }).catch((error) => {
        done(error);
      });
    });

  });

  describe('onCompile', function () {

    let config;
    beforeEach(function () {
      config = {
        plugins: {
          rsvg: {
            conversions: [
              sinon.spy(),
              sinon.spy(),
              sinon.spy()
            ]
          }
        }
      };
    });

    it('should run conversions when librsvg is available', function () {
      const plugin = new Plugin(Object.assign(defaultConfig, config));
      plugin.handleConversion = sinon.spy();
      plugin.onCompile();
      const conversions = config.plugins.rsvg.conversions;
      sinon.assert.calledWith(plugin.handleConversion, conversions[0]);
      sinon.assert.calledWith(plugin.handleConversion, conversions[1]);
      sinon.assert.calledWith(plugin.handleConversion, conversions[2]);
    });

    it('should not run conversions when librsvg is not available', function () {
      const plugin = new Plugin(Object.assign(defaultConfig, config));
      plugin.handleConversion = sinon.spy();
      delete plugin.Rsvg;
      plugin.onCompile();
      sinon.assert.notCalled(plugin.handleConversion);
    });

  });

  it('should be registered as Brunch plugin', function () {
    expect(Plugin.prototype.brunchPlugin).to.be.true;
  });

});
<|endoftext|>


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

  Foundation.libs.interchange = {
    name : 'interchange',

    version : '5.0.0',

    cache : {},

    images_loaded : false,
    nodes_loaded : false,

    settings : {
      load_attr : 'interchange',

      named_queries : {
        'default' : 'only screen',
        small : Foundation.media_queries.small,
        medium : Foundation.media_queries.medium,
        large : Foundation.media_queries.large,
        xlarge : Foundation.media_queries.xlarge,
        xxlarge: Foundation.media_queries.xxlarge,
        landscape : 'only screen and (orientation: landscape)',
        portrait : 'only screen and (orientation: portrait)',
        retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
          'only screen and (min--moz-device-pixel-ratio: 2),' +
          'only screen and (-o-min-device-pixel-ratio: 2/1),' +
          'only screen and (min-device-pixel-ratio: 2),' +
          'only screen and (min-resolution: 192dpi),' +
          'only screen and (min-resolution: 2dppx)'
      },

      directives : {
        replace: function (el, path, trigger) {
          // The trigger argument, if called within the directive, fires
          // an event named after the directive on the element, passing
          // any parameters along to the event that you pass to trigger.
          //
          // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c)
          //
          // This allows you to bind a callback like so:
          // $('#interchangeContainer').on('replace', function (e, a, b, c) {
          //   console.log($(this).html(), a, b, c);
          // });

          if (/IMG/.test(el[0].nodeName)) {
            var orig_path = el[0].src;

            if (new RegExp(path, 'i').test(orig_path)) return;

            el[0].src = path;

            return trigger(el[0].src);
          }
          var last_path = el.data('interchange-last-path');

          if (last_path == path) return;

          return $.get(path, function (response) {
            el.html(response);
            el.data('interchange-last-path', path);
            trigger();
          });

        }
      }
    },

    init : function (scope, method, options) {
      Foundation.inherit(this, 'throttle');

      this.data_attr = 'data-' + this.settings.load_attr;
      $.extend(true, this.settings, method, options);

      this.bindings(method, options);
      this.load('images');
      this.load('nodes');
    },

    events : function () {
      var self = this;

      $(window)
        .off('.interchange')
        .on('resize.fndtn.interchange', self.throttle(function () {
          self.resize.call(self);
        }, 50));

      return this;
    },

    resize : function () {
      var cache = this.cache;

      if(!this.images_loaded || !this.nodes_loaded) {
        setTimeout($.proxy(this.resize, this), 50);
        return;
      }

      for (var uuid in cache) {
        if (cache.hasOwnProperty(uuid)) {
          var passed = this.results(uuid, cache[uuid]);

          if (passed) {
            this.settings.directives[passed
              .scenario[1]](passed.el, passed.scenario[0], function () {
                if (arguments[0] instanceof Array) {
                  var args = arguments[0];
                } else {
                  var args = Array.prototype.slice.call(arguments, 0);
                }

                passed.el.trigger(passed.scenario[1], args);
              });
          }
        }
      }

    },

    results : function (uuid, scenarios) {
      var count = scenarios.length;

      if (count > 0) {
        var el = this.S('[data-uuid="' + uuid + '"]');

        for (var i = count - 1; i >= 0; i--) {
          var mq, rule = scenarios[i][2];
          if (this.settings.named_queries.hasOwnProperty(rule)) {
            mq = matchMedia(this.settings.named_queries[rule]);
          } else {
            mq = matchMedia(rule);
          }
          if (mq.matches) {
            return {el: el, scenario: scenarios[i]};
          }
        }
      }

      return false;
    },

    load : function (type, force_update) {
      if (typeof this['cached_' + type] === 'undefined' || force_update) {
        this['update_' + type]();
      }

      return this['cached_' + type];
    },

    update_images : function () {
      var images = this.S('img[' + this.data_attr + ']'),
          count = images.length,
          loaded_count = 0,
          data_attr = this.data_attr;

      this.cache = {};
      this.cached_images = [];
      this.images_loaded = (count === 0);

      for (var i = count - 1; i >= 0; i--) {
        loaded_count++;
        if (images[i]) {
          var str = images[i].getAttribute(data_attr) || '';

          if (str.length > 0) {
            this.cached_images.push(images[i]);
          }
        }

        if(loaded_count === count) {
          this.images_loaded = true;
          this.enhance('images');
        }
      }

      return this;
    },

    update_nodes : function () {
      var nodes = this.S('[' + this.data_attr + ']:not(img)'),
          count = nodes.length,
          loaded_count = 0,
          data_attr = this.data_attr;

      this.cached_nodes = [];
      // Set nodes_loaded to true if there are no nodes
      // this.nodes_loaded = false;
      this.nodes_loaded = (count === 0);

      for (var i = count - 1; i >= 0; i--) {
        loaded_count++;
        var str = nodes[i].getAttribute(data_attr) || '';

        if (str.length > 0) {
          this.cached_nodes.push(nodes[i]);
        }

        if(loaded_count === count) {
          this.nodes_loaded = true;
          this.enhance('nodes');
        }
      }

      return this;
    },

    enhance : function (type) {
      var count = this['cached_' + type].length;

      for (var i = count - 1; i >= 0; i--) {
        this.object($(this['cached_' + type][i]));
      }

      return $(window).trigger('resize');
    },

    parse_params : function (path, directive, mq) {
      return [this.trim(path), this.convert_directive(directive), this.trim(mq)];
    },

    convert_directive : function (directive) {
      var trimmed = this.trim(directive);

      if (trimmed.length > 0) {
        return trimmed;
      }

      return 'replace';
    },

    object : function(el) {
      var raw_arr = this.parse_data_attr(el),
          scenarios = [], count = raw_arr.length;

      if (count > 0) {
        for (var i = count - 1; i >= 0; i--) {
          var split = raw_arr[i].split(/\((.*?)(\))$/);

          if (split.length > 1) {
            var cached_split = split[0].split(','),
                params = this.parse_params(cached_split[0],
                  cached_split[1], split[1]);

            scenarios.push(params);
          }
        }
      }

      return this.store(el, scenarios);
    },

    uuid : function (separator) {
      var delim = separator || "-";

      function S4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
      }

      return (S4() + S4() + delim + S4() + delim + S4()
        + delim + S4() + delim + S4() + S4() + S4());
    },

    store : function (el, scenarios) {
      var uuid = this.uuid(),
          current_uuid = el.data('uuid');

      if (current_uuid) return this.cache[current_uuid];

      el.attr('data-uuid', uuid);

      return this.cache[uuid] = scenarios;
    },

    trim : function(str) {
      if (typeof str === 'string') {
        return $.trim(str);
      }

      return str;
    },

    parse_data_attr : function (el) {
      var raw = el.data(this.settings.load_attr).split(/\[(.*?)\]/),
          count = raw.length, output = [];

      for (var i = count - 1; i >= 0; i--) {
        if (raw[i].replace(/[\W\d]+/, '').length > 4) {
          output.push(raw[i]);
        }
      }

      return output;
    },

    reflow : function () {
      this.load('images', true);
      this.load('nodes', true);
    }

  };

}(jQuery, this, this.document));<commit_msg>remove dependence on CSS3 :not selector<commit_after>;(function ($, window, document, undefined) {
  'use strict';

  Foundation.libs.interchange = {
    name : 'interchange',

    version : '5.0.0',

    cache : {},

    images_loaded : false,
    nodes_loaded : false,

    settings : {
      load_attr : 'interchange',

      named_queries : {
        'default' : 'only screen',
        small : Foundation.media_queries.small,
        medium : Foundation.media_queries.medium,
        large : Foundation.media_queries.large,
        xlarge : Foundation.media_queries.xlarge,
        xxlarge: Foundation.media_queries.xxlarge,
        landscape : 'only screen and (orientation: landscape)',
        portrait : 'only screen and (orientation: portrait)',
        retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
          'only screen and (min--moz-device-pixel-ratio: 2),' +
          'only screen and (-o-min-device-pixel-ratio: 2/1),' +
          'only screen and (min-device-pixel-ratio: 2),' +
          'only screen and (min-resolution: 192dpi),' +
          'only screen and (min-resolution: 2dppx)'
      },

      directives : {
        replace: function (el, path, trigger) {
          // The trigger argument, if called within the directive, fires
          // an event named after the directive on the element, passing
          // any parameters along to the event that you pass to trigger.
          //
          // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c)
          //
          // This allows you to bind a callback like so:
          // $('#interchangeContainer').on('replace', function (e, a, b, c) {
          //   console.log($(this).html(), a, b, c);
          // });

          if (/IMG/.test(el[0].nodeName)) {
            var orig_path = el[0].src;

            if (new RegExp(path, 'i').test(orig_path)) return;

            el[0].src = path;

            return trigger(el[0].src);
          }
          var last_path = el.data('interchange-last-path');

          if (last_path == path) return;

          return $.get(path, function (response) {
            el.html(response);
            el.data('interchange-last-path', path);
            trigger();
          });

        }
      }
    },

    init : function (scope, method, options) {
      Foundation.inherit(this, 'throttle');

      this.data_attr = 'data-' + this.settings.load_attr;
      $.extend(true, this.settings, method, options);

      this.bindings(method, options);
      this.load('images');
      this.load('nodes');
    },

    events : function () {
      var self = this;

      $(window)
        .off('.interchange')
        .on('resize.fndtn.interchange', self.throttle(function () {
          self.resize.call(self);
        }, 50));

      return this;
    },

    resize : function () {
      var cache = this.cache;

      if(!this.images_loaded || !this.nodes_loaded) {
        setTimeout($.proxy(this.resize, this), 50);
        return;
      }

      for (var uuid in cache) {
        if (cache.hasOwnProperty(uuid)) {
          var passed = this.results(uuid, cache[uuid]);

          if (passed) {
            this.settings.directives[passed
              .scenario[1]](passed.el, passed.scenario[0], function () {
                if (arguments[0] instanceof Array) {
                  var args = arguments[0];
                } else {
                  var args = Array.prototype.slice.call(arguments, 0);
                }

                passed.el.trigger(passed.scenario[1], args);
              });
          }
        }
      }

    },

    results : function (uuid, scenarios) {
      var count = scenarios.length;

      if (count > 0) {
        var el = this.S('[data-uuid="' + uuid + '"]');

        for (var i = count - 1; i >= 0; i--) {
          var mq, rule = scenarios[i][2];
          if (this.settings.named_queries.hasOwnProperty(rule)) {
            mq = matchMedia(this.settings.named_queries[rule]);
          } else {
            mq = matchMedia(rule);
          }
          if (mq.matches) {
            return {el: el, scenario: scenarios[i]};
          }
        }
      }

      return false;
    },

    load : function (type, force_update) {
      if (typeof this['cached_' + type] === 'undefined' || force_update) {
        this['update_' + type]();
      }

      return this['cached_' + type];
    },

    update_images : function () {
      var images = this.S('img[' + this.data_attr + ']'),
          count = images.length,
          loaded_count = 0,
          data_attr = this.data_attr;

      this.cache = {};
      this.cached_images = [];
      this.images_loaded = (count === 0);

      for (var i = count - 1; i >= 0; i--) {
        loaded_count++;
        if (images[i]) {
          var str = images[i].getAttribute(data_attr) || '';

          if (str.length > 0) {
            this.cached_images.push(images[i]);
          }
        }

        if(loaded_count === count) {
          this.images_loaded = true;
          this.enhance('images');
        }
      }

      return this;
    },

    update_nodes : function () {
      var nodes = this.S('[' + this.data_attr + ']').not('img'),
          count = nodes.length,
          loaded_count = 0,
          data_attr = this.data_attr;

      this.cached_nodes = [];
      // Set nodes_loaded to true if there are no nodes
      // this.nodes_loaded = false;
      this.nodes_loaded = (count === 0);

      for (var i = count - 1; i >= 0; i--) {
        loaded_count++;
        var str = nodes[i].getAttribute(data_attr) || '';

        if (str.length > 0) {
          this.cached_nodes.push(nodes[i]);
        }

        if(loaded_count === count) {
          this.nodes_loaded = true;
          this.enhance('nodes');
        }
      }

      return this;
    },

    enhance : function (type) {
      var count = this['cached_' + type].length;

      for (var i = count - 1; i >= 0; i--) {
        this.object($(this['cached_' + type][i]));
      }

      return $(window).trigger('resize');
    },

    parse_params : function (path, directive, mq) {
      return [this.trim(path), this.convert_directive(directive), this.trim(mq)];
    },

    convert_directive : function (directive) {
      var trimmed = this.trim(directive);

      if (trimmed.length > 0) {
        return trimmed;
      }

      return 'replace';
    },

    object : function(el) {
      var raw_arr = this.parse_data_attr(el),
          scenarios = [], count = raw_arr.length;

      if (count > 0) {
        for (var i = count - 1; i >= 0; i--) {
          var split = raw_arr[i].split(/\((.*?)(\))$/);

          if (split.length > 1) {
            var cached_split = split[0].split(','),
                params = this.parse_params(cached_split[0],
                  cached_split[1], split[1]);

            scenarios.push(params);
          }
        }
      }

      return this.store(el, scenarios);
    },

    uuid : function (separator) {
      var delim = separator || "-";

      function S4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
      }

      return (S4() + S4() + delim + S4() + delim + S4()
        + delim + S4() + delim + S4() + S4() + S4());
    },

    store : function (el, scenarios) {
      var uuid = this.uuid(),
          current_uuid = el.data('uuid');

      if (current_uuid) return this.cache[current_uuid];

      el.attr('data-uuid', uuid);

      return this.cache[uuid] = scenarios;
    },

    trim : function(str) {
      if (typeof str === 'string') {
        return $.trim(str);
      }

      return str;
    },

    parse_data_attr : function (el) {
      var raw = el.data(this.settings.load_attr).split(/\[(.*?)\]/),
          count = raw.length, output = [];

      for (var i = count - 1; i >= 0; i--) {
        if (raw[i].replace(/[\W\d]+/, '').length > 4) {
          output.push(raw[i]);
        }
      }

      return output;
    },

    reflow : function () {
      this.load('images', true);
      this.load('nodes', true);
    }

  };

}(jQuery, this, this.document));
<|endoftext|>


<commit_before>$( document ).ready(function() {

  $('#playButton').on('click', function() {

    $( '#status' ).text( "starting" );
    this.disabled = true;
    $('#stopButton').removeAttr("disabled");

    $.ajax({
      type: "POST",
      data: {"action": "start"},
      success: function(response) {
        console.log(response);
        if (response.status != "error") $( '#status' ).text(response.status);
        else console.log(response)},
          failure: function() {
            $( '#status' ).text( "Error (could not start crawl)" );
          }
        });
  });

  $('#stopButton').on('click', function() {

    $( '#status' ).text( "stopping" );
    this.disabled = true;

    $.ajax({
      type: "POST",
      data: {"action": "stop"},
      success: function(response) {
        console.log(response);
        if (response.status != "error") $( '#status' ).text(response.status);
        else console.log(response)},
          failure: function() {
            $( '#status' ).text( "Error (could not stop crawl)" );
          }
        });
  });

  setInterval(function(){
    $.ajax({
      type: "POST",
      data: {"action": "status"},
      success: function(response){
        $( '#status' ).text(response.status);
        $( '#stats-pages' ).text(response.pages_crawled);
        $( '#stats-harvest' ).text(response.harvest_rate);
        if (response.status == "stopped") {
          $('#stopButton').attr("disabled", true);
        }
      }
    });
  }, 5000);

});<commit_msg>Play button now shows up after crawl has stopped.<commit_after>$( document ).ready(function() {

  $('#playButton').on('click', function() {

    $( '#status' ).text( "starting" );
    this.disabled = true;
    $('#stopButton').removeAttr("disabled");

    $.ajax({
      type: "POST",
      data: {"action": "start"},
      success: function(response) {
        console.log(response);
        if (response.status != "error") $( '#status' ).text(response.status);
        else console.log(response)},
          failure: function() {
            $( '#status' ).text( "Error (could not start crawl)" );
          }
    });
  });

  $('#stopButton').on('click', function() {

    $( '#status' ).text( "stopping" );
    this.disabled = true;

    $.ajax({
      type: "POST",
      data: {"action": "stop"},
      success: function(response) {
        console.log(response);
        if (response.status != "error") $( '#status' ).text(response.status);
        else console.log(response)},
          failure: function() {
            $( '#status' ).text( "Error (could not stop crawl)" );
          }
        });
  });

  setInterval(function(){
    $.ajax({
      type: "POST",
      data: {"action": "status"},
      success: function(response){
        $( '#status' ).text(response.status);
        $( '#stats-pages' ).text(response.pages_crawled);
        $( '#stats-harvest' ).text(response.harvest_rate);
        if (response.status == "stopped") {
          $('#stopButton').attr("disabled", true);
          $('#playButton').removeAttr("disabled");
        }
      }
    });
  }, 5000);

});
<|endoftext|>


<commit_before>$(document).ready(function(){
	var msg = $('#error').text();
    var course = $('#course');
    var assign = $('#assign');
    var selectedCourse = "*";
	if (msg.length > 0) {
		UIkit.notification({message: msg, pos: 'top-center', status: 'danger'});
	}

    assign.empty();
    course.empty();

    $('#filePlaceholder').text("Please select files to upload for Assignment ??");
    $('#evaluate').text("Submit Files for Assignment ??");

    $.ajax({
        type: "get",
        url: '/tool/course',
        success: function (res, status) {

            if(res.result.length == 0)
            {
                assign.toggleClass("uk-hidden", true);
                course.toggleClass("uk-hidden", true);
                $('#courseLab').toggleClass("uk-hidden", true);
                $('#assignLab').toggleClass("uk-hidden", true);

            }
            else
            {

                assign.toggleClass("uk-hidden", true);
                course.toggleClass("uk-hidden", false);
                $('#courseLab').toggleClass("uk-hidden", false);
                $('#assignLab').toggleClass("uk-hidden", true);

                var optsStr = "";

                optsStr += "<option value='None'>None</option>"
                for(var i = 0; i < res.result.length; i++)
                {
                    optsStr += "<option value='" + res.result[i] + "'>" + res.result[i] + "</option>";
                }
                course.append( optsStr );
            }

        },
        error: function(req, err) {
            console.log(err);
        }
    })

    // $.ajax({
    //     type: "post",
    //     url: '/tool/assignment',
    //     data: {
    //         insert: selectedCourse
    //     },
    //     success: function (res, status) {

    //         if(res.result.length == 0)
    //         {
    //             assign.toggleClass("uk-hidden", true);
    //             course.toggleClass("uk-hidden", true);
    //             $('#courseLab').toggleClass("uk-hidden", true);
    //             $('#assignLab').toggleClass("uk-hidden", true);

    //         }
    //         else
    //         {

    //             var optsStr = "";
    //             optsStr += "<option value='None'>None</option>"

    //             for(var i = 0; i < res.result.length; i++)
    //             {
    //                 optsStr += "<option value='" + res.result[i] + "'>" + res.result[i] + "</option>";
    //             }

    //             assign.append( optsStr );
    //         }
    //     },
    //     error: function(req, err) {
    //         console.log(err);
    //     }
    // })

});

$("#course").change(function() {
    var assign = $('#assign');
    var course = $('#course');
    assign.empty();

    var courseSelected = course.find(":selected").text();

    $.ajax({
        type: "post",
        url: 'tool/assignment',
        data: {
            insert: courseSelected
        },
        success: function (res, status) {
            var optsStr = "";

            optsStr += "<option value='None'>None</option>"

            for(var i = 0; i < res.result.length; i++)
            {
                optsStr += "<option value='" + res.result[i] + "'>" + res.result[i] + "</option>";
            }

            assign.append( optsStr );

            if(courseSelected == "None")
            {
                assign.toggleClass("uk-hidden", true);
                $('#assignLab').toggleClass("uk-hidden", true);

                $('#filePlaceholder').text("Please select files to upload for Assignment ??");
                $('#evaluate').text("Submit Files for Assignment ??");
            }
            else
            {
                assign.toggleClass("uk-hidden", false);
                $('#assignLab').toggleClass("uk-hidden", false);

                $('#evaluate').text("Submit Files for " + course.find(":selected").text() + " " + assign.find(":selected").text());
                $('#filePlaceholder').text("Please select files to upload for " + course.find(":selected").text() + " " + assign.find(":selected").text())
            }

        }
    })

})

$("#settingsToggle").click(function() {
    $("#settingsToggle").toggleClass("uk-button-primary");
});

$('#error').bind("DOMSubtreeModified",function(){
	var msg = $('#error').text();
	if (msg.length > 0) {
		UIkit.notification({message: msg, pos: 'top-center', status: 'danger'});
	}
});

$("#toolPreference").submit(function(event) {
    var val = event.originalEvent.explicitOriginalTarget.innerHTML;

    $.ajax({
        type: "post",
        url:'/tool/preferences',
        dataType: 'json',
        data: {
        	tool: val
        },
        success: function (data, textStatus) {
        	location.reload(true);
        },
        error: function (req, err){
            location.reload(true);
        }
    });
});

<commit_msg>another bugfix for the assignment selection<commit_after>$(document).ready(function(){
	var msg = $('#error').text();
    var course = $('#course');
    var assign = $('#assign');
    var selectedCourse = "*";
	if (msg.length > 0) {
		UIkit.notification({message: msg, pos: 'top-center', status: 'danger'});
	}

    assign.empty();
    course.empty();

    $('#filePlaceholder').text("Please select files to upload for Assignment ??");
    $('#evaluate').text("Submit Files for Assignment ??");

    $.ajax({
        type: "get",
        url: '/tool/course',
        success: function (res, status) {

            if(res.result.length == 0)
            {
                assign.toggleClass("uk-hidden", true);
                course.toggleClass("uk-hidden", true);
                $('#courseLab').toggleClass("uk-hidden", true);
                $('#assignLab').toggleClass("uk-hidden", true);

            }
            else
            {

                assign.toggleClass("uk-hidden", true);
                course.toggleClass("uk-hidden", false);
                $('#courseLab').toggleClass("uk-hidden", false);
                $('#assignLab').toggleClass("uk-hidden", true);

                var optsStr = "";

                optsStr += "<option value='None'>None</option>"
                for(var i = 0; i < res.result.length; i++)
                {
                    optsStr += "<option value='" + res.result[i] + "'>" + res.result[i] + "</option>";
                }
                course.append( optsStr );
            }

        },
        error: function(req, err) {
            console.log(err);
        }
    })

    // $.ajax({
    //     type: "post",
    //     url: '/tool/assignment',
    //     data: {
    //         insert: selectedCourse
    //     },
    //     success: function (res, status) {

    //         if(res.result.length == 0)
    //         {
    //             assign.toggleClass("uk-hidden", true);
    //             course.toggleClass("uk-hidden", true);
    //             $('#courseLab').toggleClass("uk-hidden", true);
    //             $('#assignLab').toggleClass("uk-hidden", true);

    //         }
    //         else
    //         {

    //             var optsStr = "";
    //             optsStr += "<option value='None'>None</option>"

    //             for(var i = 0; i < res.result.length; i++)
    //             {
    //                 optsStr += "<option value='" + res.result[i] + "'>" + res.result[i] + "</option>";
    //             }

    //             assign.append( optsStr );
    //         }
    //     },
    //     error: function(req, err) {
    //         console.log(err);
    //     }
    // })

});

$("#course").change(function() {
    var assign = $('#assign');
    var course = $('#course');
    assign.empty();

    var courseSelected = course.find(":selected").text();

    $.ajax({
        type: "post",
        url: 'tool/assignment',
        data: {
            insert: courseSelected
        },
        success: function (res, status) {
            var optsStr = "";

            optsStr += "<option value='None'>None</option>"

            for(var i = 0; i < res.result.length; i++)
            {
                optsStr += "<option value='" + res.result[i] + "'>" + res.result[i] + "</option>";
            }

            assign.append( optsStr );

            if(courseSelected == "None")
            {
                assign.toggleClass("uk-hidden", true);
                $('#assignLab').toggleClass("uk-hidden", true);

                $('#filePlaceholder').text("Please select files to upload for Assignment ??");
                $('#evaluate').text("Submit Files for Assignment ??");
            }
            else
            {
                assign.toggleClass("uk-hidden", false);
                $('#assignLab').toggleClass("uk-hidden", false);

                // $('#evaluate').text("Submit Files for " + course.find(":selected").text() + " " + assign.find(":selected").text());
                // $('#filePlaceholder').text("Please select files to upload for " + course.find(":selected").text() + " " + assign.find(":selected").text())
            }

        }
    })

});

$("#assign").change(function() {
    var assign = $('#assign');
    var course = $('#course');

    if(assign.find(":selected").text() == "None")
    {
         $('#evaluate').text("Submit Files for " + course.find(":selected").text() + " Assignment ??");
         $('#filePlaceholder').text("Please select files to upload for " + course.find(":selected").text() + " Assignment ??");
    }
    else
    {
        $('#evaluate').text("Submit Files for " + course.find(":selected").text() + " " + assign.find(":selected").text());
        $('#filePlaceholder').text("Please select files to upload for " + course.find(":selected").text() + " " + assign.find(":selected").text())

    }

});

$("#settingsToggle").click(function() {
    $("#settingsToggle").toggleClass("uk-button-primary");
});

$('#error').bind("DOMSubtreeModified",function(){
	var msg = $('#error').text();
	if (msg.length > 0) {
		UIkit.notification({message: msg, pos: 'top-center', status: 'danger'});
	}
});

$("#toolPreference").submit(function(event) {
    var val = event.originalEvent.explicitOriginalTarget.innerHTML;

    $.ajax({
        type: "post",
        url:'/tool/preferences',
        dataType: 'json',
        data: {
        	tool: val
        },
        success: function (data, textStatus) {
        	location.reload(true);
        },
        error: function (req, err){
            location.reload(true);
        }
    });
});

<|endoftext|>


<commit_before>/*
* jQuery Mobile Framework : "checkboxradio" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
(function($, undefined ) {
$.widget( "mobile.checkboxradio", $.mobile.widget, {
	options: {
		theme: null
	},
	_create: function(){
		var self = this,
			input = this.element,
			label = input.closest("form,fieldset,[data-role='page']").find("label[for='" + input.attr( "id" ) + "']"),
			inputtype = input.attr( "type" ),
			checkedicon = "ui-icon-" + inputtype + "-on",
			uncheckedicon = "ui-icon-" + inputtype + "-off";

		if ( inputtype != "checkbox" && inputtype != "radio" ) { return; }

		// If there's no selected theme...
		if( !this.options.theme ) {
			this.options.theme = this.element.data( "theme" );
		}

		label
			.buttonMarkup({
				theme: this.options.theme,
				icon: this.element.parents( "[data-type='horizontal']" ).length ? undefined : uncheckedicon,
				shadow: false
			});

		// wrap the input + label in a div
		input
			.add( label )
			.wrapAll( "

" );

		label.bind({
			mouseover: function() {
				if( $(this).parent().is('.ui-disabled') ){ return false; }
			},

			"tap": function( event ){
				self._cacheVals();
				input.attr( "checked", inputtype === "radio" && true || !input.is( ":checked" ) );
				self._updateAll();
				event.preventDefault();
			},

			click: false

		});

		input
			.bind({
				mousedown: function(){
					this._cacheVals();
				},

				click: function(){
					self._updateAll();
				},

				focus: function() {
					label.addClass( "ui-focus" );
				},

				blur: function() {
					label.removeClass( "ui-focus" );
				}
			});

		this.refresh();

	},

	_cacheVals: function(){
		this._getInputSet().each(function(){
			$(this).data("cacheVal", $(this).is(":checked") );
		});
	},

	//returns either a set of radios with the same name attribute, or a single checkbox
	_getInputSet: function(){
		return this.element.closest( "form,fieldset,[data-role='page']" )
				.find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.element.attr( "type" ) +"']" );
	},

	_updateAll: function(){
		this._getInputSet().each(function(){
			var dVal = $(this).data("cacheVal");
			if( dVal && dVal !== $(this).is(":checked") || $(this).is( "[type='checkbox']" ) ){
				$(this).trigger("change");
			}
		})
		.checkboxradio( "refresh" );
	},

	refresh: function( ){
		var input = this.element,
			label = input.closest("form,fieldset,[data-role='page']").find("label[for='" + input.attr( "id" ) + "']"),
			inputtype = input.attr( "type" ),
			icon = label.find( ".ui-icon" ),
			checkedicon = "ui-icon-" + inputtype + "-on",
			uncheckedicon = "ui-icon-" + inputtype + "-off";

		if ( input[0].checked ) {
			label.addClass( "ui-btn-active" );
			icon.addClass( checkedicon );
			icon.removeClass( uncheckedicon );

		} else {
			label.removeClass( "ui-btn-active" );
			icon.removeClass( checkedicon );
			icon.addClass( uncheckedicon );
		}

		if( input.is( ":disabled" ) ){
			this.disable();
		}
		else {
			this.enable();
		}
	},

	disable: function(){
		this.element.attr("disabled",true).parent().addClass("ui-disabled");
	},

	enable: function(){
		this.element.attr("disabled",false).parent().removeClass("ui-disabled");
	}
});
})( jQuery );
<commit_msg>fixed a regression in some android 2.2 devices where checkboxes were toggling on and off on every click. Fixes #935 as well.<commit_after>/*
* jQuery Mobile Framework : "checkboxradio" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
(function($, undefined ) {
$.widget( "mobile.checkboxradio", $.mobile.widget, {
	options: {
		theme: null
	},
	_create: function(){
		var self = this,
			input = this.element,
			label = input.closest("form,fieldset,[data-role='page']").find("label[for='" + input.attr( "id" ) + "']"),
			inputtype = input.attr( "type" ),
			checkedicon = "ui-icon-" + inputtype + "-on",
			uncheckedicon = "ui-icon-" + inputtype + "-off";

		if ( inputtype != "checkbox" && inputtype != "radio" ) { return; }

		// If there's no selected theme...
		if( !this.options.theme ) {
			this.options.theme = this.element.data( "theme" );
		}

		label
			.buttonMarkup({
				theme: this.options.theme,
				icon: this.element.parents( "[data-type='horizontal']" ).length ? undefined : uncheckedicon,
				shadow: false
			});

		// wrap the input + label in a div
		input
			.add( label )
			.wrapAll( "

" );

		label.bind({
			mouseover: function() {
				if( $(this).parent().is('.ui-disabled') ){ return false; }
			},

			"touchmove": function( event ){
				var oe = event.originalEvent.touches[0];
				if( label.data("movestart") ){
					if( Math.abs( label.data("movestart")[0] - oe.pageX ) > 10 ||
						Math.abs( abel.data("movestart")[1] - oe.pageY ) > 10 ){
							label.data("moved", true);
						}
				}
				else{
					label.data("movestart", [ parseFloat( oe.pageX ), parseFloat( oe.pageY ) ]);
				}
			},

			"touchend mouseup": function( event ){
				label.removeData("movestart");
				if( label.data("etype") && label.data("etype") !== event.type || label.data("moved") ){
					label.removeData("etype").removeData("moved");
					if( label.data("moved") ){
						label.removeData("moved");
					}
					return false;
				}
				label.data( "etype", event.type );
				self._cacheVals();
				input.attr( "checked", inputtype === "radio" && true || !input.is( ":checked" ) );
				self._updateAll();
				event.preventDefault();
			},

			click: false

		});

		input
			.bind({
				mousedown: function(){
					this._cacheVals();
				},

				click: function(){
					self._updateAll();
				},

				focus: function() {
					label.addClass( "ui-focus" );
				},

				blur: function() {
					label.removeClass( "ui-focus" );
				}
			});

		this.refresh();

	},

	_cacheVals: function(){
		this._getInputSet().each(function(){
			$(this).data("cacheVal", $(this).is(":checked") );
		});
	},

	//returns either a set of radios with the same name attribute, or a single checkbox
	_getInputSet: function(){
		return this.element.closest( "form,fieldset,[data-role='page']" )
				.find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.element.attr( "type" ) +"']" );
	},

	_updateAll: function(){
		this._getInputSet().each(function(){
			var dVal = $(this).data("cacheVal");
			if( dVal && dVal !== $(this).is(":checked") || $(this).is( "[type='checkbox']" ) ){
				$(this).trigger("change");
			}
		})
		.checkboxradio( "refresh" );
	},

	refresh: function( ){
		var input = this.element,
			label = input.closest("form,fieldset,[data-role='page']").find("label[for='" + input.attr( "id" ) + "']"),
			inputtype = input.attr( "type" ),
			icon = label.find( ".ui-icon" ),
			checkedicon = "ui-icon-" + inputtype + "-on",
			uncheckedicon = "ui-icon-" + inputtype + "-off";

		if ( input[0].checked ) {
			label.addClass( "ui-btn-active" );
			icon.addClass( checkedicon );
			icon.removeClass( uncheckedicon );

		} else {
			label.removeClass( "ui-btn-active" );
			icon.removeClass( checkedicon );
			icon.addClass( uncheckedicon );
		}

		if( input.is( ":disabled" ) ){
			this.disable();
		}
		else {
			this.enable();
		}
	},

	disable: function(){
		this.element.attr("disabled",true).parent().addClass("ui-disabled");
	},

	enable: function(){
		this.element.attr("disabled",false).parent().removeClass("ui-disabled");
	}
});
})( jQuery );
<|endoftext|>


<commit_before>(function() {
  var colors = {
    'ORANGE': {
      colour: 'rgb(255,144,47)',
      secondary_colour: ['LIGHT BLUE', 'DARK BLUE'],
      index: 8
    },
    'LIGHT BLUE': {
      colour: 'rgb(51,151,197)',
      secondary_colour: ['YELLOW', 'RED'],
      index: 4
    },
    'DARK BLUE': {
      colour: 'rgb(59,54,182)',
      secondary_colour: ['ORANGE', 'YELLOW'],
      index: 3
    },
    'GREEN': {
      colour: 'rgb(83,119,48)',
      secondary_colour: ['PINK', 'PURPLE'],
      index: 5
    },
    'YELLOW': {
      colour: 'rgb(219,217,37)',
      secondary_colour: ['LIGHT BLUE', 'PURPLE'],
      index: 6
    },
    'BLACK': {
      colour: 'rgb(25,25,25)',
      secondary_colour: ['ORANGE', 'PINK', 'LIGHT BLUE', 'GREEN', 'RED'],
      index: 10
    },
    'PINK': {
      colour: 'rgb(206,51,122)',
      secondary_colour: ['LIGHT BLUE', 'ORANGE'],
      index: 1
    },
    'WHITE': {
      colour: 'rgb(200,200,200)',
      secondary_colour: ['PINK', 'LIGHT BLUE', 'ORANGE', 'RED', 'GREEN'],
      index: 9
    },
    'BROWN': {
      colour: 'rgb(142,107,68)',
      secondary_colour: ['DARK BLUE', 'PINK'],
      index: 7
    },
    'PURPLE': {
      colour: 'rgb(113,52,165)',
      secondary_colour: ['YELLOW', 'GREEN'],
      index: 2
    },
    'RED': {
      colour: 'rgb(210,50,44)',
      secondary_colour: ['GREEN', 'LIGHT BLUE'],
      index: 0
    }
  };
  var colorNames = Object.keys(colors)

  var parseRgb = function(string) {
    return string.replace('rgb(', '').replace(')', '').split(',').map(function(s) {return parseInt(s, 10)})
  }

  var componentFromHue = function(m1, m2, h) {
    h = ((h % 1) + 1) % 1;
    if (h*6 < 1) {
      return m1 + (m2-m1) * h*6;
    }
    if (h*2 < 1) {
      return m2;
    }
    if (h*3 < 2) {
      return m1 + (m2-m1) * (2/3 - h) * 6;
    }
    return m1;
  }

  var rgbFromHsl = function(h, s, l) {
    var m2;
    if (l < 0.5) {
      m2 = l * (s+1);
    } else {
      m2 = l + s - l*s;
    }
    var m1 = l*2 - m2;
    return {
      r: componentFromHue(m1, m2, h + 1/3),
      g: componentFromHue(m1, m2, h),
      b: componentFromHue(m1, m2, h - 1/3)
    };
  }

  var hslFromRgb = function(r, g, b) {
    var m = Math.min(r, g, b)
    var M = Math.max(r, g, b)
    var l = (M+m)/2
    var c = M - m
    var s
    if (l <= 0.0) {
      s = 0
    } else if (l <= 0.5) {
      s = c/(2*l)
    } else {
      s = c/(2 - 2*l)
    }
    var h = 0
    if (c == 0) {
      h = 0
    } else if (M == r) {
      h = ((g - b) / c)
    } else if (M == g) {
      h = ((b - r) / c) + 2
    } else if (M == b) {
      h = ((r - g) / c) + 4
    }
    h = ((h/6) + 1) % 1;

    return {
      h: h,
      s: s,
      l: l
    }
  }

  function hueReplace(from, to, primary, secondary) {
    primary = hslFromRgb(primary[0]/255, primary[1]/255, primary[2]/255)
    secondary = hslFromRgb(secondary[0]/255, secondary[1]/255, secondary[2]/255)

    var canvas = document.createElement("canvas");
    canvas.width = from.offsetWidth
    canvas.height = from.offsetHeight

    var ctx = canvas.getContext("2d");
    ctx.drawImage(from, 0, 0, canvas.width, canvas.height);

    var map = ctx.getImageData(0, 0, canvas.width, canvas.height)
    var data = map.data;

    var r, g, b
    var hsl, rgb
    for(var i = 0, len = data.length;i < len;i += 4) {
      r = data[i]/255
      g = data[i+1]/255
      b = data[i+2]/255
      // alpha channel (p+3) is ignored

      hsl = hslFromRgb(r, g, b)
      if (hsl.h > 0.40 && hsl.h < 0.70) {
        hsl.h = primary.h
        if (hsl.s > 0.1) {
          hsl.s = primary.s
          hsl.l = primary.l*Math.sqrt(hsl.l) + (1-primary.l)*Math.pow(hsl.l, 2)
        }
      } else if (hsl.h > 0.05 && hsl.h < 0.18) {
        hsl.h = secondary.h
        if (hsl.s > 0.2) {
          hsl.s = secondary.s
          hsl.l = primary.l*Math.sqrt(hsl.l) + (1-primary.l)*Math.pow(hsl.l, 2)
        }
      }
      rgb = rgbFromHsl(hsl.h, hsl.s, hsl.l)

      data[i] = rgb.r*255
      data[i+1] = rgb.g*255
      data[i+2] = rgb.b*255
      //data[i] = hsl.l*255
      //data[i+1] = hsl.l*255
      //data[i+2] = hsl.l*255
    }

    ctx.putImageData(map,0,0);

    to.src = canvas.toDataURL();
  }

  var baseBlue = [58, 119, 174]
  var baseYellow = [255, 200, 2]

  var $commander = $('[data-bind="visible: true, attr: {src: commanderImg}"]')
  var $clone = $commander.clone()
  $commander.hide()
  $commander.after($clone)
  var colorize = function() {
    var main = colors[colorNames[Math.floor(Math.random() * 11)]]
    //var main = colors['BLACK']
    var primary = parseRgb(main.colour)
    var choices = main.secondary_colour
    var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

    $commander.off('load', colorize)
    hueReplace(
      $commander[0],
      $clone[0],
      primary
      ,
      secondary
    );
    //setTimeout(colorize, 1000)
  }
  $commander.on('load', colorize)

  setTimeout(function() {
    $('.commander img').each(function() {
      console.log(this, arguments)
      var $com = $(this)
      //var $clone = $com.clone()
      //$com.hide()
      //$com.after($clone)
      var colorize = function() {
        var main = colors[colorNames[Math.floor(Math.random() * 11)]]
        //var main = colors['BLACK']
        var primary = parseRgb(main.colour)
        var choices = main.secondary_colour
        var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

        console.log($com, main, primary, choices, secondary)
        hueReplace(
          $com[0],
          $com[0],
          primary
          ,
          secondary
        );
        //setTimeout(colorize, 1000)
      }
      //$com.on('load', colorize)
      colorize()
    })
  }, 1000)
})()
<commit_msg>get primary colors<commit_after>(function() {
  var colors = {
    'ORANGE': {
      colour: 'rgb(255,144,47)',
      secondary_colour: ['LIGHT BLUE', 'DARK BLUE'],
      index: 8
    },
    'LIGHT BLUE': {
      colour: 'rgb(51,151,197)',
      secondary_colour: ['YELLOW', 'RED'],
      index: 4
    },
    'DARK BLUE': {
      colour: 'rgb(59,54,182)',
      secondary_colour: ['ORANGE', 'YELLOW'],
      index: 3
    },
    'GREEN': {
      colour: 'rgb(83,119,48)',
      secondary_colour: ['PINK', 'PURPLE'],
      index: 5
    },
    'YELLOW': {
      colour: 'rgb(219,217,37)',
      secondary_colour: ['LIGHT BLUE', 'PURPLE'],
      index: 6
    },
    'BLACK': {
      colour: 'rgb(25,25,25)',
      secondary_colour: ['ORANGE', 'PINK', 'LIGHT BLUE', 'GREEN', 'RED'],
      index: 10
    },
    'PINK': {
      colour: 'rgb(206,51,122)',
      secondary_colour: ['LIGHT BLUE', 'ORANGE'],
      index: 1
    },
    'WHITE': {
      colour: 'rgb(200,200,200)',
      secondary_colour: ['PINK', 'LIGHT BLUE', 'ORANGE', 'RED', 'GREEN'],
      index: 9
    },
    'BROWN': {
      colour: 'rgb(142,107,68)',
      secondary_colour: ['DARK BLUE', 'PINK'],
      index: 7
    },
    'PURPLE': {
      colour: 'rgb(113,52,165)',
      secondary_colour: ['YELLOW', 'GREEN'],
      index: 2
    },
    'RED': {
      colour: 'rgb(210,50,44)',
      secondary_colour: ['GREEN', 'LIGHT BLUE'],
      index: 0
    }
  };
  var colorNames = Object.keys(colors)

  var parseRgb = function(string) {
    return string.replace('rgb(', '').replace(')', '').split(',').map(function(s) {return parseInt(s, 10)})
  }

  var componentFromHue = function(m1, m2, h) {
    h = ((h % 1) + 1) % 1;
    if (h*6 < 1) {
      return m1 + (m2-m1) * h*6;
    }
    if (h*2 < 1) {
      return m2;
    }
    if (h*3 < 2) {
      return m1 + (m2-m1) * (2/3 - h) * 6;
    }
    return m1;
  }

  var rgbFromHsl = function(h, s, l) {
    var m2;
    if (l < 0.5) {
      m2 = l * (s+1);
    } else {
      m2 = l + s - l*s;
    }
    var m1 = l*2 - m2;
    return {
      r: componentFromHue(m1, m2, h + 1/3),
      g: componentFromHue(m1, m2, h),
      b: componentFromHue(m1, m2, h - 1/3)
    };
  }

  var hslFromRgb = function(r, g, b) {
    var m = Math.min(r, g, b)
    var M = Math.max(r, g, b)
    var l = (M+m)/2
    var c = M - m
    var s
    if (l <= 0.0) {
      s = 0
    } else if (l <= 0.5) {
      s = c/(2*l)
    } else {
      s = c/(2 - 2*l)
    }
    var h = 0
    if (c == 0) {
      h = 0
    } else if (M == r) {
      h = ((g - b) / c)
    } else if (M == g) {
      h = ((b - r) / c) + 2
    } else if (M == b) {
      h = ((r - g) / c) + 4
    }
    h = ((h/6) + 1) % 1;

    return {
      h: h,
      s: s,
      l: l
    }
  }

  function hueReplace(from, to, primary, secondary) {
    primary = hslFromRgb(primary[0]/255, primary[1]/255, primary[2]/255)
    secondary = hslFromRgb(secondary[0]/255, secondary[1]/255, secondary[2]/255)

    var canvas = document.createElement("canvas");
    canvas.width = from.offsetWidth
    canvas.height = from.offsetHeight

    var ctx = canvas.getContext("2d");
    ctx.drawImage(from, 0, 0, canvas.width, canvas.height);

    var map = ctx.getImageData(0, 0, canvas.width, canvas.height)
    var data = map.data;

    var r, g, b
    var hsl, rgb
    for(var i = 0, len = data.length;i < len;i += 4) {
      r = data[i]/255
      g = data[i+1]/255
      b = data[i+2]/255
      // alpha channel (p+3) is ignored

      hsl = hslFromRgb(r, g, b)
      if (hsl.h > 0.40 && hsl.h < 0.70) {
        hsl.h = primary.h
        if (hsl.s > 0.1) {
          hsl.s = primary.s
          hsl.l = primary.l*Math.sqrt(hsl.l) + (1-primary.l)*Math.pow(hsl.l, 2)
        }
      } else if (hsl.h > 0.05 && hsl.h < 0.18) {
        hsl.h = secondary.h
        if (hsl.s > 0.2) {
          hsl.s = secondary.s
          hsl.l = primary.l*Math.sqrt(hsl.l) + (1-primary.l)*Math.pow(hsl.l, 2)
        }
      }
      rgb = rgbFromHsl(hsl.h, hsl.s, hsl.l)

      data[i] = rgb.r*255
      data[i+1] = rgb.g*255
      data[i+2] = rgb.b*255
      //data[i] = hsl.l*255
      //data[i+1] = hsl.l*255
      //data[i+2] = hsl.l*255
    }

    ctx.putImageData(map,0,0);

    to.src = canvas.toDataURL();
  }

  var baseBlue = [58, 119, 174]
  var baseYellow = [255, 200, 2]

  var $commander = $('[data-bind="visible: true, attr: {src: commanderImg}"]')
  var $clone = $commander.clone()
  $commander.hide()
  $commander.after($clone)
  var colorize = function() {
    var main = colors[colorNames[Math.floor(Math.random() * 11)]]
    //var main = colors['BLACK']
    var primary = parseRgb(main.colour)
    var choices = main.secondary_colour
    var secondary = parseRgb(colors[choices[Math.floor(Math.random() * choices.length)]].colour)

    $commander.off('load', colorize)
    hueReplace(
      $commander[0],
      $clone[0],
      primary
      ,
      secondary
    );
    //setTimeout(colorize, 1000)
  }
  $commander.on('load', colorize)

  var playerColors = ko.computed(function() {
    var nested = model.teams().map(function(team) {
      return team.players().map(function(player) {
        return parseRgb(player.color())
      })
    })
    return _.flatten(nested, true)
  })

  var colorCinematic = function() {
    $('.commander img').each(function(i) {
      var $com = $(this)
      var colorize = function() {
        hueReplace(
          $com[0],
          $com[0],
          playerColors()[i]
          ,
          [127, 127, 127]
        );
      }
      colorize()
    })
  }

  setTimeout(colorCinematic, 1000)
})()
<|endoftext|>


<commit_before>var fs = require('fs'),
  path = require('path'),
  ADODB = require('../index'),
  expect = require('expect.js');

var source = path.join(__dirname, 'node-adodb.mdb'),
  mdb = fs.readFileSync(path.join(__dirname, '../examples/node-adodb.mdb'));

fs.writeFileSync(source, mdb);

// Variable declaration
var adodb = path.join(__dirname, 'adodb.js'),
  sysroot = process.env['systemroot'] || process.env['windir'],
  x64 = fs.existsSync(path.join(sysroot, 'SysWOW64')),
  cscript = path.join(sysroot, x64 ? 'SysWOW64' : 'System32', 'cscript.exe');

console.log(cscript);
console.log(adodb);

describe('ADODB', function (){
  // Variable declaration
  var connection = ADODB.open('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + source + ';');

  it('execute', function (next){
    connection
      .execute('INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Nuintun", "Male", 25)')
      .on('done', function (data){
        expect(data).to.eql({
          valid: true,
          message: 'Execute SQL: INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Nuintun", "Male", 25) success !'
        });

        next();
      }).on('fail', function (error){
        expect(error).to.have.key('valid');

        next();
      });
  });

  it('executeScalar', function (next){
    connection
      .executeScalar('INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Alice", "Female", 25)', 'SELECT @@Identity AS id')
      .on('done', function (data){
        expect(data).to.eql({
          valid: true,
          message: 'Execute Scalar SQL: INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Alice", "Female", 25) / SELECT @@Identity AS id success !',
          records: [{ id: 5 }]
        });

        next();
      }).on('fail', function (error){
        expect(error).to.have.key('valid');

        next();
      });
  });

  it('query', function (next){
    connection
      .query('SELECT * FROM Users')
      .on('done', function (data){
        expect(data).to.eql({
          valid: true,
          message: 'Execute SQL: SELECT * FROM Users success !',
          records: [
            {
              UserId: 1,
              UserName: "Nuintun",
              UserSex: "Male",
              UserAge: 25
            },
            {
              UserId: 2,
              UserName: "Angela",
              UserSex: "Female",
              UserAge: 23
            },
            {
              UserId: 3,
              UserName: "Newton",
              UserSex: "Male",
              UserAge: 25
            },
            {
              UserId: 4,
              UserName: "Nuintun",
              UserSex: "Male",
              UserAge: 25
            },
            {
              UserId: 5,
              UserName: "Alice",
              UserSex: "Female",
              UserAge: 25
            }
          ]
        });

        next();
      }).on('fail', function (error){
        expect(error).to.have.key('valid');

        next();
      });
  });
});
<commit_msg>add test case<commit_after>var fs = require('fs'),
  path = require('path'),
  ADODB = require('../index'),
  expect = require('expect.js');

var source = path.join(__dirname, 'node-adodb.mdb'),
  mdb = fs.readFileSync(path.join(__dirname, '../examples/node-adodb.mdb'));

fs.writeFileSync(source, mdb);

// Variable declaration
var adodb = path.join(__dirname, 'adodb.js'),
  sysroot = process.env['systemroot'] || process.env['windir'],
  x64 = fs.existsSync(path.join(sysroot, 'SysWOW64')),
  cscript = path.join(sysroot, x64 ? 'SysWOW64' : 'System32', 'cscript.exe');

console.log(cscript);
console.log(adodb);
console.log(fs.existsSync(cscript));

describe('ADODB', function (){
  // Variable declaration
  var connection = ADODB.open('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + source + ';');

  it('execute', function (next){
    connection
      .execute('INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Nuintun", "Male", 25)')
      .on('done', function (data){
        expect(data).to.eql({
          valid: true,
          message: 'Execute SQL: INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Nuintun", "Male", 25) success !'
        });

        next();
      }).on('fail', function (error){
        expect(error).to.have.key('valid');

        next();
      });
  });

  it('executeScalar', function (next){
    connection
      .executeScalar('INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Alice", "Female", 25)', 'SELECT @@Identity AS id')
      .on('done', function (data){
        expect(data).to.eql({
          valid: true,
          message: 'Execute Scalar SQL: INSERT INTO Users(UserName, UserSex, UserAge) VALUES ("Alice", "Female", 25) / SELECT @@Identity AS id success !',
          records: [{ id: 5 }]
        });

        next();
      }).on('fail', function (error){
        expect(error).to.have.key('valid');

        next();
      });
  });

  it('query', function (next){
    connection
      .query('SELECT * FROM Users')
      .on('done', function (data){
        expect(data).to.eql({
          valid: true,
          message: 'Execute SQL: SELECT * FROM Users success !',
          records: [
            {
              UserId: 1,
              UserName: "Nuintun",
              UserSex: "Male",
              UserAge: 25
            },
            {
              UserId: 2,
              UserName: "Angela",
              UserSex: "Female",
              UserAge: 23
            },
            {
              UserId: 3,
              UserName: "Newton",
              UserSex: "Male",
              UserAge: 25
            },
            {
              UserId: 4,
              UserName: "Nuintun",
              UserSex: "Male",
              UserAge: 25
            },
            {
              UserId: 5,
              UserName: "Alice",
              UserSex: "Female",
              UserAge: 25
            }
          ]
        });

        next();
      }).on('fail', function (error){
        expect(error).to.have.key('valid');

        next();
      });
  });
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name        SO Time Lines
// @namespace   Kyll-things
// @description Random chat improvements
// @include     *://chat.stackoverflow.com/rooms/*
// @version     1
// @run-at      document-idle
// @eat         waffle
// ==/UserScript==

// Add some Plop
window.Plop = window.Plop || {}
Plopify = (...args) => Object.assign(window.Plop, ...args)

// Add some magic
HTMLCollection.prototype[Symbol.iterator] =
  HTMLCollection.prototype[Symbol.iterator] || Array.prototype[Symbol.iterator]

// Add some style
const headNode = document.getElementsByTagName('head')[0]
    , styleNode = document.createElement('style')

headNode.appendChild(styleNode)
//TODO: Do this programmatically, kind of ugly atm
styleNode.innerHTML = '.message.two-minutes {  border-bottom-style: solid!important;  border-bottom-color: red!important;  border-bottom-width: thin!important;}.message.five-minutes {  border-bottom-style: solid!important;  border-bottom-color: green!important;  border-bottom-width: thin!important;}.message.ten-minutes {  border-bottom-style: solid!important;  border-bottom-color: blue!important;  border-bottom-width: thin!important;}'

// Add timestamps on all existing messages
// This requires the DOM to be loaded.
// Try until it worked
// If anyone has some kind of cleaner way to do this (event?), I'm taker
const allTimestampsInterval = setInterval(function tryAddAllTimestamps() {
  const allMessages = document.querySelectorAll('*[id^="message-"]')

  for(let message of allMessages) {
    message.setAttribute('timestamp', $.data(message, 'info').time)
  }

  if(allMessages.length > 0) {
    clearInterval(allTimestampsInterval)
  }
}, 2000)

window.CHAT.addEventHandlerHook(({event_type, time_stamp, message_id}) => {
  // New message
  if(event_type === 1) {
    // We need the HTML element to exist, it's set synchronously
    // Thus, queue the query
    setTimeout(() => {
      const element = document.getElementById(`message-${message_id}`)
      if (element) {
        element.setAttribute('timestamp', time_stamp)
      }
    }, 0);
  }
})

const twoMinutesClass = 'two-minutes'
    , fiveMinutesClass = 'five-minutes'
    , tenMinutesClass = 'ten-minutes'

    , testFiveSecondsClass = 'five-seconds'

Plopify({twoMinutesClass, fiveMinutesClass, tenMinutesClass, testFiveSecondsClass})

setInterval(function manageTimeLines() {
  const removeTimeLines = () => {
    [
      ...document.getElementsByClassName(twoMinutesClass)
      ,  ...document.getElementsByClassName(fiveMinutesClass)
      ,  ...document.getElementsByClassName(tenMinutesClass)

      ,  ...document.getElementsByClassName(testFiveSecondsClass)
    ].forEach(e => {
      e.classList.remove(twoMinutesClass)
      e.classList.remove(fiveMinutesClass)
      e.classList.remove(tenMinutesClass)

      e.classList.remove(testFiveSecondsClass)
    })
  }

  const addTimeLines = () => {
    const twoMinutesToMs = 1000 * 60 * 2
        , fiveMinutesToMs = 1000 * 60 * 5
        , tenMinutesToMs = 1000 * 60 * 10

        , testFiveSecondsToMs = 1000 * 5

    Plopify({twoMinutesToMs, fiveMinutesToMs, tenMinutesToMs, testFiveSecondsToMs})

    const allMessages = document.querySelectorAll('.message')
        , maxLookupAmount = Math.min(42, allMessages.length)
        , now = Date.now()

    Plopify({maxLookupAmount})

    let markedTwoMinutes = false
      , markedFiveMinutes = false
      , markedTenMinutes = false

      , testMarkedFiveSeconds = false

    for(i = allMessages.length - 1; i > allMessages.length - maxLookupAmount; i--) {
      let currentMessage = allMessages[i]
        // Fetch the timestamp on the HTML element, multiply by 1000 to get
        // millisecond precision
        , messageTimestamp = Number.parseInt(
          currentMessage.getAttribute('timestamp')
        ) * 1000

      if (
        messageTimestamp < (now - testFiveSecondsToMs)
        && !testMarkedFiveSeconds
      ) {
        currentMessage.classList.add(testFiveSecondsClass)
        testMarkedFiveSeconds = true
      }
      if (
        messageTimestamp < (now - twoMinutesToMs)
        && !markedTwoMinutes
      ) {
        currentMessage.classList.add(twoMinutesClass)
        markedTwoMinutes = true
      }
      if (
        messageTimestamp < (now - fiveMinutesToMs)
        && !markedFiveMinutes
      ) {
        currentMessage.classList.add(fiveMinutesClass)
        markedFiveMinutes = true
      }
      if (
        messageTimestamp < (now - tenMinutesToMs)
        && !markedTenMinutes
      ) {
        currentMessage.classList.add(tenMinutesClass)
        markedTenMinutes = true
      }
    }
  }

  removeTimeLines()

  addTimeLines()
}, 4200)
<commit_msg>Fixed crash occuring with old messages<commit_after>// ==UserScript==
// @name        SO Time Lines
// @namespace   Kyll-things
// @description Random chat improvements
// @include     *://chat.stackoverflow.com/rooms/*
// @version     1
// @run-at      document-idle
// @eat         waffle
// ==/UserScript==

// Add some Plop
window.Plop = window.Plop || {}
Plopify = (...args) => Object.assign(window.Plop, ...args)

// Add some magic
HTMLCollection.prototype[Symbol.iterator] =
  HTMLCollection.prototype[Symbol.iterator] || Array.prototype[Symbol.iterator]

// Add some style
const headNode = document.getElementsByTagName('head')[0]
    , styleNode = document.createElement('style')

headNode.appendChild(styleNode)
//TODO: Do this programmatically, kind of ugly atm
styleNode.innerHTML = '.message.two-minutes {  border-bottom-style: solid!important;  border-bottom-color: red!important;  border-bottom-width: thin!important;}.message.five-minutes {  border-bottom-style: solid!important;  border-bottom-color: green!important;  border-bottom-width: thin!important;}.message.ten-minutes {  border-bottom-style: solid!important;  border-bottom-color: blue!important;  border-bottom-width: thin!important;}'

// Add timestamps on all existing messages
// This requires the DOM to be loaded.
// Try until it worked
// If anyone has some kind of cleaner way to do this (event?), I'm taker
const allTimestampsInterval = setInterval(function tryAddAllTimestamps() {
  const allMessages = document.querySelectorAll('*[id^="message-"]')

  for(let message of allMessages) {
    let timestamp = $.data(message, 'info') && $.data(message, 'info').time
    message.setAttribute('timestamp', timestamp)
  }

  if(allMessages.length > 0) {
    clearInterval(allTimestampsInterval)
  }
}, 2000)

window.CHAT.addEventHandlerHook(({event_type, time_stamp, message_id}) => {
  // New message
  if(event_type === 1) {
    // We need the HTML element to exist, it's set synchronously
    // Thus, queue the query
    setTimeout(() => {
      const element = document.getElementById(`message-${message_id}`)
      if (element) {
        element.setAttribute('timestamp', time_stamp)
      }
    }, 0);
  }
})

const twoMinutesClass = 'two-minutes'
    , fiveMinutesClass = 'five-minutes'
    , tenMinutesClass = 'ten-minutes'

    , testFiveSecondsClass = 'five-seconds'

Plopify({twoMinutesClass, fiveMinutesClass, tenMinutesClass, testFiveSecondsClass})

setInterval(function manageTimeLines() {
  const removeTimeLines = () => {
    [
      ...document.getElementsByClassName(twoMinutesClass)
      ,  ...document.getElementsByClassName(fiveMinutesClass)
      ,  ...document.getElementsByClassName(tenMinutesClass)

      ,  ...document.getElementsByClassName(testFiveSecondsClass)
    ].forEach(e => {
      e.classList.remove(twoMinutesClass)
      e.classList.remove(fiveMinutesClass)
      e.classList.remove(tenMinutesClass)

      e.classList.remove(testFiveSecondsClass)
    })
  }

  const addTimeLines = () => {
    const twoMinutesToMs = 1000 * 60 * 2
        , fiveMinutesToMs = 1000 * 60 * 5
        , tenMinutesToMs = 1000 * 60 * 10

        , testFiveSecondsToMs = 1000 * 5

    Plopify({twoMinutesToMs, fiveMinutesToMs, tenMinutesToMs, testFiveSecondsToMs})

    const allMessages = document.querySelectorAll('.message')
        , maxLookupAmount = Math.min(42, allMessages.length)
        , now = Date.now()

    Plopify({maxLookupAmount})

    let markedTwoMinutes = false
      , markedFiveMinutes = false
      , markedTenMinutes = false

      , testMarkedFiveSeconds = false

    for(i = allMessages.length - 1; i > allMessages.length - maxLookupAmount; i--) {
      let currentMessage = allMessages[i]
        // Fetch the timestamp on the HTML element, multiply by 1000 to get
        // millisecond precision
        , messageTimestamp = Number.parseInt(
          currentMessage.getAttribute('timestamp')
        ) * 1000

      if (
        messageTimestamp < (now - testFiveSecondsToMs)
        && !testMarkedFiveSeconds
      ) {
        currentMessage.classList.add(testFiveSecondsClass)
        testMarkedFiveSeconds = true
      }
      if (
        messageTimestamp < (now - twoMinutesToMs)
        && !markedTwoMinutes
      ) {
        currentMessage.classList.add(twoMinutesClass)
        markedTwoMinutes = true
      }
      if (
        messageTimestamp < (now - fiveMinutesToMs)
        && !markedFiveMinutes
      ) {
        currentMessage.classList.add(fiveMinutesClass)
        markedFiveMinutes = true
      }
      if (
        messageTimestamp < (now - tenMinutesToMs)
        && !markedTenMinutes
      ) {
        currentMessage.classList.add(tenMinutesClass)
        markedTenMinutes = true
      }
    }
  }

  removeTimeLines()

  addTimeLines()
}, 4200)
<|endoftext|>


<commit_before>/*
* "checkboxradio" plugin
*/

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Consistent styling for checkboxes/radio buttons.
//>>label: Checkboxes/Radio Buttons
//>>group: forms

define( [ "jquery", "./jquery.mobile.core", "./jquery.mobile.widget", "./jquery.mobile.buttonMarkup" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.checkboxradio", $.mobile.widget, {
	options: {
		theme: null,
		initSelector: "input[type='checkbox'],input[type='radio']"
	},
	_create: function() {
		var self = this,
			input = this.element,
			// NOTE: Windows Phone could not find the label through a selector
			// filter works though.
			label = input.closest( "form,fieldset,:jqmData(role='page')" ).find( "label" ).filter( "[for='" + input[ 0 ].id + "']" ),
			inputtype = input.attr( "type" ),
			mini = input.closest( "form,fieldset" ).jqmData('mini'),
			checkedState = inputtype + "-on",
			uncheckedState = inputtype + "-off",
			icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
			activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
			checkedClass = "ui-" + checkedState + activeBtn,
			uncheckedClass = "ui-" + uncheckedState,
			checkedicon = "ui-icon-" + checkedState,
			uncheckedicon = "ui-icon-" + uncheckedState;

		if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
			return;
		}

		// Expose for other methods
		$.extend( this, {
			label: label,
			inputtype: inputtype,
			checkedClass: checkedClass,
			uncheckedClass: uncheckedClass,
			checkedicon: checkedicon,
			uncheckedicon: uncheckedicon
		});

		// If there's no selected theme...
		if( !this.options.theme ) {
			this.options.theme = this.element.jqmData( "theme" );
		}

		label.buttonMarkup({
			theme: this.options.theme,
			icon: icon,
			shadow: false,
			mini: mini
		});

		// Wrap the input + label in a div
		var wrapper = document.createElement('div');
		wrapper.className = 'ui-' + inputtype;
		input[0].parentNode.insertBefore(wrapper,input[0]);
		wrapper.appendChild(input[0]);
		wrapper.appendChild(label[0]);

		label.bind({
			vmouseover: function( event ) {
				if ( $( this ).parent().is( ".ui-disabled" ) ) {
					event.stopPropagation();
				}
			},

			vclick: function( event ) {
				if ( input.is( ":disabled" ) ) {
					event.preventDefault();
					return;
				}

				self._cacheVals();
				input.attr( "checked", inputtype === "radio" && true || !input.attr( "checked" ) );
				//input.prop( "checked", inputtype === "radio" && true || !input.attr( "checked" ) );

				// trigger click handler's bound directly to the input as a substitute for
				// how label clicks behave normally in the browsers
				// TODO: it would be nice to let the browser's handle the clicks and pass them
				//       through to the associate input. we can swallow that click at the parent
				//       wrapper element level
				input.triggerHandler( 'click' );

				// Input set for common radio buttons will contain all the radio
				// buttons, but will not for checkboxes. clearing the checked status
				// of other radios ensures the active button state is applied properly
				self._getInputSet().not( input ).removeAttr( "checked" );

				self._updateAll();
				return false;
			}

		});

		input
			.bind({
				vmousedown: function() {
					self._cacheVals();
				},

				vclick: function() {
					var $this = $(this);

					// Adds checked attribute to checked input when keyboard is used
					if ( $this.is( ":checked" ) ) {

						$this.attr( "checked", "checked" );
						self._getInputSet().not($this).removeAttr( "checked" );
					} else {

						$this.removeAttr( "checked" );
					}

					self._updateAll();
				},

				focus: function() {
					label.addClass( $.mobile.focusClass );
				},

				blur: function() {
					label.removeClass( $.mobile.focusClass );
				}
			});

		this.refresh();
	},

	_cacheVals: function() {
		this._getInputSet().each(function() {
			var $this = $(this);

			$this.jqmData( "cacheVal", $this.is( ":checked" ) );
		});
	},

	//returns either a set of radios with the same name attribute, or a single checkbox
	_getInputSet: function(){
		if(this.inputtype == "checkbox") {
			return this.element;
		}

		return this.element.closest( "form,fieldset,:jqmData(role='page')" )
			.find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
	},

	_updateAll: function() {
		var self = this;

		this._getInputSet().each(function() {
			var $this = $(this);

			if ( $this.is( ":checked" ) || self.inputtype === "checkbox" ) {
				$this.trigger( "change" );
			}
		})
		.checkboxradio( "refresh" );
	},

	refresh: function() {
		var input = this.element,
			label = this.label,
			icon = label.find( ".ui-icon" );

		// input[0].checked expando doesn't always report the proper value
		// for checked='checked'

		if ( input[ 0 ].getAttribute( "checked" ) ) {
			label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
			icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
		} else {
			label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
			icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
		}

		if ( input.is( ":disabled" ) ) {
			this.disable();
		} else {
			this.enable();
		}
	},

	disable: function() {
		this.element.attr( "disabled", true ).parent().addClass( "ui-disabled" );
	},

	enable: function() {
		this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ){
	$.mobile.checkboxradio.prototype.enhanceWithin( e.target, true );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Fixes #3580 — Fixes radio/checkbox rendering inside dialogs when not wrapped in fieldcontain. Also addresses some general brokenness for radio/checkboxes in dialogs.<commit_after>/*
* "checkboxradio" plugin
*/

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Consistent styling for checkboxes/radio buttons.
//>>label: Checkboxes/Radio Buttons
//>>group: forms

define( [ "jquery", "./jquery.mobile.core", "./jquery.mobile.widget", "./jquery.mobile.buttonMarkup" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.checkboxradio", $.mobile.widget, {
	options: {
		theme: null,
		initSelector: "input[type='checkbox'],input[type='radio']"
	},
	_create: function() {
		var self = this,
			input = this.element,
			// NOTE: Windows Phone could not find the label through a selector
			// filter works though.
			label = $( input ).closest( "form,fieldset,:jqmData(role='page'),:jqmData(role='dialog')" ).find( "label" ).filter( "[for='" + input[ 0 ].id + "']" ),
			inputtype = input.attr( "type" ),
			mini = input.closest( "form,fieldset" ).jqmData('mini'),
			checkedState = inputtype + "-on",
			uncheckedState = inputtype + "-off",
			icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
			activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
			checkedClass = "ui-" + checkedState + activeBtn,
			uncheckedClass = "ui-" + uncheckedState,
			checkedicon = "ui-icon-" + checkedState,
			uncheckedicon = "ui-icon-" + uncheckedState;

		if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
			return;
		}

		// Expose for other methods
		$.extend( this, {
			label: label,
			inputtype: inputtype,
			checkedClass: checkedClass,
			uncheckedClass: uncheckedClass,
			checkedicon: checkedicon,
			uncheckedicon: uncheckedicon
		});

		// If there's no selected theme...
		if( !this.options.theme ) {
			this.options.theme = this.element.jqmData( "theme" );
		}

		label.buttonMarkup({
			theme: this.options.theme,
			icon: icon,
			shadow: false,
			mini: mini
		});

		// Wrap the input + label in a div
		var wrapper = document.createElement('div');
		wrapper.className = 'ui-' + inputtype;
		input[0].parentNode.insertBefore(wrapper,input[0]);
		wrapper.appendChild(input[0]);
		wrapper.appendChild(label[0]);

		label.bind({
			vmouseover: function( event ) {
				if ( $( this ).parent().is( ".ui-disabled" ) ) {
					event.stopPropagation();
				}
			},

			vclick: function( event ) {
				if ( input.is( ":disabled" ) ) {
					event.preventDefault();
					return;
				}

				self._cacheVals();
				input.attr( "checked", inputtype === "radio" && true || !input.attr( "checked" ) );
				//input.prop( "checked", inputtype === "radio" && true || !input.attr( "checked" ) );

				// trigger click handler's bound directly to the input as a substitute for
				// how label clicks behave normally in the browsers
				// TODO: it would be nice to let the browser's handle the clicks and pass them
				//       through to the associate input. we can swallow that click at the parent
				//       wrapper element level
				input.triggerHandler( 'click' );

				// Input set for common radio buttons will contain all the radio
				// buttons, but will not for checkboxes. clearing the checked status
				// of other radios ensures the active button state is applied properly
				self._getInputSet().not( input ).removeAttr( "checked" );

				self._updateAll();
				return false;
			}

		});

		input
			.bind({
				vmousedown: function() {
					self._cacheVals();
				},

				vclick: function() {
					var $this = $(this);

					// Adds checked attribute to checked input when keyboard is used
					if ( $this.is( ":checked" ) ) {

						$this.attr( "checked", "checked" );
						self._getInputSet().not($this).removeAttr( "checked" );
					} else {

						$this.removeAttr( "checked" );
					}

					self._updateAll();
				},

				focus: function() {
					label.addClass( $.mobile.focusClass );
				},

				blur: function() {
					label.removeClass( $.mobile.focusClass );
				}
			});

		this.refresh();
	},

	_cacheVals: function() {
		this._getInputSet().each(function() {
			var $this = $(this);

			$this.jqmData( "cacheVal", $this.is( ":checked" ) );
		});
	},

	//returns either a set of radios with the same name attribute, or a single checkbox
	_getInputSet: function(){
		if(this.inputtype == "checkbox") {
			return this.element;
		}

		return this.element.closest( "form,fieldset,:jqmData(role='page')" )
			.find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
	},

	_updateAll: function() {
		var self = this;

		this._getInputSet().each(function() {
			var $this = $(this);

			if ( $this.is( ":checked" ) || self.inputtype === "checkbox" ) {
				$this.trigger( "change" );
			}
		})
		.checkboxradio( "refresh" );
	},

	refresh: function() {
		var input = this.element,
			label = this.label,
			icon = label.find( ".ui-icon" );

		// input[0].checked expando doesn't always report the proper value
		// for checked='checked'

		if ( input[ 0 ].getAttribute( "checked" ) ) {
			label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
			icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
		} else {
			label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
			icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
		}

		if ( input.is( ":disabled" ) ) {
			this.disable();
		} else {
			this.enable();
		}
	},

	disable: function() {
		this.element.attr( "disabled", true ).parent().addClass( "ui-disabled" );
	},

	enable: function() {
		this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ){
	$.mobile.checkboxradio.prototype.enhanceWithin( e.target, true );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>