<commit_before>// Foggy, v1.02
//
// Description: jQuery plugin for blurring page elements
// Homepage:    http://nbartlomiej.github.com/foggy
// Author:      nbartlomiej@gmail.com

(function( $ ){

  $.fn.foggy = function( options ) {

    var settings = $.extend( {
      opacity:      0.8,
      blurRadius:   2,
      quality:      16,
      cssFilterSupport: true
    }, options);

    var BlurPass = function(content, position, offset, opacity){
      this.content = content;
      this.position = position;
      this.offset = offset;
      this.opacity = opacity;
    };

    BlurPass.prototype.render = function(target){
      $('<div/>', { html: this.content }).css({
        position: this.position,
        opacity: this.opacity,
        top: this.offset[0],
        left: this.offset[1]
      }).appendTo(target);
    };

    var Circle = function(radius){
      this.radius = radius;
    };

    Circle.prototype.includes = function(x,y){
      if (Math.pow(x,2) + Math.pow(y,2) <= Math.pow(this.radius, 2)){
        return true;
      } else {
        return false;
      }
    };

    Circle.prototype.points = function(){
      var results = [];
      for (var x = -this.radius; x<=this.radius; x++){
        for (var y = -this.radius; y<=this.radius; y++){
          if (this.includes(x,y)){
            results.push([x,y]);
          }
        }
      }
      return results;
    };

    var ManualFog = function(element, settings){
      this.element = element;
      this.settings = settings;
    };

    ManualFog.prototype.calculateOffsets = function(radius, quality){
      var all_offsets = $.grep(
        new Circle(radius+1).points(),
        function(element){ return (element[0] != 0) || (element[1] != 0) }
      );
      var offsets;
      if (all_offsets.length <= quality){
        offsets = all_offsets;
      } else {
        var overhead = all_offsets.length - quality;
        var targets = [];
        for (var i = 0; i < overhead; i++){
          targets.push(Math.round(i * (all_offsets.length / overhead)));
        }
        offsets = $.grep( all_offsets, function(element, index){
          if ($.inArray(index, targets) >= 0){
            return false;
          } else {
            return true;
          }
        });
      }
      return offsets;
    };

    ManualFog.prototype.render = function(){
      var content = $(this.element).html();
      $(this.element).empty();
      var wrapper = $('<div/>').css({ position: 'relative' });
      var offsets = this.calculateOffsets(
        this.settings.blurRadius, this.settings.quality
      );
      var opacity = (this.settings.opacity * 1.2) / (offsets.length + 1);
      new BlurPass(content, 'relative', [0,0], opacity).render(wrapper);
      $(offsets).each(function(index, offset){
        new BlurPass(content, 'absolute', offset, opacity).render(wrapper);
      });
      wrapper.appendTo(this.element);
    };

    var FilterFog = function(element, settings){
      this.element = element;
      this.settings = settings;
    }

    FilterFog.prototype.render = function(){
      var opacityPercent = (''+settings.opacity).slice(2,4);
      $(this.element).css({
        '-webkit-filter': 'blur('+this.settings.blurRadius+'px)',
        opacity: settings.opacity
      });
    }

    return this.each(function(index, element) {
      if (settings.cssFilterSupport && '-webkit-filter' in document.body.style){
        new FilterFog(element, settings).render();
      } else {
        new ManualFog(element, settings).render();
      }
    });
  };

})( jQuery );
<commit_msg>Allowing multiple calls for foggy method<commit_after>// Foggy, v1.02
//
// Description: jQuery plugin for blurring page elements
// Homepage:    http://nbartlomiej.github.com/foggy
// Author:      nbartlomiej@gmail.com

(function( $ ){

  $.fn.foggy = function( options ) {

    var settings = $.extend( {
      opacity:      0.8,
      blurRadius:   2,
      quality:      16,
      cssFilterSupport: true
    }, options);

    var BlurPass = function(content, position, offset, opacity){
      this.content = content;
      this.position = position;
      this.offset = offset;
      this.opacity = opacity;
    };

    BlurPass.prototype.render = function(target){
      $('<div/>', {
        html: this.content, class: 'foggy-pass-'+this.position
      }).css({
        position: this.position,
        opacity: this.opacity,
        top: this.offset[0],
        left: this.offset[1]
      }).appendTo(target);
    };

    var Circle = function(radius){
      this.radius = radius;
    };

    Circle.prototype.includes = function(x,y){
      if (Math.pow(x,2) + Math.pow(y,2) <= Math.pow(this.radius, 2)){
        return true;
      } else {
        return false;
      }
    };

    Circle.prototype.points = function(){
      var results = [];
      for (var x = -this.radius; x<=this.radius; x++){
        for (var y = -this.radius; y<=this.radius; y++){
          if (this.includes(x,y)){
            results.push([x,y]);
          }
        }
      }
      return results;
    };

    var ManualFog = function(element, settings){
      this.element = element;
      this.settings = settings;
    };

    ManualFog.prototype.calculateOffsets = function(radius, quality){
      var all_offsets = $.grep(
        new Circle(radius+1).points(),
        function(element){ return (element[0] != 0) || (element[1] != 0) }
      );
      var offsets;
      if (all_offsets.length <= quality){
        offsets = all_offsets;
      } else {
        var overhead = all_offsets.length - quality;
        var targets = [];
        for (var i = 0; i < overhead; i++){
          targets.push(Math.round(i * (all_offsets.length / overhead)));
        }
        offsets = $.grep( all_offsets, function(element, index){
          if ($.inArray(index, targets) >= 0){
            return false;
          } else {
            return true;
          }
        });
      }
      return offsets;
    };

    ManualFog.prototype.getContent = function(){
      var candidate = $(this.element).find('.foggy-pass-relative')[0];
      if (candidate){
        return $(candidate).html();
      } else {
        return $(this.element).html();
      }
    };

    ManualFog.prototype.render = function(){
      var content = this.getContent();
      $(this.element).empty();
      var wrapper = $('<div/>').css({ position: 'relative' });
      var offsets = this.calculateOffsets(
        this.settings.blurRadius, this.settings.quality
      );
      var opacity = (this.settings.opacity * 1.2) / (offsets.length + 1);
      new BlurPass(content, 'relative', [0,0], opacity).render(wrapper);
      $(offsets).each(function(index, offset){
        new BlurPass(content, 'absolute', offset, opacity).render(wrapper);
      });
      wrapper.appendTo(this.element);
    };

    var FilterFog = function(element, settings){
      this.element = element;
      this.settings = settings;
    }

    FilterFog.prototype.render = function(){
      var opacityPercent = (''+settings.opacity).slice(2,4);
      $(this.element).css({
        '-webkit-filter': 'blur('+this.settings.blurRadius+'px)',
        opacity: settings.opacity
      });
    }

    return this.each(function(index, element) {
      if (settings.cssFilterSupport && '-webkit-filter' in document.body.style){
        new FilterFog(element, settings).render();
      } else {
        new ManualFog(element, settings).render();
      }
    });
  };

})( jQuery );
<|endoftext|>


<commit_before>// Peity jQuery plugin version 1.0.0
// (c) 2012 Ben Pickles
//
// http://benpickles.github.com/peity
//
// Released under MIT license.
(function($, document, Math, devicePixelRatio) {
  var canvasSupported = document.createElement("canvas").getContext

  var peity = $.fn.peity = function(type, options) {
    if (canvasSupported) {
      this.each(function() {
        var defaults = peity.defaults[type]
        var data = {}
        var $this = $(this)

        $.each($this.data(), function(name, value) {
          if (name in defaults) data[name] = value
        })

        var opts = $.extend({}, defaults, data, options)
        var chart = new Peity($this, type, opts)
        chart.draw()

        $this.change(function() {
          chart.draw()
        })
      });
    }

    return this;
  };

  var Peity = function($elem, type, opts) {
    this.$elem = $elem
    this.type = type
    this.opts = opts
  }

  var PeityPrototype = Peity.prototype

  PeityPrototype.colours = function() {
    var colours = this.opts.colours
    var func = colours

    if (!$.isFunction(func)) {
      func = function(_, i) {
        return colours[i % colours.length]
      }
    }

    return func
  }

  PeityPrototype.draw = function() {
    peity.graphers[this.type].call(this, this.opts)
  }

  PeityPrototype.prepareCanvas = function(width, height) {
    var canvas = this.canvas

    if (canvas) {
      this.context.clearRect(0, 0, canvas.width, canvas.height)
    } else {
      canvas = $("<canvas>").attr({
        height: height * devicePixelRatio,
        width: width * devicePixelRatio
      })

      if (devicePixelRatio != 1) {
        canvas.css({
          height: height,
          width: width
        })
      }

      this.canvas = canvas = canvas[0]
      this.context = canvas.getContext("2d")
      this.$elem.hide().before(canvas)
    }

    return canvas
  }

  PeityPrototype.values = function() {
    return $.map(this.$elem.text().split(this.opts.delimiter), function(value) {
      return parseFloat(value)
    })
  }

  peity.defaults = {}
  peity.graphers = {}

  peity.register = function(type, defaults, grapher) {
    this.defaults[type] = defaults
    this.graphers[type] = grapher
  }

  peity.register(
    'pie',
    {
      colours: ["#ff9900", "#fff4dd", "#ffc66e"],
      delimiter: null,
      diameter: 16
    },
    function(opts) {
      if (!opts.delimiter) {
        var delimiter = this.$elem.text().match(/[^0-9\.]/)
        opts.delimiter = delimiter ? delimiter[0] : ","
      }

      var values = this.values()

      if (opts.delimiter == "/") {
        var v1 = values[0]
        var v2 = values[1]
        values = [v1, v2 - v1]
      }

      var i = 0
      var length = values.length
      var sum = 0

      for (; i < length; i++) {
        sum += values[i]
      }

      var canvas = this.prepareCanvas(opts.diameter, opts.diameter)
      var context = this.context
      var half = canvas.width / 2
      var pi = Math.PI
      var colours = this.colours()

      context.save()
      context.translate(half, half)
      context.rotate(-pi / 2)

      for (i = 0; i < length; i++) {
        var value = values[i]
        var slice = (value / sum) * pi * 2

        context.beginPath()
        context.moveTo(0, 0)
        context.arc(0, 0, half, 0, slice, false)
        context.fillStyle = colours.call(this, value, i, values)
        context.fill()
        context.rotate(slice)
      }

      context.restore()
    }
  )

  peity.register(
    "line",
    {
      colour: "#c6d9fd",
      strokeColour: "#4d89f9",
      strokeWidth: 1,
      delimiter: ",",
      height: 16,
      max: null,
      min: 0,
      width: 32
    },
    function(opts) {
      var values = this.values()
      if (values.length == 1) values.push(values[0])
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var canvas = this.prepareCanvas(opts.width, opts.height)
      var context = this.context
      var width = canvas.width
      var height = canvas.height
      var xQuotient = width / (values.length - 1)
      var yQuotient = height / (max - min)

      var coords = [];
      var i;

      context.beginPath();
      context.moveTo(0, height + (min * yQuotient))

      for (i = 0; i < values.length; i++) {
        var x = i * xQuotient
        var y = height - (yQuotient * (values[i] - min))

        coords.push({ x: x, y: y });
        context.lineTo(x, y);
      }

      context.lineTo(width, height + (min * yQuotient))
      context.fillStyle = opts.colour;
      context.fill();

      if (opts.strokeWidth) {
        context.beginPath();
        context.moveTo(0, coords[0].y);
        for (i = 0; i < coords.length; i++) {
          context.lineTo(coords[i].x, coords[i].y);
        }
        context.lineWidth = opts.strokeWidth * devicePixelRatio;
        context.strokeStyle = opts.strokeColour;
        context.stroke();
      }
    }
  );

  peity.register(
    'bar',
    {
      colours: ["#4D89F9"],
      delimiter: ",",
      height: 16,
      max: null,
      min: 0,
      spacing: devicePixelRatio,
      width: 32
    },
    function(opts) {
      var values = this.values()
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var canvas = this.prepareCanvas(opts.width, opts.height)
      var context = this.context

      var width = canvas.width
      var height = canvas.height
      var yQuotient = height / (max - min)
      var space = opts.spacing
      var xQuotient = (width + space) / values.length
      var colours = this.colours()

      for (var i = 0; i < values.length; i++) {
        var value = values[i]
        var x = i * xQuotient
        var y = height - (yQuotient * (value - min))

        context.fillStyle = colours.call(this, value, i, values)
        context.fillRect(x, y, xQuotient - space, yQuotient * values[i])
      }
    }
  );
})(jQuery, document, Math, window.devicePixelRatio || 1);
<commit_msg>$el will do.<commit_after>// Peity jQuery plugin version 1.0.0
// (c) 2012 Ben Pickles
//
// http://benpickles.github.com/peity
//
// Released under MIT license.
(function($, document, Math, devicePixelRatio) {
  var canvasSupported = document.createElement("canvas").getContext

  var peity = $.fn.peity = function(type, options) {
    if (canvasSupported) {
      this.each(function() {
        var defaults = peity.defaults[type]
        var data = {}
        var $this = $(this)

        $.each($this.data(), function(name, value) {
          if (name in defaults) data[name] = value
        })

        var opts = $.extend({}, defaults, data, options)
        var chart = new Peity($this, type, opts)
        chart.draw()

        $this.change(function() {
          chart.draw()
        })
      });
    }

    return this;
  };

  var Peity = function($el, type, opts) {
    this.$el = $el
    this.type = type
    this.opts = opts
  }

  var PeityPrototype = Peity.prototype

  PeityPrototype.colours = function() {
    var colours = this.opts.colours
    var func = colours

    if (!$.isFunction(func)) {
      func = function(_, i) {
        return colours[i % colours.length]
      }
    }

    return func
  }

  PeityPrototype.draw = function() {
    peity.graphers[this.type].call(this, this.opts)
  }

  PeityPrototype.prepareCanvas = function(width, height) {
    var canvas = this.canvas

    if (canvas) {
      this.context.clearRect(0, 0, canvas.width, canvas.height)
    } else {
      canvas = $("<canvas>").attr({
        height: height * devicePixelRatio,
        width: width * devicePixelRatio
      })

      if (devicePixelRatio != 1) {
        canvas.css({
          height: height,
          width: width
        })
      }

      this.canvas = canvas = canvas[0]
      this.context = canvas.getContext("2d")
      this.$el.hide().before(canvas)
    }

    return canvas
  }

  PeityPrototype.values = function() {
    return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
      return parseFloat(value)
    })
  }

  peity.defaults = {}
  peity.graphers = {}

  peity.register = function(type, defaults, grapher) {
    this.defaults[type] = defaults
    this.graphers[type] = grapher
  }

  peity.register(
    'pie',
    {
      colours: ["#ff9900", "#fff4dd", "#ffc66e"],
      delimiter: null,
      diameter: 16
    },
    function(opts) {
      if (!opts.delimiter) {
        var delimiter = this.$el.text().match(/[^0-9\.]/)
        opts.delimiter = delimiter ? delimiter[0] : ","
      }

      var values = this.values()

      if (opts.delimiter == "/") {
        var v1 = values[0]
        var v2 = values[1]
        values = [v1, v2 - v1]
      }

      var i = 0
      var length = values.length
      var sum = 0

      for (; i < length; i++) {
        sum += values[i]
      }

      var canvas = this.prepareCanvas(opts.diameter, opts.diameter)
      var context = this.context
      var half = canvas.width / 2
      var pi = Math.PI
      var colours = this.colours()

      context.save()
      context.translate(half, half)
      context.rotate(-pi / 2)

      for (i = 0; i < length; i++) {
        var value = values[i]
        var slice = (value / sum) * pi * 2

        context.beginPath()
        context.moveTo(0, 0)
        context.arc(0, 0, half, 0, slice, false)
        context.fillStyle = colours.call(this, value, i, values)
        context.fill()
        context.rotate(slice)
      }

      context.restore()
    }
  )

  peity.register(
    "line",
    {
      colour: "#c6d9fd",
      strokeColour: "#4d89f9",
      strokeWidth: 1,
      delimiter: ",",
      height: 16,
      max: null,
      min: 0,
      width: 32
    },
    function(opts) {
      var values = this.values()
      if (values.length == 1) values.push(values[0])
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var canvas = this.prepareCanvas(opts.width, opts.height)
      var context = this.context
      var width = canvas.width
      var height = canvas.height
      var xQuotient = width / (values.length - 1)
      var yQuotient = height / (max - min)

      var coords = [];
      var i;

      context.beginPath();
      context.moveTo(0, height + (min * yQuotient))

      for (i = 0; i < values.length; i++) {
        var x = i * xQuotient
        var y = height - (yQuotient * (values[i] - min))

        coords.push({ x: x, y: y });
        context.lineTo(x, y);
      }

      context.lineTo(width, height + (min * yQuotient))
      context.fillStyle = opts.colour;
      context.fill();

      if (opts.strokeWidth) {
        context.beginPath();
        context.moveTo(0, coords[0].y);
        for (i = 0; i < coords.length; i++) {
          context.lineTo(coords[i].x, coords[i].y);
        }
        context.lineWidth = opts.strokeWidth * devicePixelRatio;
        context.strokeStyle = opts.strokeColour;
        context.stroke();
      }
    }
  );

  peity.register(
    'bar',
    {
      colours: ["#4D89F9"],
      delimiter: ",",
      height: 16,
      max: null,
      min: 0,
      spacing: devicePixelRatio,
      width: 32
    },
    function(opts) {
      var values = this.values()
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var canvas = this.prepareCanvas(opts.width, opts.height)
      var context = this.context

      var width = canvas.width
      var height = canvas.height
      var yQuotient = height / (max - min)
      var space = opts.spacing
      var xQuotient = (width + space) / values.length
      var colours = this.colours()

      for (var i = 0; i < values.length; i++) {
        var value = values[i]
        var x = i * xQuotient
        var y = height - (yQuotient * (value - min))

        context.fillStyle = colours.call(this, value, i, values)
        context.fillRect(x, y, xQuotient - space, yQuotient * values[i])
      }
    }
  );
})(jQuery, document, Math, window.devicePixelRatio || 1);
<|endoftext|>


<commit_before>// Peity jQuery plugin version 2.0.5
// (c) 2014 Ben Pickles
//
// http://benpickles.github.io/peity
//
// Released under MIT license.
(function($, document, Math) {
  var svgElement = function(tag, attrs) {
    var elem = document.createElementNS("http://www.w3.org/2000/svg", tag)
    $(elem).attr(attrs)
    return elem
  }

  // https://gist.github.com/madrobby/3201472
  var svgSupported = 'createElementNS' in document && svgElement('svg').createSVGRect

  var peity = $.fn.peity = function(type, options) {
    if (svgSupported) {
      this.each(function() {
        var $this = $(this)
        var chart = $this.data("peity")

        if (chart) {
          if (type) chart.type = type
          $.extend(chart.opts, options)
        } else {
          var defaults = peity.defaults[type]
          var data = {}

          $.each($this.data(), function(name, value) {
            if (name in defaults) data[name] = value
          })

          chart = new Peity(
            $this,
            type,
            $.extend({}, defaults, data, options)
          )

          $this
            .change(function() { chart.draw() })
            .data("peity", chart)
        }

        chart.draw()
      });
    }

    return this;
  };

  var Peity = function($el, type, opts) {
    this.$el = $el
    this.type = type
    this.opts = opts
  }

  var PeityPrototype = Peity.prototype

  PeityPrototype.draw = function() {
    peity.graphers[this.type].call(this, this.opts)
  }

  PeityPrototype.fill = function() {
    var fill = this.opts.fill

    return $.isFunction(fill)
      ? fill
      : function(_, i) { return fill[i % fill.length] }
  }

  PeityPrototype.prepare = function(width, height) {
    if (!this.svg) {
      this.$el.hide().after(
        this.svg = svgElement("svg", {
          "class": "peity"
        })
      )
    }

    return $(this.svg)
      .empty()
      .data('peity', this)
      .attr({
        height: height,
        width: width
      })
  }

  PeityPrototype.values = function() {
    return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
      return parseFloat(value)
    })
  }

  peity.defaults = {}
  peity.graphers = {}

  peity.register = function(type, defaults, grapher) {
    this.defaults[type] = defaults
    this.graphers[type] = grapher
  }

  peity.register(
    'pie',
    {
      delimiter: null,
      fill: ['#ff9900', '#fff4dd', '#ffc66e'],
      radius: 8
    },
    function(opts) {
      if (!opts.delimiter) {
        var delimiter = this.$el.text().match(/[^0-9\.]/)
        opts.delimiter = delimiter ? delimiter[0] : ","
      }

      var values = this.values()

      if (opts.delimiter == "/") {
        var v1 = values[0]
        var v2 = values[1]
        values = [v1, Math.max(0, v2 - v1)]
      }

      var i = 0
      var length = values.length
      var sum = 0

      for (; i < length; i++) {
        sum += values[i]
      }

      var diameter = opts.radius * 2

      var $svg = this.prepare(
        opts.width || diameter,
        opts.height || diameter
      )

      var width = $svg.width()
        , height = $svg.height()
        , cx = width / 2
        , cy = height / 2

      var radius = Math.min(cx, cy)
        , innerRadius = opts.innerRadius
      var pi = Math.PI
      var fill = this.fill()

      var scale = this.scale = function(value, radius) {
        var radians = value / sum * pi * 2 - pi / 2

        return [
          radius * Math.cos(radians) + cx,
          radius * Math.sin(radians) + cy
        ]
      }

      var cumulative = 0

      for (i = 0; i < length; i++) {
        var value = values[i]
          , portion = value / sum
          , node

        if (portion == 0) continue

        if (portion == 1) {
          if (innerRadius) {
            var x2 = cx - 0.01
              , y1 = cy - radius
              , y2 = cy - innerRadius

            node = svgElement('path', {
              d: [
                'M', cx, y1,
                'A', radius, radius, 0, 1, 1, x2, y1,
                'L', x2, y2,
                'A', innerRadius, innerRadius, 0, 1, 0, cx, y2,
                'Z'
              ].join(' ')
            })
          } else {
            node = svgElement("circle", {
              cx: cx,
              cy: cy,
              r: radius
            })
          }
        } else {
          var cumulativePlusValue = cumulative + value

          var d = ['M'].concat(
            scale(cumulative, radius),
            'A', radius, radius, 0, portion > 0.5 ? 1 : 0, 1,
            scale(cumulativePlusValue, radius),
            'L'
          )

          if (innerRadius) {
            d = d.concat(
              scale(cumulativePlusValue, innerRadius),
              'A', innerRadius, innerRadius, 0, portion > 0.5 ? 1 : 0, 0,
              scale(cumulative, innerRadius),
              'Z'
            )
          } else {
            d.push(cx, cy, 'Z')
          }

          cumulative += value

          node = svgElement("path", {
            d: d.join(" ")
          })
        }

        $(node).attr('fill', fill.call(this, value, i, values))

        this.svg.appendChild(node)
      }
    }
  )

  peity.register(
    'donut',
    peity.defaults.pie,
    function(opts) {
      if (!opts.innerRadius) opts.innerRadius = opts.radius * 0.5
      peity.graphers.pie.call(this, opts)
    }
  )

  peity.register(
    "line",
    {
      delimiter: ",",
      fill: "#c6d9fd",
      height: 16,
      max: null,
      min: 0,
      stroke: "#4d89f9",
      strokeWidth: 1,
      width: 32
    },
    function(opts) {
      var values = this.values()
      if (values.length == 1) values.push(values[0])
      var max = Math.max.apply(Math, typeof opts.max == 'number' ? values.concat(opts.max) : values)
      var min = Math.min.apply(Math, typeof opts.min == 'number' ? values.concat(opts.min) : values)

      var $svg = this.prepare(opts.width, opts.height)
        , width = $svg.width()
        , height = $svg.height() - opts.strokeWidth
        , diff = max - min

      var xScale = this.x = function(input) {
        return input * (width / (values.length - 1))
      }

      var yScale = this.y = function(input) {
        var y = height

        if (diff) {
          y -= ((input - min) / diff) * height
        }

        return y + opts.strokeWidth / 2
      }

      var zero = yScale(Math.max(min, 0))
        , coords = [0, zero]

      for (var i = 0; i < values.length; i++) {
        coords.push(
          xScale(i),
          yScale(values[i])
        )
      }

      coords.push(width, zero)

      this.svg.appendChild(
        svgElement('polygon', {
          fill: opts.fill,
          points: coords.join(' ')
        })
      )

      if (opts.strokeWidth) {
        this.svg.appendChild(
          svgElement('polyline', {
            fill: 'transparent',
            points: coords.slice(2, coords.length - 2).join(' '),
            stroke: opts.stroke,
            'stroke-width': opts.strokeWidth,
            'stroke-linecap': 'square'
          })
        )
      }
    }
  );

  peity.register(
    'bar',
    {
      delimiter: ",",
      fill: ["#4D89F9"],
      height: 16,
      max: null,
      min: 0,
      padding: 0.1,
      width: 32
    },
    function(opts) {
      var values = this.values()
      var max = Math.max.apply(Math, typeof opts.max == 'number' ? values.concat(opts.max) : values)
      var min = Math.min.apply(Math, typeof opts.min == 'number' ? values.concat(opts.min) : values)

      var $svg = this.prepare(opts.width, opts.height)
        , width = $svg.width()
        , height = $svg.height()
        , diff = max - min
        , padding = opts.padding
        , fill = this.fill()

      var xScale = this.x = function(input) {
        return input * width / values.length
      }

      var yScale = this.y = function(input) {
        return height - (
          diff
            ? ((input - min) / diff) * height
            : 1
        )
      }

      for (var i = 0; i < values.length; i++) {
        var x = xScale(i + padding)
          , w = xScale(i + 1 - padding) - x
          , value = values[i]
          , valueY = yScale(value)
          , y1 = valueY
          , y2 = valueY
          , h

        if (!diff) {
          h = 1
        } else if (value < 0) {
          y1 = yScale(Math.min(max, 0))
        } else {
          y2 = yScale(Math.max(min, 0))
        }

        h = y2 - y1

        if (h == 0) {
          h = 1
          if (max > 0 && diff) y1--
        }

        this.svg.appendChild(
          svgElement('rect', {
            fill: fill.call(this, value, i, values),
            x: x,
            y: y1,
            width: w,
            height: h
          })
        )
      }
    }
  );
})(jQuery, document, Math);
<commit_msg>It turns out you don’t need to specify Z to close a path.<commit_after>// Peity jQuery plugin version 2.0.5
// (c) 2014 Ben Pickles
//
// http://benpickles.github.io/peity
//
// Released under MIT license.
(function($, document, Math) {
  var svgElement = function(tag, attrs) {
    var elem = document.createElementNS("http://www.w3.org/2000/svg", tag)
    $(elem).attr(attrs)
    return elem
  }

  // https://gist.github.com/madrobby/3201472
  var svgSupported = 'createElementNS' in document && svgElement('svg').createSVGRect

  var peity = $.fn.peity = function(type, options) {
    if (svgSupported) {
      this.each(function() {
        var $this = $(this)
        var chart = $this.data("peity")

        if (chart) {
          if (type) chart.type = type
          $.extend(chart.opts, options)
        } else {
          var defaults = peity.defaults[type]
          var data = {}

          $.each($this.data(), function(name, value) {
            if (name in defaults) data[name] = value
          })

          chart = new Peity(
            $this,
            type,
            $.extend({}, defaults, data, options)
          )

          $this
            .change(function() { chart.draw() })
            .data("peity", chart)
        }

        chart.draw()
      });
    }

    return this;
  };

  var Peity = function($el, type, opts) {
    this.$el = $el
    this.type = type
    this.opts = opts
  }

  var PeityPrototype = Peity.prototype

  PeityPrototype.draw = function() {
    peity.graphers[this.type].call(this, this.opts)
  }

  PeityPrototype.fill = function() {
    var fill = this.opts.fill

    return $.isFunction(fill)
      ? fill
      : function(_, i) { return fill[i % fill.length] }
  }

  PeityPrototype.prepare = function(width, height) {
    if (!this.svg) {
      this.$el.hide().after(
        this.svg = svgElement("svg", {
          "class": "peity"
        })
      )
    }

    return $(this.svg)
      .empty()
      .data('peity', this)
      .attr({
        height: height,
        width: width
      })
  }

  PeityPrototype.values = function() {
    return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
      return parseFloat(value)
    })
  }

  peity.defaults = {}
  peity.graphers = {}

  peity.register = function(type, defaults, grapher) {
    this.defaults[type] = defaults
    this.graphers[type] = grapher
  }

  peity.register(
    'pie',
    {
      delimiter: null,
      fill: ['#ff9900', '#fff4dd', '#ffc66e'],
      radius: 8
    },
    function(opts) {
      if (!opts.delimiter) {
        var delimiter = this.$el.text().match(/[^0-9\.]/)
        opts.delimiter = delimiter ? delimiter[0] : ","
      }

      var values = this.values()

      if (opts.delimiter == "/") {
        var v1 = values[0]
        var v2 = values[1]
        values = [v1, Math.max(0, v2 - v1)]
      }

      var i = 0
      var length = values.length
      var sum = 0

      for (; i < length; i++) {
        sum += values[i]
      }

      var diameter = opts.radius * 2

      var $svg = this.prepare(
        opts.width || diameter,
        opts.height || diameter
      )

      var width = $svg.width()
        , height = $svg.height()
        , cx = width / 2
        , cy = height / 2

      var radius = Math.min(cx, cy)
        , innerRadius = opts.innerRadius
      var pi = Math.PI
      var fill = this.fill()

      var scale = this.scale = function(value, radius) {
        var radians = value / sum * pi * 2 - pi / 2

        return [
          radius * Math.cos(radians) + cx,
          radius * Math.sin(radians) + cy
        ]
      }

      var cumulative = 0

      for (i = 0; i < length; i++) {
        var value = values[i]
          , portion = value / sum
          , node

        if (portion == 0) continue

        if (portion == 1) {
          if (innerRadius) {
            var x2 = cx - 0.01
              , y1 = cy - radius
              , y2 = cy - innerRadius

            node = svgElement('path', {
              d: [
                'M', cx, y1,
                'A', radius, radius, 0, 1, 1, x2, y1,
                'L', x2, y2,
                'A', innerRadius, innerRadius, 0, 1, 0, cx, y2
              ].join(' ')
            })
          } else {
            node = svgElement("circle", {
              cx: cx,
              cy: cy,
              r: radius
            })
          }
        } else {
          var cumulativePlusValue = cumulative + value

          var d = ['M'].concat(
            scale(cumulative, radius),
            'A', radius, radius, 0, portion > 0.5 ? 1 : 0, 1,
            scale(cumulativePlusValue, radius),
            'L'
          )

          if (innerRadius) {
            d = d.concat(
              scale(cumulativePlusValue, innerRadius),
              'A', innerRadius, innerRadius, 0, portion > 0.5 ? 1 : 0, 0,
              scale(cumulative, innerRadius)
            )
          } else {
            d.push(cx, cy)
          }

          cumulative += value

          node = svgElement("path", {
            d: d.join(" ")
          })
        }

        $(node).attr('fill', fill.call(this, value, i, values))

        this.svg.appendChild(node)
      }
    }
  )

  peity.register(
    'donut',
    peity.defaults.pie,
    function(opts) {
      if (!opts.innerRadius) opts.innerRadius = opts.radius * 0.5
      peity.graphers.pie.call(this, opts)
    }
  )

  peity.register(
    "line",
    {
      delimiter: ",",
      fill: "#c6d9fd",
      height: 16,
      max: null,
      min: 0,
      stroke: "#4d89f9",
      strokeWidth: 1,
      width: 32
    },
    function(opts) {
      var values = this.values()
      if (values.length == 1) values.push(values[0])
      var max = Math.max.apply(Math, typeof opts.max == 'number' ? values.concat(opts.max) : values)
      var min = Math.min.apply(Math, typeof opts.min == 'number' ? values.concat(opts.min) : values)

      var $svg = this.prepare(opts.width, opts.height)
        , width = $svg.width()
        , height = $svg.height() - opts.strokeWidth
        , diff = max - min

      var xScale = this.x = function(input) {
        return input * (width / (values.length - 1))
      }

      var yScale = this.y = function(input) {
        var y = height

        if (diff) {
          y -= ((input - min) / diff) * height
        }

        return y + opts.strokeWidth / 2
      }

      var zero = yScale(Math.max(min, 0))
        , coords = [0, zero]

      for (var i = 0; i < values.length; i++) {
        coords.push(
          xScale(i),
          yScale(values[i])
        )
      }

      coords.push(width, zero)

      this.svg.appendChild(
        svgElement('polygon', {
          fill: opts.fill,
          points: coords.join(' ')
        })
      )

      if (opts.strokeWidth) {
        this.svg.appendChild(
          svgElement('polyline', {
            fill: 'transparent',
            points: coords.slice(2, coords.length - 2).join(' '),
            stroke: opts.stroke,
            'stroke-width': opts.strokeWidth,
            'stroke-linecap': 'square'
          })
        )
      }
    }
  );

  peity.register(
    'bar',
    {
      delimiter: ",",
      fill: ["#4D89F9"],
      height: 16,
      max: null,
      min: 0,
      padding: 0.1,
      width: 32
    },
    function(opts) {
      var values = this.values()
      var max = Math.max.apply(Math, typeof opts.max == 'number' ? values.concat(opts.max) : values)
      var min = Math.min.apply(Math, typeof opts.min == 'number' ? values.concat(opts.min) : values)

      var $svg = this.prepare(opts.width, opts.height)
        , width = $svg.width()
        , height = $svg.height()
        , diff = max - min
        , padding = opts.padding
        , fill = this.fill()

      var xScale = this.x = function(input) {
        return input * width / values.length
      }

      var yScale = this.y = function(input) {
        return height - (
          diff
            ? ((input - min) / diff) * height
            : 1
        )
      }

      for (var i = 0; i < values.length; i++) {
        var x = xScale(i + padding)
          , w = xScale(i + 1 - padding) - x
          , value = values[i]
          , valueY = yScale(value)
          , y1 = valueY
          , y2 = valueY
          , h

        if (!diff) {
          h = 1
        } else if (value < 0) {
          y1 = yScale(Math.min(max, 0))
        } else {
          y2 = yScale(Math.max(min, 0))
        }

        h = y2 - y1

        if (h == 0) {
          h = 1
          if (max > 0 && diff) y1--
        }

        this.svg.appendChild(
          svgElement('rect', {
            fill: fill.call(this, value, i, values),
            x: x,
            y: y1,
            width: w,
            height: h
          })
        )
      }
    }
  );
})(jQuery, document, Math);
<|endoftext|>


<commit_before>// Peity jQuery plugin version 1.2.1
// (c) 2013 Ben Pickles
//
// http://benpickles.github.io/peity
//
// Released under MIT license.
(function($, document, Math, devicePixelRatio) {
  var canvasSupported = document.createElement("canvas").getContext

  var peity = $.fn.peity = function(type, options) {
    if (canvasSupported) {
      this.each(function() {
        var $this = $(this)
        var chart = $this.data("peity")

        if (chart) {
          if (type) chart.type = type
          $.extend(chart.opts, options)
          chart.draw()
        } else {
          var defaults = peity.defaults[type]
          var data = {}

          $.each($this.data(), function(name, value) {
            if (name in defaults) data[name] = value
          })

          var opts = $.extend({}, defaults, data, options)
          var chart = new Peity($this, type, opts)
          chart.draw()

          $this
            .change(function() { chart.draw() })
            .data("peity", chart)
        }
      });
    }

    return this;
  };

  var Peity = function($el, type, opts) {
    this.$el = $el
    this.type = type
    this.opts = opts
  }

  var PeityPrototype = Peity.prototype

  PeityPrototype.draw = function() {
    peity.graphers[this.type].call(this, this.opts)
  }

  PeityPrototype.fill = function() {
    var fill = this.opts.fill
    var func = fill

    if (!$.isFunction(func)) {
      func = function(_, i) {
        return fill[i % fill.length]
      }
    }

    return func
  }

  PeityPrototype.prepareCanvas = function(width, height) {
    if (this.svg) {
      $(this.svg).empty()
    } else {
      this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
      this.svg.setAttribute("class", "peity")

      this.$el.hide().after(this.svg)

      $(this.svg).data("peity", this)
    }

    this.svg.setAttribute("height", height)
    this.svg.setAttribute("width", width)
  }

  PeityPrototype.values = function() {
    return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
      return parseFloat(value)
    })
  }

  peity.defaults = {}
  peity.graphers = {}

  peity.register = function(type, defaults, grapher) {
    this.defaults[type] = defaults
    this.graphers[type] = grapher
  }

  peity.register(
    'pie',
    {
      delimiter: null,
      diameter: 16,
      fill: ["#ff9900", "#fff4dd", "#ffc66e"]
    },
    function(opts) {
      if (!opts.delimiter) {
        var delimiter = this.$el.text().match(/[^0-9\.]/)
        opts.delimiter = delimiter ? delimiter[0] : ","
      }

      var values = this.values()

      if (opts.delimiter == "/") {
        var v1 = values[0]
        var v2 = values[1]
        values = [v1, v2 - v1]
      }

      var i = 0
      var length = values.length
      var sum = 0

      for (; i < length; i++) {
        sum += values[i]
      }

      var width = opts.width || opts.diameter
        , height = opts.height || opts.diameter

      this.prepareCanvas(width, height)

      var radius = Math.min(width, height) / 2
      var pi = Math.PI
      var fill = this.fill()
      var start = -pi / 2

      for (i = 0; i < length; i++) {
        var value = values[i]
          , portion = value / sum
          , node

        if (portion == 1) {
          node = document.createElementNS("http://www.w3.org/2000/svg", "circle")
          node.setAttribute("cx", radius)
          node.setAttribute("cy", radius)
          node.setAttribute("r", radius)
        } else {
          var slice = portion * pi * 2
            , end = start + slice
            , x1 = radius * Math.cos(start) + radius
            , y1 = radius * Math.sin(start) + radius
            , x2 = radius * Math.cos(end) + radius
            , y2 = radius * Math.sin(end) + radius

          var d = [
            "M", radius, radius,
            "L", x1, y1,
            "A", radius, radius, 0, slice > pi ? 1 : 0, 1, x2, y2,
            "Z"
          ]

          node = document.createElementNS("http://www.w3.org/2000/svg", "path")
          node.setAttribute("d", d.join(" "))

          start = end
        }

        node.setAttribute("fill", fill.call(this, value, i, values))

        this.svg.appendChild(node)
      }
    }
  )

  peity.register(
    "line",
    {
      delimiter: ",",
      fill: "#c6d9fd",
      height: 16,
      max: null,
      min: 0,
      stroke: "#4d89f9",
      strokeWidth: 1,
      width: 32
    },
    function(opts) {
      var values = this.values()
      if (values.length == 1) values.push(values[0])
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var width = opts.width
        , height = opts.height

      this.prepareCanvas(width, height)

      height -= opts.strokeWidth

      var xQuotient = width / (values.length - 1)
        , yQuotient = height / (max - min)
        , zero = height + (min * yQuotient)
        , coords = [0, zero]

      for (var i = 0; i < values.length; i++) {
        var x = i * xQuotient
        var y = height - (yQuotient * (values[i] - min)) + opts.strokeWidth / 2

        coords.push(x, y)
      }

      coords.push(width, zero)

      var polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon")
      polygon.setAttribute("fill", opts.fill)
      polygon.setAttribute("points", coords.join(" "))

      this.svg.appendChild(polygon)

      if (opts.strokeWidth) {
        var polyline = document.createElementNS("http://www.w3.org/2000/svg", "polyline")
        polyline.setAttribute("fill", "transparent")
        polyline.setAttribute("points", coords.slice(2, coords.length - 2).join(" "))
        polyline.setAttribute("stroke", opts.stroke)
        polyline.setAttribute("stroke-width", opts.strokeWidth)
        polyline.setAttribute("stroke-linecap", "square")

        this.svg.appendChild(polyline)
      }
    }
  );

  peity.register(
    'bar',
    {
      delimiter: ",",
      fill: ["#4D89F9"],
      height: 16,
      max: null,
      min: 0,
      spacing: devicePixelRatio,
      width: 32
    },
    function(opts) {
      var values = this.values()
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var width = opts.width
        , height = opts.height

      this.prepareCanvas(width, height)

      var yQuotient = height / (max - min)
      var space = opts.spacing
      var xQuotient = (width + space) / values.length
      var fill = this.fill()

      for (var i = 0; i < values.length; i++) {
        var value = values[i]
        var y = height - (yQuotient * (value - min))
        var h

        if (value == 0) {
          if (min >= 0 || max > 0) y -= 1
          h = 1
        } else {
          h = yQuotient * value
        }

        if (h < 0) {
          y += h
          h = -h
        }

        var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect")
        rect.setAttribute("fill", fill.call(this, value, i, values))
        rect.setAttribute("x", i * xQuotient)
        rect.setAttribute("y", y)
        rect.setAttribute("width", xQuotient - space)
        rect.setAttribute("height", h)

        this.svg.appendChild(rect)
      }
    }
  );
})(jQuery, document, Math, window.devicePixelRatio || 1);
<commit_msg>We're preparing a SVG element.<commit_after>// Peity jQuery plugin version 1.2.1
// (c) 2013 Ben Pickles
//
// http://benpickles.github.io/peity
//
// Released under MIT license.
(function($, document, Math, devicePixelRatio) {
  var canvasSupported = document.createElement("canvas").getContext

  var peity = $.fn.peity = function(type, options) {
    if (canvasSupported) {
      this.each(function() {
        var $this = $(this)
        var chart = $this.data("peity")

        if (chart) {
          if (type) chart.type = type
          $.extend(chart.opts, options)
          chart.draw()
        } else {
          var defaults = peity.defaults[type]
          var data = {}

          $.each($this.data(), function(name, value) {
            if (name in defaults) data[name] = value
          })

          var opts = $.extend({}, defaults, data, options)
          var chart = new Peity($this, type, opts)
          chart.draw()

          $this
            .change(function() { chart.draw() })
            .data("peity", chart)
        }
      });
    }

    return this;
  };

  var Peity = function($el, type, opts) {
    this.$el = $el
    this.type = type
    this.opts = opts
  }

  var PeityPrototype = Peity.prototype

  PeityPrototype.draw = function() {
    peity.graphers[this.type].call(this, this.opts)
  }

  PeityPrototype.fill = function() {
    var fill = this.opts.fill
    var func = fill

    if (!$.isFunction(func)) {
      func = function(_, i) {
        return fill[i % fill.length]
      }
    }

    return func
  }

  PeityPrototype.prepareSVG = function(width, height) {
    if (this.svg) {
      $(this.svg).empty()
    } else {
      this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
      this.svg.setAttribute("class", "peity")

      this.$el.hide().after(this.svg)

      $(this.svg).data("peity", this)
    }

    this.svg.setAttribute("height", height)
    this.svg.setAttribute("width", width)
  }

  PeityPrototype.values = function() {
    return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
      return parseFloat(value)
    })
  }

  peity.defaults = {}
  peity.graphers = {}

  peity.register = function(type, defaults, grapher) {
    this.defaults[type] = defaults
    this.graphers[type] = grapher
  }

  peity.register(
    'pie',
    {
      delimiter: null,
      diameter: 16,
      fill: ["#ff9900", "#fff4dd", "#ffc66e"]
    },
    function(opts) {
      if (!opts.delimiter) {
        var delimiter = this.$el.text().match(/[^0-9\.]/)
        opts.delimiter = delimiter ? delimiter[0] : ","
      }

      var values = this.values()

      if (opts.delimiter == "/") {
        var v1 = values[0]
        var v2 = values[1]
        values = [v1, v2 - v1]
      }

      var i = 0
      var length = values.length
      var sum = 0

      for (; i < length; i++) {
        sum += values[i]
      }

      var width = opts.width || opts.diameter
        , height = opts.height || opts.diameter

      this.prepareSVG(width, height)

      var radius = Math.min(width, height) / 2
      var pi = Math.PI
      var fill = this.fill()
      var start = -pi / 2

      for (i = 0; i < length; i++) {
        var value = values[i]
          , portion = value / sum
          , node

        if (portion == 1) {
          node = document.createElementNS("http://www.w3.org/2000/svg", "circle")
          node.setAttribute("cx", radius)
          node.setAttribute("cy", radius)
          node.setAttribute("r", radius)
        } else {
          var slice = portion * pi * 2
            , end = start + slice
            , x1 = radius * Math.cos(start) + radius
            , y1 = radius * Math.sin(start) + radius
            , x2 = radius * Math.cos(end) + radius
            , y2 = radius * Math.sin(end) + radius

          var d = [
            "M", radius, radius,
            "L", x1, y1,
            "A", radius, radius, 0, slice > pi ? 1 : 0, 1, x2, y2,
            "Z"
          ]

          node = document.createElementNS("http://www.w3.org/2000/svg", "path")
          node.setAttribute("d", d.join(" "))

          start = end
        }

        node.setAttribute("fill", fill.call(this, value, i, values))

        this.svg.appendChild(node)
      }
    }
  )

  peity.register(
    "line",
    {
      delimiter: ",",
      fill: "#c6d9fd",
      height: 16,
      max: null,
      min: 0,
      stroke: "#4d89f9",
      strokeWidth: 1,
      width: 32
    },
    function(opts) {
      var values = this.values()
      if (values.length == 1) values.push(values[0])
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var width = opts.width
        , height = opts.height

      this.prepareSVG(width, height)

      height -= opts.strokeWidth

      var xQuotient = width / (values.length - 1)
        , yQuotient = height / (max - min)
        , zero = height + (min * yQuotient)
        , coords = [0, zero]

      for (var i = 0; i < values.length; i++) {
        var x = i * xQuotient
        var y = height - (yQuotient * (values[i] - min)) + opts.strokeWidth / 2

        coords.push(x, y)
      }

      coords.push(width, zero)

      var polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon")
      polygon.setAttribute("fill", opts.fill)
      polygon.setAttribute("points", coords.join(" "))

      this.svg.appendChild(polygon)

      if (opts.strokeWidth) {
        var polyline = document.createElementNS("http://www.w3.org/2000/svg", "polyline")
        polyline.setAttribute("fill", "transparent")
        polyline.setAttribute("points", coords.slice(2, coords.length - 2).join(" "))
        polyline.setAttribute("stroke", opts.stroke)
        polyline.setAttribute("stroke-width", opts.strokeWidth)
        polyline.setAttribute("stroke-linecap", "square")

        this.svg.appendChild(polyline)
      }
    }
  );

  peity.register(
    'bar',
    {
      delimiter: ",",
      fill: ["#4D89F9"],
      height: 16,
      max: null,
      min: 0,
      spacing: devicePixelRatio,
      width: 32
    },
    function(opts) {
      var values = this.values()
      var max = Math.max.apply(Math, values.concat([opts.max]));
      var min = Math.min.apply(Math, values.concat([opts.min]))

      var width = opts.width
        , height = opts.height

      this.prepareSVG(width, height)

      var yQuotient = height / (max - min)
      var space = opts.spacing
      var xQuotient = (width + space) / values.length
      var fill = this.fill()

      for (var i = 0; i < values.length; i++) {
        var value = values[i]
        var y = height - (yQuotient * (value - min))
        var h

        if (value == 0) {
          if (min >= 0 || max > 0) y -= 1
          h = 1
        } else {
          h = yQuotient * value
        }

        if (h < 0) {
          y += h
          h = -h
        }

        var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect")
        rect.setAttribute("fill", fill.call(this, value, i, values))
        rect.setAttribute("x", i * xQuotient)
        rect.setAttribute("y", y)
        rect.setAttribute("width", xQuotient - space)
        rect.setAttribute("height", h)

        this.svg.appendChild(rect)
      }
    }
  );
})(jQuery, document, Math, window.devicePixelRatio || 1);
<|endoftext|>


<commit_before>/*!
 * JSizes - JQuery plugin v0.33
 *
 * Licensed under the revised BSD License.
 * Copyright 2008-2010 Bram Stein
 * All rights reserved.
 */
/*global jQuery*/
(function ($) {
	var num = function (value) {
			return parseInt(value, 10) || 0;
		},
		isNumber = function (value) {
			return (typeof value === 'number' || value instanceof Number) && !isNaN(value);
		};

	/**
	 * Sets or gets the values for min-width, min-height, max-width
	 * and max-height.
	 */
	$.each(['min', 'max'], function (i, name) {
		$.fn[name + 'Size'] = function (value) {
			var width, height;
			if (value) {
				if (value.width !== undefined) {
					this.css(name + '-width', value.width);
				}
				if (value.height !== undefined) {
					this.css(name + '-height', value.height);
				}
				return this;
			}
			else {
				width = this.css(name + '-width');
				height = this.css(name + '-height');
				// Apparently:
				//  * Opera returns -1px instead of none
				//  * IE6 returns undefined instead of none
				return {'width': (name === 'max' && (width === undefined || width === 'none' || num(width) === -1) && Number.MAX_VALUE) || num(width),
						'height': (name === 'max' && (height === undefined || height === 'none' || num(height) === -1) && Number.MAX_VALUE) || num(height)};
			}
		};
	});

	/**
	 * Returns whether or not an element is visible.
	 */
	$.fn.isVisible = function () {
		return this.is(':visible');
	};

	/**
	 * Sets or gets the values for border, margin and padding.
	 */
	$.each(['border', 'margin', 'padding'], function (i, name) {
		$.fn[name] = function (value) {
			if (value) {
				if (value.top !== undefined) {
					this.css(name + '-top' + (name === 'border' ? '-width' : ''), value.top);
				}
				if (value.bottom !== undefined) {
					this.css(name + '-bottom' + (name === 'border' ? '-width' : ''), value.bottom);
				}
				if (value.left !== undefined) {
					this.css(name + '-left' + (name === 'border' ? '-width' : ''), value.left);
				}
				if (value.right !== undefined) {
					this.css(name + '-right' + (name === 'border' ? '-width' : ''), value.right);
				}
				return this;
			}
			else {
				return {top: num(this.css(name + '-top' + (name === 'border' ? '-width' : ''))),
						bottom: num(this.css(name + '-bottom' + (name === 'border' ? '-width' : ''))),
						left: num(this.css(name + '-left' + (name === 'border' ? '-width' : ''))),
						right: num(this.css(name + '-right' + (name === 'border' ? '-width' : '')))};
			}
		};
	});
})(jQuery);
<commit_msg>Removed isNumber method.<commit_after>/*!
 * JSizes - JQuery plugin v0.33
 *
 * Licensed under the revised BSD License.
 * Copyright 2008-2010 Bram Stein
 * All rights reserved.
 */
/*global jQuery*/
(function ($) {
	var num = function (value) {
			return parseInt(value, 10) || 0;
		};

	/**
	 * Sets or gets the values for min-width, min-height, max-width
	 * and max-height.
	 */
	$.each(['min', 'max'], function (i, name) {
		$.fn[name + 'Size'] = function (value) {
			var width, height;
			if (value) {
				if (value.width !== undefined) {
					this.css(name + '-width', value.width);
				}
				if (value.height !== undefined) {
					this.css(name + '-height', value.height);
				}
				return this;
			}
			else {
				width = this.css(name + '-width');
				height = this.css(name + '-height');
				// Apparently:
				//  * Opera returns -1px instead of none
				//  * IE6 returns undefined instead of none
				return {'width': (name === 'max' && (width === undefined || width === 'none' || num(width) === -1) && Number.MAX_VALUE) || num(width),
						'height': (name === 'max' && (height === undefined || height === 'none' || num(height) === -1) && Number.MAX_VALUE) || num(height)};
			}
		};
	});

	/**
	 * Returns whether or not an element is visible.
	 */
	$.fn.isVisible = function () {
		return this.is(':visible');
	};

	/**
	 * Sets or gets the values for border, margin and padding.
	 */
	$.each(['border', 'margin', 'padding'], function (i, name) {
		$.fn[name] = function (value) {
			if (value) {
				if (value.top !== undefined) {
					this.css(name + '-top' + (name === 'border' ? '-width' : ''), value.top);
				}
				if (value.bottom !== undefined) {
					this.css(name + '-bottom' + (name === 'border' ? '-width' : ''), value.bottom);
				}
				if (value.left !== undefined) {
					this.css(name + '-left' + (name === 'border' ? '-width' : ''), value.left);
				}
				if (value.right !== undefined) {
					this.css(name + '-right' + (name === 'border' ? '-width' : ''), value.right);
				}
				return this;
			}
			else {
				return {top: num(this.css(name + '-top' + (name === 'border' ? '-width' : ''))),
						bottom: num(this.css(name + '-bottom' + (name === 'border' ? '-width' : ''))),
						left: num(this.css(name + '-left' + (name === 'border' ? '-width' : ''))),
						right: num(this.css(name + '-right' + (name === 'border' ? '-width' : '')))};
			}
		};
	});
})(jQuery);
<|endoftext|>


<commit_before>
var MyTitle = React.createClass({
  render: function () {
    return (
      React.DOM.div(null,
        React.DOM.h1(null, 'check out this component!'))
    )
  }
})

var MyFirstComponent = React.createClass({
  render: function() {
    return (
      React.DOM.div(null,
        React.createElement(MyTitle),
        React.createElement(MyTitle),
        React.createElement(MyTitle),
        React.createElement(MyTitle))
        // React.DOM.h1(null, 'This is my first component!'))
    )
  }
})

ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
<commit_msg>Create a factory method for the MyTitle component.<commit_after>
var MyTitle = React.createClass({
  render: function () {
    return (
      React.DOM.div(null,
        React.DOM.h1(null, 'check out this component!'))
    )
  }
})

var MyTitleFactory = React.createFactory(MyTitle)

var MyFirstComponent = React.createClass({
  render: function() {
    return (
      React.DOM.div(null,
        MyTitleFactory(null),
        MyTitleFactory(null),
        MyTitleFactory(null),
        MyTitleFactory(null))
        // React.DOM.h1(null, 'This is my first component!'))
    )
  }
})

ReactDOM.render(React.createElement(MyFirstComponent), document.getElementById('app'))
<|endoftext|>


<commit_before>//Object.create shim
if (typeof Object.create === "undefined") {
    Object.create = function (proto) {
        var F = function () {};
        F.prototype = proto;
        return new F();
    };
}

//Date.now shim
if (typeof Date.now === "undefined") {
    Date.now = function () {
        return new Date().getTime();
    };
}

/**
 * Generic proxy object to catch or group DOMEvents together
 * @param context {Object} the context of the callback
 * @param [tag] {String|HTMLElement} either the tagname of the proxy element or a pre-specified element
 * @constructor DOMRouter
 */
var DOMRouter = function (context, tag) {
    var self = this;
    self.context = context;
    self.element = (tag instanceof HTMLElement ?
        tag : document.createElement(tag || "div"));
    self.listeners = {};
    self.listener = function () {
        self.callback.apply(self, arguments)
    };
};

/**
 * resolves the event based on the actual browser
 * @param event {String}
 * @returns {String}
 */
DOMRouter.prototype.normalizeEvent = function (event) {
    return (DOMRouter.eventPrefix + event.replace("on", ""));
};

/**
 * adds event listener
 * @param listeners {Object} map of events as keys and callbacks as strings or functions
 * @return {DOMRouter}
 */
DOMRouter.prototype.addListener = function (listeners) {
    var l;
    var element = this.element;
    var _listeners = this.listeners;

    for (l in listeners) {
        if (listeners.hasOwnProperty(l) && !_listeners.hasOwnProperty(l)) {
            element[DOMRouter.handlers.add](this.normalizeEvent(l), this.listener);

            _listeners[l] = listeners[l];
        }
    }

    return this;
};

/**
 * removes the listener from the lookup
 * @param listener
 * @return {DOMRouter}
 */
DOMRouter.prototype.removeListener = function (listener) {
    var element = this.element;
    delete this.listeners[listener];
    element[DOMRouter.handlers.remove](this.normalizeEvent(listener), this.listener);
    return this;
};

/**
 * removes all listeners from the dom element
 * @return {DOMRouter}
 */
DOMRouter.prototype.removeListeners = function () {
    var element = this.element;
    var listeners = this.listeners;
    var l;

    for (l in listeners) {
        if (listeners.hasOwnProperty(l)) {
            element[DOMRouter.handlers.remove](this.normalizeEvent(l), this.listener);
        }
    }

    return this;
};

/**
 * removes all listeners from the dom element and the hub too
 * @return {DOMRouter}
 */
DOMRouter.prototype.removeAllListeners = function () {
    this.removeListeners();
    this.listeners = {};
    return this;
};

/**
 * returns the proxy DOMElement
 * @returns {HTMLElement}
 */
DOMRouter.prototype.getElement = function () {
	return this.element;
};

/**
 * replaces the router element
 * @param element {HTMLElement}
 * @param listeners {Object} map of events as keys and callbacks as strings or functions
 * @return {DOMRouter}
 */
DOMRouter.prototype.setElement = function (element, listeners) {
    var l;
    var _listeners = this.listeners;

    //unregister all events from old element
    this.removeListeners();

    this.element = element;

    //register events again
    for (l in listeners) {
        if (listeners.hasOwnProperty(l) && !_listeners.hasOwnProperty(l)) {
            element[DOMRouter.handlers.add](this.normalizeEvent(l), this.listener);

            _listeners[l] = listeners[l];
        }
    }

    return this;
};

/**
 * generic callback for each event
 * @param event {Event}
 */
DOMRouter.prototype.callback = function (event) {
    var listeners = this.listeners;
    var type = event.type;
    var context = this.context;
    var listener;

    if (listeners.hasOwnProperty(type)) {
        listener = listeners[type];

        if (typeof listener === "string") {
            context[listener].apply(context, arguments);
        } else if (typeof listener === "function") {
            listener.apply(context, arguments);
        }
    }
};

/**
 * collection of the browser specific event types
 * @static
 */
DOMRouter.handlers = (function () {
    var events = {
        add: "addEventListener",
        remove: "removeEventListener",
        dispatch: "dispatchEvent"
    };

    //IE
    if (document.attachEvent) {
        events.add = "attachEvent";
        events.remove = "detachEvent";
        events.dispatch = "fireEvent";
    }

    return events;
}());

/**
 * prefix for browser specific generic event types
 * @static
 */
DOMRouter.eventPrefix = (function () {
    var div = document.createElement("div");
    return (div.addEventListener ? "" : "on");
}());

/**
 * @static
 * for debugging
 * @returns {Console}
 */
DOMRouter.getConsole = function () {
    return (console ? console : { log: function () {} });
};
<commit_msg>Creates reference to DOMRouter instance on the HTMLElement: __router__ , Implements listener staticaly so clearly it will only have one method to invoke<commit_after>//Object.create shim
if (typeof Object.create === "undefined") {
    Object.create = function (proto) {
        var F = function () {};
        F.prototype = proto;
        return new F();
    };
}

//Date.now shim
if (typeof Date.now === "undefined") {
    Date.now = function () {
        return new Date().getTime();
    };
}

/**
 * Generic proxy object to catch or group DOMEvents together
 * @param context {Object} the context of the callback
 * @param [tag] {String|HTMLElement} either the tagname of the proxy element or a pre-specified element
 * @constructor DOMRouter
 */
var DOMRouter = function (context, tag) {
    this.context = context;
    this.element = (tag instanceof HTMLElement ?
        tag : document.createElement(tag || "div"));
    this.element.__router__ = this;
    this.listeners = {};
    this.listener = DOMRouter.listener;
};

/**
 * generic event capture method. Each DOMRouter instance references and calls ONE function
 */
DOMRouter.listener = function () {
    var router = this.__router__;
    return router.callback.apply(router, arguments);
};

/**
 * resolves the event based on the actual browser
 * @param event {String}
 * @returns {String}
 */
DOMRouter.prototype.normalizeEvent = function (event) {
    return (DOMRouter.eventPrefix + event.replace("on", ""));
};

/**
 * adds event listener
 * @param listeners {Object} map of events as keys and callbacks as strings or functions
 * @return {DOMRouter}
 */
DOMRouter.prototype.addListener = function (listeners) {
    var l;
    var element = this.element;
    var _listeners = this.listeners;

    for (l in listeners) {
        if (listeners.hasOwnProperty(l) && !_listeners.hasOwnProperty(l)) {
            element[DOMRouter.handlers.add](this.normalizeEvent(l), this.listener);

            _listeners[l] = listeners[l];
        }
    }

    return this;
};

/**
 * removes the listener from the lookup
 * @param listener
 * @return {DOMRouter}
 */
DOMRouter.prototype.removeListener = function (listener) {
    var element = this.element;
    delete this.listeners[listener];
    element[DOMRouter.handlers.remove](this.normalizeEvent(listener), this.listener);
    return this;
};

/**
 * removes all listeners from the dom element
 * @return {DOMRouter}
 */
DOMRouter.prototype.removeListeners = function () {
    var element = this.element;
    var listeners = this.listeners;
    var l;

    for (l in listeners) {
        if (listeners.hasOwnProperty(l)) {
            element[DOMRouter.handlers.remove](this.normalizeEvent(l), this.listener);
        }
    }

    return this;
};

/**
 * removes all listeners from the dom element and the hub too
 * @return {DOMRouter}
 */
//TODO: rename to 'reset'
DOMRouter.prototype.removeAllListeners = function () {
    this.removeListeners();
    this.listeners = {};
    return this;
};

/**
 * returns the proxy DOMElement
 * @returns {HTMLElement}
 */
DOMRouter.prototype.getElement = function () {
	return this.element;
};

/**
 * replaces the router element
 * @param element {HTMLElement}
 * @param listeners {Object} map of events as keys and callbacks as strings or functions
 * @return {DOMRouter}
 */
DOMRouter.prototype.setElement = function (element, listeners) {
    var l;
    var _listeners = this.listeners;

    //unregister all events from old element
    this.removeListeners();

    this.element = element;
    this.element.__router__ = this;

    //register events again
    for (l in listeners) {
        if (listeners.hasOwnProperty(l) && !_listeners.hasOwnProperty(l)) {
            element[DOMRouter.handlers.add](this.normalizeEvent(l), this.listener);

            _listeners[l] = listeners[l];
        }
    }

    return this;
};

/**
 * generic callback for each event
 * @param event {Event}
 */
DOMRouter.prototype.callback = function (event) {
    var listeners = this.listeners;
    var type = event.type;
    var context = this.context;
    var listener;

    if (listeners.hasOwnProperty(type)) {
        listener = listeners[type];

        if (typeof listener === "string") {
            return context[listener].apply(context, arguments);
        } else if (typeof listener === "function") {
            return listener.apply(context, arguments);
        }
    }

    return true;
};

/**
 * collection of the browser specific event types
 * @static
 */
DOMRouter.handlers = (function () {
    var events = {
        add: "addEventListener",
        remove: "removeEventListener",
        dispatch: "dispatchEvent"
    };

    //IE
    if (document.attachEvent) {
        events.add = "attachEvent";
        events.remove = "detachEvent";
        events.dispatch = "fireEvent";
    }

    return events;
}());

/**
 * prefix for browser specific generic event types
 * @static
 */
DOMRouter.eventPrefix = (function () {
    var div = document.createElement("div");
    return (div.addEventListener ? "" : "on");
}());

/**
 * @static
 * for debugging
 * @returns {Console}
 */
DOMRouter.getConsole = function () {
    return (console ? console : { log: function () {} });
};
<|endoftext|>


<commit_before>class MyCourses {
    constructor(uni, term) {
        // TODO: Add saving courses, currently uni and term are redundant
        this.courses = [];
        this.numConvert = {
            0: "All",
            1: "One",
            2: "Two",
            3: "Three",
            4: "Four",
            5: "Five"
        }

        // Type represents how many courses to choose (0 = all, 1 = one of, etc)
        this.setupPills();
    }

    /*
        Sets up the initial group pills and creates the "All of" initial pill
    */
    setupPills() {
        var self = this;

        $("#coursegroups").empty();

        var addGroupbtn = $('
+
');
        addGroupbtn.click(function (event) {
            // Add One of group
            self.addGroup(1);
        });

        $("#coursegroups").append(addGroupbtn);

        this.addGroup(0);
        this.setGroupActive(0);
    }

    /*
        Adds a new course group of the specified type (0 for All, 1 for one, etc..)
    */
    addGroup(type) {
        // make sure we have 4 total groups or less
        if (this.courses.length <= 3) {
            var thisgroup = {"type": type, "courses": {}};
            var id = this.courses.length;
            this.courses[id] = thisgroup;

            this.generatePill(id, type);
        }
    }

    /*
        Generates, binds, and appends the given pill with the speicifed id and type
    */
    generatePill(id, type) {
        var self = this;

        var text = this.numConvert[type] + " of";

        var html = $('
' + text + '

')

        html.find("a:first").click(function(e){
            // If a pill is already selected, open the dropdown
            // If not, set the pill as active

            // check if this group is already active
            var groupid = $(this).parent().attr("groupid");

            // Check if we need to set this as active
            if (groupid != self.activeGroup) {
                // we don't want the dropdown to open for this item
                e.stopPropagation();

                // check if the dropdown for the old active pill is open
                // if so, close it
                var isopen = $('li[groupid="' + self.activeGroup + '"]').hasClass("open");

                if (isopen == true) {
                    // close it
                    $('li[groupid="' + self.activeGroup + '"]').find('.dropdown-menu').dropdown('toggle');
                }

                // set this group as active
                self.setGroupActive(groupid);
            }
        });

        // Populate the dropdown
        html.find('.dropdown-menu').append(this.generatePillDropdown());

        // Bind the dropdown click handler
        html.find('li').click(function (event) {
            // find the group type
            var grouptype = $(this).attr("grouptype");
            // find the group id
            var groupid = $(this).parent().parent().attr("groupid");

            // Change the group type
            self.changeGroupType(groupid, grouptype);
        });

        $("#addGroupbtn").before(html);
    }

    /*
        Changes the type of a group type and updates the element
    */
    changeGroupType(id, type) {
        this.courses[id]["type"] = type;

        // Change the HTML
        $('li[groupid="' + id + '"]').find("a:first").html(this.numConvert[type] + ' of');
    }

    /*
        Sets the specified group to active
    */
    setGroupActive(id) {
        // remove old active class
        if (this.activeGroup != undefined) {
            $('li[groupid="' + this.activeGroup + '"]').removeClass("active");
        }

        this.activeGroup = id;
        $('li[groupid="' + id + '"]').addClass("active");

        // now display all the courses in the group
        this.displayGroup(this.activeGroup);
    }

    /*
        Populates the courses in the specified group
    */
    displayGroup(group) {
        var self = this;

        // empty out any current courses
        $("#courseList").empty();

        for (var course in self.courses[self.activeGroup]["courses"]) {
            var course = self.courses[self.activeGroup]["courses"][course];

            self.displayCourse(course["obj"], course["obj"]["path"]);
        }
    }

    /*
        Generates the dropdown HTML for a group pill
    */
    generatePillDropdown() {
        var html = '';

        for (var x in this.numConvert) {
            html += '
' + this.numConvert[x] + ' of
';
        }

        return html;
    }

    /*
        Expands the type name (LEC = Lecture, TUT = Tutorial)
    */
    typeExpand(type) {
        var map = {
            "LEC": "Lecture",
            "TUT": "Tutorial",
            "LAB": "Lab"
        }

        if (map[type] != undefined) {
            return map[type];
        }
        else {
            return type;
        }
    }

    /*
        Deletes the given course in any group except the passed in one
    */
    deleteCourseFromNonSafe(delcourse, safegroup) {
        // iterate the groups
        for (var group in this.courses) {
            if (group != safegroup) {
                // we can delete in this group
                for (var course in this.courses[group]["courses"]) {
                    if (course == delcourse) {
                        delete this.courses[group]["courses"][course];
                    }
                }
            }
        }
    }

    /*
        Adds the specified course to the current active group and populates the HTML
    */
    addCourse(course, path, classid) {
        var self = this;

        // We want a separate copy of the obj to work on
        course = jQuery.extend({}, course);

        // add the path to the obj
        course["path"] = path;

        var subject = path.split("\\");

        var coursenum = subject[subject.length-1] // 203
        var subject = subject[subject.length-2]; // CPSC

        var coursecode = subject + " " + coursenum; // CPSC 203

        // Add the key if it isn't there
        if (self.courses[self.activeGroup]["courses"][coursecode] == undefined) {
            self.courses[self.activeGroup]["courses"][coursecode] = {};
            self.courses[self.activeGroup]["courses"][coursecode]["types"] = {};

            // add the possible types
            for (var classv in course["classes"]) {
                if (course["classes"][classv]["type"] != undefined) {
                    var thistype = course["classes"][classv]["type"];
                    self.courses[self.activeGroup]["courses"][coursecode]["types"][thistype] = true;
                }
            }

            // check to see if any other groups have this course, is so, delete the course from them
            self.deleteCourseFromNonSafe(coursecode, self.activeGroup);

            self.displayCourse(course, path);
        }

        var thiscourse = self.courses[self.activeGroup]["courses"][coursecode];

        // set the course obj
        thiscourse["obj"] = course;

        if (classid != undefined) {
            var classtype = true;

            // figure out the class type
            for (var classv in course["classes"]) {
                if (course["classes"][classv]["id"] == classid) {
                    classtype = course["classes"][classv]["type"];
                    break;
                }
            }

            thiscourse["types"][classtype] = classid;
        }
    }

    /*
        Appends the given course to the current courselist HTML
    */
    displayCourse(course, path, classid) {
        var self = this;

        var html = "";
        if (classid == undefined) {
            html = $(this.generateCourseHTML(course, path));

            html.find("label").click(function (event) {
                event.stopPropagation();
                self.bindButton(this, "course");
            });
        }

        $("#courseList").prepend(html);
    }

    /*
        Binds an accordion click
    */
    bindButton(button, type) {
        var self = this;

        // Onclick handler

        // do we need to close the element?
        if ($(button).attr("accordopen") == "true") {
            // Close the element
            $(button).attr("accordopen", "false");

            $(button).parent().find("ul").slideUp(function () {
                $(this).empty();
            });

        }
        else {

            // Open accordion
            var thispath = $(button).attr("path");
            $(button).attr("accordopen", "true");

            var element = $(button).parent().find("ul");

            // Populate depending on type
            if (type == "course") {
                // Element to populate
                self.displayCourseDropDown(element, thispath);
            }
        }
    }

    /*
        Generates the dropdown when clicking on a course in MyCourses
    */
    displayCourseDropDown(element, coursecode) {
        var self = this;

        element.slideUp(function () {

            var thiscourse = self.courses[self.activeGroup]["courses"][coursecode];

            // iterate through each class type
            for (var type in thiscourse["types"]) {
                var thistype = thiscourse["types"][type];
                if (thistype == true) {
                    // They don't have a specific selection, we'll have to generate it
                    var html = '
' + self.typeExpand(type) + '
';
                    element.append(html);
                }
                else if (thistype != false) {
                    // this is a specific class

                    // find the obj of the class
                    var data = {"classes": []};

                    for (var classv in thiscourse["obj"]["classes"]) {
                        var thisclass = thiscourse["obj"]["classes"][classv];
                        if (thisclass["id"] == thistype) {
                            // we found the obj for this class
                            data["classes"].push(thisclass);
                            break;
                        }
                    }

                    if (data["classes"].length > 0) {
                        // generate the table
                        var html = window.classList.generateClasses(data, element, false, false);
                        // edit the css
                        html.css("padding-left", "50px");
                        html.css("padding-right", "40px");
                    }
                }
            }

            element.slideDown();
        });
    }

    /*
        Generates the course HTML
    */
    generateCourseHTML(course, path) {
        var subject = path.split("\\");
        var coursenum = subject[subject.length-1]
        var subject = subject[subject.length-2];

        var title = subject + " " + coursenum;

        if (course["description"] != undefined && course["description"]["name"] != undefined) {
            title += " - " + course["description"]["name"];
        }

        return this.generateAccordionHTML(title, subject + " " + coursenum);
    }

    /*
        Generates the course remove button HTML
    */
    generateRemoveButton() {
        return '<button class="btn btn-default">×</button>';
    }

    /*
        Generates the general accordian structure HTML given a value
    */
    generateAccordionHTML(value, path) {
        return '
' + value + '

';
    }
}<commit_msg>If the accordion contents change, update it<commit_after>class MyCourses {
    constructor(uni, term) {
        // TODO: Add saving courses, currently uni and term are redundant
        this.courses = [];
        this.numConvert = {
            0: "All",
            1: "One",
            2: "Two",
            3: "Three",
            4: "Four",
            5: "Five"
        }

        // Type represents how many courses to choose (0 = all, 1 = one of, etc)
        this.setupPills();
    }

    /*
        Sets up the initial group pills and creates the "All of" initial pill
    */
    setupPills() {
        var self = this;

        $("#coursegroups").empty();

        var addGroupbtn = $('
+
');
        addGroupbtn.click(function (event) {
            // Add One of group
            self.addGroup(1);
        });

        $("#coursegroups").append(addGroupbtn);

        this.addGroup(0);
        this.setGroupActive(0);
    }

    /*
        Adds a new course group of the specified type (0 for All, 1 for one, etc..)
    */
    addGroup(type) {
        // make sure we have 4 total groups or less
        if (this.courses.length <= 3) {
            var thisgroup = {"type": type, "courses": {}};
            var id = this.courses.length;
            this.courses[id] = thisgroup;

            this.generatePill(id, type);
        }
    }

    /*
        Generates, binds, and appends the given pill with the speicifed id and type
    */
    generatePill(id, type) {
        var self = this;

        var text = this.numConvert[type] + " of";

        var html = $('
' + text + '

')

        html.find("a:first").click(function(e){
            // If a pill is already selected, open the dropdown
            // If not, set the pill as active

            // check if this group is already active
            var groupid = $(this).parent().attr("groupid");

            // Check if we need to set this as active
            if (groupid != self.activeGroup) {
                // we don't want the dropdown to open for this item
                e.stopPropagation();

                // check if the dropdown for the old active pill is open
                // if so, close it
                var isopen = $('li[groupid="' + self.activeGroup + '"]').hasClass("open");

                if (isopen == true) {
                    // close it
                    $('li[groupid="' + self.activeGroup + '"]').find('.dropdown-menu').dropdown('toggle');
                }

                // set this group as active
                self.setGroupActive(groupid);
            }
        });

        // Populate the dropdown
        html.find('.dropdown-menu').append(this.generatePillDropdown());

        // Bind the dropdown click handler
        html.find('li').click(function (event) {
            // find the group type
            var grouptype = $(this).attr("grouptype");
            // find the group id
            var groupid = $(this).parent().parent().attr("groupid");

            // Change the group type
            self.changeGroupType(groupid, grouptype);
        });

        $("#addGroupbtn").before(html);
    }

    /*
        Changes the type of a group type and updates the element
    */
    changeGroupType(id, type) {
        this.courses[id]["type"] = type;

        // Change the HTML
        $('li[groupid="' + id + '"]').find("a:first").html(this.numConvert[type] + ' of');
    }

    /*
        Sets the specified group to active
    */
    setGroupActive(id) {
        // remove old active class
        if (this.activeGroup != undefined) {
            $('li[groupid="' + this.activeGroup + '"]').removeClass("active");
        }

        this.activeGroup = id;
        $('li[groupid="' + id + '"]').addClass("active");

        // now display all the courses in the group
        this.displayGroup(this.activeGroup);
    }

    /*
        Populates the courses in the specified group
    */
    displayGroup(group) {
        var self = this;

        // empty out any current courses
        $("#courseList").empty();

        for (var course in self.courses[self.activeGroup]["courses"]) {
            var course = self.courses[self.activeGroup]["courses"][course];

            self.displayCourse(course["obj"], course["obj"]["path"]);
        }
    }

    /*
        Generates the dropdown HTML for a group pill
    */
    generatePillDropdown() {
        var html = '';

        for (var x in this.numConvert) {
            html += '
' + this.numConvert[x] + ' of
';
        }

        return html;
    }

    /*
        Expands the type name (LEC = Lecture, TUT = Tutorial)
    */
    typeExpand(type) {
        var map = {
            "LEC": "Lecture",
            "TUT": "Tutorial",
            "LAB": "Lab"
        }

        if (map[type] != undefined) {
            return map[type];
        }
        else {
            return type;
        }
    }

    /*
        Deletes the given course in any group except the passed in one
    */
    deleteCourseFromNonSafe(delcourse, safegroup) {
        // iterate the groups
        for (var group in this.courses) {
            if (group != safegroup) {
                // we can delete in this group
                for (var course in this.courses[group]["courses"]) {
                    if (course == delcourse) {
                        delete this.courses[group]["courses"][course];
                    }
                }
            }
        }
    }

    /*
        Adds the specified course to the current active group and populates the HTML
    */
    addCourse(course, path, classid) {
        var self = this;

        // We want a separate copy of the obj to work on
        course = jQuery.extend({}, course);

        // add the path to the obj
        course["path"] = path;

        var subject = path.split("\\");

        var coursenum = subject[subject.length-1] // 203
        var subject = subject[subject.length-2]; // CPSC

        var coursecode = subject + " " + coursenum; // CPSC 203

        // Add the key if it isn't there
        if (self.courses[self.activeGroup]["courses"][coursecode] == undefined) {
            self.courses[self.activeGroup]["courses"][coursecode] = {};
            self.courses[self.activeGroup]["courses"][coursecode]["types"] = {};

            // add the possible types
            for (var classv in course["classes"]) {
                if (course["classes"][classv]["type"] != undefined) {
                    var thistype = course["classes"][classv]["type"];
                    self.courses[self.activeGroup]["courses"][coursecode]["types"][thistype] = true;
                }
            }

            // check to see if any other groups have this course, is so, delete the course from them
            self.deleteCourseFromNonSafe(coursecode, self.activeGroup);

            self.displayCourse(course, path);
        }

        var thiscourse = self.courses[self.activeGroup]["courses"][coursecode];

        // set the course obj
        thiscourse["obj"] = course;

        if (classid != undefined) {
            var classtype = true;

            // figure out the class type
            for (var classv in course["classes"]) {
                if (course["classes"][classv]["id"] == classid) {
                    classtype = course["classes"][classv]["type"];
                    break;
                }
            }

            thiscourse["types"][classtype] = classid;

            self.updateAccordion(coursecode);
        }
    }

    /*
        Updates the data in the given open accordion
    */
    updateAccordion(course) {
        var self = this;

        // get the label
        var label = $('label[path="' + course + '"]');

        // Check if its open
        if (label.attr("accordopen") == "true") {
            // update it
            label.attr("accordopen", "false");
            label.parent().find("ul:first").slideUp(function () {
                $(this).empty();
                self.bindButton(label, "course");
            });
        }
    }

    /*
        Appends the given course to the current courselist HTML
    */
    displayCourse(course, path, classid) {
        var self = this;

        var html = "";
        if (classid == undefined) {
            html = $(this.generateCourseHTML(course, path));

            html.find("label").click(function (event) {
                event.stopPropagation();
                self.bindButton(this, "course");
            });
        }

        $("#courseList").prepend(html);
    }

    /*
        Binds an accordion click
    */
    bindButton(button, type) {
        var self = this;

        // Onclick handler

        // do we need to close the element?
        if ($(button).attr("accordopen") == "true") {
            // Close the element
            $(button).attr("accordopen", "false");

            $(button).parent().find("ul").slideUp(function () {
                $(this).empty();
            });

        }
        else {

            // Open accordion
            var thispath = $(button).attr("path");
            $(button).attr("accordopen", "true");

            var element = $(button).parent().find("ul");

            // Populate depending on type
            if (type == "course") {
                // Element to populate
                self.displayCourseDropDown(element, thispath);
            }
        }
    }

    /*
        Generates the dropdown when clicking on a course in MyCourses
    */
    displayCourseDropDown(element, coursecode) {
        var self = this;

        element.slideUp(function () {

            var thiscourse = self.courses[self.activeGroup]["courses"][coursecode];

            // iterate through each class type
            for (var type in thiscourse["types"]) {
                var thistype = thiscourse["types"][type];
                if (thistype == true) {
                    // They don't have a specific selection, we'll have to generate it
                    var html = '
' + self.typeExpand(type) + '
';
                    element.append(html);
                }
                else if (thistype != false) {
                    // this is a specific class

                    // find the obj of the class
                    var data = {"classes": []};

                    for (var classv in thiscourse["obj"]["classes"]) {
                        var thisclass = thiscourse["obj"]["classes"][classv];
                        if (thisclass["id"] == thistype) {
                            // we found the obj for this class
                            data["classes"].push(thisclass);
                            break;
                        }
                    }

                    if (data["classes"].length > 0) {
                        // generate the table
                        var html = window.classList.generateClasses(data, element, false, false);
                        // edit the css
                        html.css("padding-left", "50px");
                        html.css("padding-right", "40px");
                    }
                }
            }

            element.slideDown();
        });
    }

    /*
        Generates the course HTML
    */
    generateCourseHTML(course, path) {
        var subject = path.split("\\");
        var coursenum = subject[subject.length-1]
        var subject = subject[subject.length-2];

        var title = subject + " " + coursenum;

        if (course["description"] != undefined && course["description"]["name"] != undefined) {
            title += " - " + course["description"]["name"];
        }

        return this.generateAccordionHTML(title, subject + " " + coursenum);
    }

    /*
        Generates the course remove button HTML
    */
    generateRemoveButton() {
        return '<button class="btn btn-default">×</button>';
    }

    /*
        Generates the general accordian structure HTML given a value
    */
    generateAccordionHTML(value, path) {
        return '
' + value + '

';
    }
}<|endoftext|>