<commit_before>angular.module('npact')

  .controller('npactGraphContainerCtrl', function($scope, $element, $window, $log, $timeout,
                                           npactConstants, Utils, GraphConfig, Evt,
                                           GraphingCalculator) {
    'use strict';

    var getWidth = function() {
      return $element.width() - 15; //from style.css `.graph`
    };

    //The mouse event responders
    var onPan = function(offset) {
          GraphConfig.offset += Math.round(offset);
          $scope.$apply();
        },
        onZoom = function(opts) {
          $log.log('Zoom event:', opts);
          var zoomOpts = angular.extend({}, GraphConfig, opts);
          //updates `offset`, and `basesPerGraph`
          angular.extend(GraphConfig, GraphingCalculator.zoom(zoomOpts));
          $scope.$apply();
        };

    //The baseOpts are the graph options that are the same for every graph
    var baseOpts = { width: getWidth(), onPan: onPan, onZoom: onZoom };
    this.graphOptions = function(idx) {
      // This function builds the specific options for a graph, the
      // options object is lazily generated when needed
      var start = $scope.graphSpecs[idx];
      var opts = { startBase: start,
                   endBase: start + GraphConfig.basesPerGraph};
      opts = angular.extend(opts, baseOpts);
      return opts;
    };

    var repartition = function() {
      if(GraphConfig.startBase === undefined ||
         GraphConfig.endBase === undefined ||
         GraphConfig.basesPerGraph === undefined) { return; }
      $scope.graphSpecs = GraphingCalculator.partition(GraphConfig);
      $log.log('Partitioned into', $scope.graphSpecs.length, 'rows.');
      updateVisibility();
      $timeout(rebuild);
    },
        draw = function() { $scope.$broadcast(Evt.DRAW); },
        redraw = function() {
          if (!baseOpts.axisTitle) return;  //too early to do anything
          $scope.$broadcast(Evt.REDRAW);
        },
        rebuild = function() {
          if (!baseOpts.axisTitle) return;  //too early to do anything
          $scope.$broadcast(Evt.REBUILD);
        };

    // watch the environment for changes we care about
    $scope.$watchCollection(function() {
      return [ GraphConfig.length, GraphConfig.basesPerGraph,
               GraphConfig.offset, GraphConfig.startBase, GraphConfig.endBase];
    }, repartition);

    $scope.$watch(GraphConfig.profileTitle, function(title) {
      //A profileTitle change indicates different nucleotides: rebuild
      baseOpts.axisTitle = title;
      rebuild();
    });

    $scope.$watch(GraphConfig.activeTracks, function(val) {
      //Find headers and headerY
      angular.extend(baseOpts, GraphingCalculator.trackSizeCalc(val));
      baseOpts.m = GraphingCalculator.chart(baseOpts);
      updateRowHeight(baseOpts.m.height);
      redraw();
    }, true);

    $scope.$watch(
      function() { return GraphConfig.colorBlindFriendly; },
      function(val) {
        baseOpts.colors = val ?
          npactConstants.colorBlindLineColors : npactConstants.lineColors;
        redraw();
    });

    /***  Scrolling and Graph Visibility management ***/
    var $win = angular.element($window),
        winHeight = $win.height(),
        slack = 50, // how many pixels outside of viewport to render
        topOffset = $element.offset().top,
        topIdx = 0, bottomIdx = 0,
        graphBoxHeight = 0,
        updateRowHeight = function(height) {
          $scope.graphHeight = height;
          //add padding and border from style.css `.graph`
          graphBoxHeight = height + 10 + 1;
          updateVisibility();
        },
        updateVisibility = function() {
          if(!baseOpts.m) return;
          var scrollDist = $window.scrollY - topOffset - slack;
          topIdx = Math.floor(scrollDist / graphBoxHeight);
          bottomIdx = topIdx + Math.ceil((winHeight) / graphBoxHeight);
        },
        onScroll = function() {
          updateVisibility();
          draw();
        },
        onResize = function() {
          winHeight = $win.height();
          if($element.width() !== baseOpts.width) {
            topOffset = $element.offset().top;
            baseOpts.width = getWidth();
            updateVisibility();
            redraw();
          }
          else {
            //If the width didn't change then its the same as scrolling
            onScroll();
          }
        };

    this.visible = function(idx) {
      return idx >= topIdx && idx <= bottomIdx;
    };
    $win.on('resize', onResize);
    $win.on('scroll', onScroll);
    $scope.$on('$destroy', function() {
      $win.off('resize', onResize);
      $win.off('scroll', onScroll);
    });
  })
  .directive('npactGraphContainer', function(STATIC_BASE_URL) {
    return {
      restrict: 'A',
      scope: {},
      templateUrl: STATIC_BASE_URL + 'js/graphs/graph-container.html',
      controller: 'npactGraphContainerCtrl as ctrl'
    };
  })

  .directive('npactGraph', function (Grapher, Evt, GraphingCalculator, $log, $timeout) {
    'use strict';
    return {
      restrict: 'A',
      require: '^npactGraphContainer',
      link: function($scope, $element, $attrs, ctrl) {
        var g = null,
            visible = ctrl.visible,
            idx = $attrs.idx,
            el = $element[0],
            // redraw gets set for all graphs once (e.g. a new track
            // triggers broadcasts redraw), but only gets cleared as
            // the currently visible ones are drawn
            redraw = false,
            draw = function() {
              if(!redraw || !visible(idx)) { return; }
              var opts = ctrl.graphOptions(idx);
              //However long it actually takes to draw, we have the
              //latest options as of this point
              redraw = false;
              (g || (g = new Grapher(el, opts)))
                .redraw(opts)
                .catch(function() {
                  //something went wrong, we will still need to redraw this
                  redraw = true;
                })
              ;
            },
            schedule = function() {
              if(!redraw || !visible(idx)) { return; }
              $timeout(draw, 0, false);
            },
            discard = function() {
              if(g) { g.destroy(); g = null; }
            };
        $scope.$on(Evt.DRAW, schedule);
        $scope.$on(Evt.REDRAW, function() { redraw = true; schedule();});
        $scope.$on(Evt.REBUILD, function() { discard(); redraw = true; schedule(); });
        $scope.$on('$destroy', discard);
      }
    };
  })
  .directive('npactExtract', function(STATIC_BASE_URL) {
    return {
      restrict: 'A',
      scope: { extract: '=npactExtract'},
      templateUrl: STATIC_BASE_URL + 'js/graphs/extract.html'
    };
  })
;
<commit_msg>GraphContainer: Clean up var names and function style a bit<commit_after>angular.module('npact')
  .controller('npactGraphContainerCtrl', function($scope, $element, $window, $log, $timeout,
                                           npactConstants, Utils, GraphConfig, Evt,
                                           GraphingCalculator) {
    'use strict';

    var getWidth = function() {
      return $element.width() - 15; //from style.css `.graph`
    };

    //The mouse event responders
    var onPan = function(offset) {
          GraphConfig.offset += Math.round(offset);
          $scope.$apply();
        },
        onZoom = function(opts) {
          $log.log('Zoom event:', opts);
          var zoomOpts = angular.extend({}, GraphConfig, opts);
          //updates `offset`, and `basesPerGraph`
          angular.extend(GraphConfig, GraphingCalculator.zoom(zoomOpts));
          $scope.$apply();
        };

    //The baseOpts are the graph options that are the same for every graph
    var baseOpts = { width: getWidth(), onPan: onPan, onZoom: onZoom };
    this.graphOptions = function(idx) {
      // This function builds the specific options for a graph; as
      // many graph rows will never be drawn this only generates the
      // object for a row when needed.
      var start = $scope.graphSpecs[idx];
      var opts = { startBase: start,
                   endBase: start + GraphConfig.basesPerGraph};
      opts = angular.extend(opts, baseOpts);
      return opts;
    };

    var draw = function() { $scope.$broadcast(Evt.DRAW); },
        redraw = function() {
          if (!baseOpts.axisTitle || !baseOpts.m) return;  //too early to do anything
          $scope.$broadcast(Evt.REDRAW);
        },
        rebuild = function() {
          if (!baseOpts.axisTitle || !baseOpts.m) return;  //too early to do anything
          $scope.$broadcast(Evt.REBUILD);
        };

    /*** Watch the config for changes we care about ***/
    $scope.$watchCollection(
      function() {
        return [GraphConfig.length, GraphConfig.basesPerGraph,
                GraphConfig.offset, GraphConfig.startBase, GraphConfig.endBase];
      },
      function() {
        // basic row geometry changed, repartition and rebuild
        if(GraphConfig.startBase === undefined ||
           GraphConfig.endBase === undefined ||
           GraphConfig.basesPerGraph === undefined) { return; }
        $scope.graphSpecs = GraphingCalculator.partition(GraphConfig);
        $log.log('Partitioned into', $scope.graphSpecs.length, 'rows.');
        updateVisibility(); //number of rows might have changed.
        $timeout(rebuild);
      });

    $scope.$watch(GraphConfig.profileTitle, function(title) {
      //A profileTitle change indicates different nucleotides: rebuild
      baseOpts.axisTitle = title;
      rebuild();
    });

    $scope.$watch(GraphConfig.activeTracks, function(val) {
      //Find headers and headerY
      angular.extend(baseOpts, GraphingCalculator.trackSizeCalc(val));
      baseOpts.m = GraphingCalculator.chart(baseOpts);
      updateRowHeight(baseOpts.m.height);
      redraw();
    }, true);

    $scope.$watch(
      function() { return GraphConfig.colorBlindFriendly; },
      function(val) {
        baseOpts.colors = val ?
          npactConstants.colorBlindLineColors : npactConstants.lineColors;
        redraw();
    });

    /***  Scrolling and Graph Visibility management ***/
    var $win = angular.element($window),
        winHeight = $win.height(),
        slack = 50, // how many pixels outside of viewport to render
        topOffset = $element.offset().top,
        topIdx = 0, bottomIdx = 0,
        graphRowHeight = 0,
        updateRowHeight = function(height) {
          $scope.graphHeight = height;
          //add padding and border from style.css `.graph`
          graphRowHeight = height + 10 + 1;
          updateVisibility();
        },
        updateVisibility = function() {
          if(!baseOpts.m) return;
          var scrollDist = $window.scrollY - topOffset - slack;
          topIdx = Math.floor(scrollDist / graphRowHeight);
          bottomIdx = topIdx + Math.ceil(winHeight / graphRowHeight);
        },
        onScroll = function() {
          updateVisibility();
          draw();
        },
        onResize = function() {
          winHeight = $win.height();
          if(getWidth() !== baseOpts.width) {
            topOffset = $element.offset().top;
            baseOpts.width = getWidth();
            updateVisibility();
            redraw();
          }
          else {
            //If the width didn't change then its the same as scrolling
            onScroll();
          }
        };

    this.visible = function(idx) { return idx >= topIdx && idx <= bottomIdx; };
    $win.on('resize', onResize);
    $win.on('scroll', onScroll);
    $scope.$on('$destroy', function() {
      $win.off('resize', onResize);
      $win.off('scroll', onScroll);
    });
  })
  .directive('npactGraphContainer', function(STATIC_BASE_URL) {
    return {
      restrict: 'A',
      scope: {},
      templateUrl: STATIC_BASE_URL + 'js/graphs/graph-container.html',
      controller: 'npactGraphContainerCtrl as ctrl'
    };
  })

  .directive('npactGraph', function (Grapher, Evt, GraphingCalculator, $log, $timeout) {
    'use strict';
    return {
      restrict: 'A',
      require: '^npactGraphContainer',
      link: function($scope, $element, $attrs, ctrl) {
        var g = null,
            visible = ctrl.visible,
            idx = $attrs.idx,
            el = $element[0],
            // redraw gets set for all graphs once (e.g. a new track
            // triggers broadcasts redraw), but only gets cleared as
            // the currently visible ones are drawn
            redraw = false,
            draw = function() {
              if(!redraw || !visible(idx)) { return; }
              var opts = ctrl.graphOptions(idx);
              //However long it actually takes to draw, we have the
              //latest options as of this point
              redraw = false;
              (g || (g = new Grapher(el, opts)))
                .redraw(opts)
                .catch(function() {
                  //something went wrong, we will still need to redraw this
                  redraw = true;
                })
              ;
            },
            schedule = function() {
              if(!redraw || !visible(idx)) { return; }
              $timeout(draw, 0, false);
            },
            discard = function() {
              if(g) { g.destroy(); g = null; }
            };
        $scope.$on(Evt.DRAW, schedule);
        $scope.$on(Evt.REDRAW, function() { redraw = true; schedule();});
        $scope.$on(Evt.REBUILD, function() { discard(); redraw = true; schedule(); });
        $scope.$on('$destroy', discard);
      }
    };
  })
  .directive('npactExtract', function(STATIC_BASE_URL) {
    return {
      restrict: 'A',
      scope: { extract: '=npactExtract'},
      templateUrl: STATIC_BASE_URL + 'js/graphs/extract.html'
    };
  })
;
<|endoftext|>


<commit_before>class Node {
  constructor(data) {
    this._isLeaf = false;
    this._children = {};
    this._data = data;
  }

  get isLeaf() {
    return this._isLeaf;
  }

  set isLeaf(val) {
    this._isLeaf = val;
  }

  get children() {
    return this._children;
  }

  get data() {
    return this._data;
  }

  set data(val) {
    this._data = val;
  }
}

class Trie {
  constructor() {
    this._root = new Node('');
  }
}

module.exports = Trie;
<commit_msg>Trie: Constructor updated<commit_after>class Node {
  constructor(data) {
    this._isLeaf = false;
    this._children = {};
    this._data = data;
  }

  get isLeaf() {
    return this._isLeaf;
  }

  set isLeaf(val) {
    this._isLeaf = val;
  }

  get children() {
    return this._children;
  }

  get data() {
    return this._data;
  }

  set data(val) {
    this._data = val;
  }
}

class Trie {
  constructor() {
    this._root = new Node();
    this._size = 0;
  }
  }
}

module.exports = Trie;
<|endoftext|>


<commit_before>import { Window, GridLayout, FillLayout, Ellipse, Text,
         VerticalLayout, HorizontalLayout, Morph } from "../index.js";
import { Color, LinearGradient, pt } from "lively.graphics";
import { obj, num } from "lively.lang";

export class ColorPicker extends Window {

  constructor(props) {
    this.color = props.color || Color.blue;
    super({
      ...props,
      title: "Color Picker",
      targetMorph: this.colorPalette()
    });
    this.update();
  }

  get pickerPosition() {
    // translate the hsv of color to a position
    const [_, s, b] = this.color.toHSB();
    return pt(this.getSubmorphNamed("hue").width * s,
              this.getSubmorphNamed("hue").height * (1 - b))
  }

  set pickerPosition({x: light, y: dark}) {
    // translate the pos to a new hsv value
    var [h, s, b] = this.color.toHSB(),
        {width, height} = this.getSubmorphNamed("hue"),
        s = Math.max(0, Math.min(light / width, 1)),
        b = Math.max(0, Math.min(1 - (dark / height), 1));
    this.color = Color.hsb(h, s, b);
    this.update();
  }

  get scalePosition() {
    var [h, _, _] = this.color.toHSB();
    return pt(this.getSubmorphNamed("scale").width / 2, this.getSubmorphNamed("hueGradient").height * (h / 360));
  }

  set scalePosition(pos) {
    console.log(pos.y / this.getSubmorphNamed("hueGradient").height)
    const [_, s, b] = this.color.toHSB(),
          h = Math.max(0, Math.min((pos.y / this.getSubmorphNamed("hueGradient").height) * 360, 359));
    this.color = Color.hsb(h, s, b);
    this.update();
  }

  update() {
    this.getSubmorphNamed("field").update(this);
    this.getSubmorphNamed("colorViewer").update(this);
    this.getSubmorphNamed("picker").update(this);
    this.getSubmorphNamed("slider").update(this);
    //this.getSubmorphNamed("harmonies").update(this);
    this.getSubmorphNamed("hashViewer").update(this);
    this.getSubmorphNamed("hsbViewer").update(this);
    this.getSubmorphNamed("rgbViewer").update(this);
  }

  colorPalette() {
    const colorPalette = this.getSubmorphNamed("colorPalette") || new Morph({
      name: "colorPalette",
      fill: Color.transparent,
      layout: new GridLayout({grid: [["field", "scale", "details"]
                                     //["harmonies", "harmonies", "harmonies"]
                                     ]}),
      submorphs: [this.fieldPicker(), this.scalePicker(), this.colorDetails()]
    })
    colorPalette.layout.col(1).fixed = 55;
    colorPalette.layout.col(2).fixed = 100;
    return colorPalette;
  }

  fieldPicker() {
    return this.getSubmorphNamed("field") || new Morph({
      layout: new FillLayout({morphs: ["hue", "shade", "light"], spacing: 9}),
      name: "field",
      fill: Color.transparent,
      update(colorPicker) {
        const [h, s, b] = colorPicker.color.toHSB();
        this.getSubmorphNamed("hue").fill = Color.hsb(h, 1, 1)
      },
      submorphs: [{
        name: "hue",
        fill: this.color
      },{
        name: "shade",
        fill: new LinearGradient([{color: Color.white, offset: "0%"},
                                  {color: Color.transparent, offset: "100%"}],
                                  "eastwest")
      },{
        name: "light",
        fill: new LinearGradient([{color: Color.black, offset: "0%"},
                                  {color: Color.transparent, offset: "100%"}],
                                  "southnorth"),
        onMouseDown: (evt) => {
          this.pickerPosition = evt.positionIn(this.getSubmorphNamed("light"));
        },
        submorphs: [{
          name: "picker",
          type: "ellipse",
          draggable: false,
          fill: Color.transparent,
          borderColor: Color.black,
          borderWidth: 3,
          extent: pt(18,18),
          update(colorPicker) {
            this.center = colorPicker.pickerPosition;
          },
          submorphs: [{
            type: "ellipse",
            fill: Color.transparent,
            borderColor: Color.white,
            onDrag: (evt) => {
              this.pickerPosition = this.pickerPosition.addPt(evt.state.dragDelta)
            },
            borderWidth: 3,
            center: pt(8,8),
            extent: pt(12,12)
          }]
      }]
     }]
    });
  }

  scalePicker() {
    return this.getSubmorphNamed("scale") || new Morph({
      layout: new FillLayout({morphs: ["hueGradient"], spacing: 9}),
      name: "scale",
      fill: Color.transparent,
      submorphs: [{
        name: "hueGradient",
        fill: new LinearGradient([
          {color: Color.rgb(255,0,0), offset: "0%"},
          {color: Color.rgb(255,255,0), offset: "17%"},
          {color: Color.limeGreen, offset: "33%"},
          {color: Color.cyan, offset: "50%"},
          {color: Color.blue, offset: "66%"},
          {color: Color.magenta, offset: "83%"}],
         "northsouth"),
        onMouseDown: (evt) => {
          this.scalePosition = pt(0, evt.positionIn(this.getSubmorphNamed("hueGradient")).y);
        }
      },{
        name: "slider",
        height: 10,
        width: 50,
        borderRadius: 3,
        borderColor: Color.black,
        fill: Color.transparent,
        borderWidth: 2,
        update(colorPicker) {
          this.center = colorPicker.scalePosition.addPt(pt(0,10));
        },
        onDrag: (evt) => {
          this.scalePosition = this.scalePosition.addPt(pt(0, evt.state.dragDelta.y));
        }
      }]
    });
  }

  keyValue({name, key, value, update}) {
    return new Morph({
      update,
      name: name || key,
      fill: Color.transparent,
      layout: new HorizontalLayout({spacing: 5}),
      setValue(value) {
        this.submorphs[1].textString = obj.safeToString(value);
      },
      submorphs: [
        new Text({
          fill: Color.transparent,
          textString: key,
          fontColor: Color.darkgray,
          fontWeight: "bold"}),
        new Text({
          fill: Color.transparent,
          textString: obj.safeToString(value),
          fixedWidth: true})]
    })
  }

  hashViewer() {
    return this.getSubmorphNamed("hashViewer") || this.keyValue({
      name: "hashViewer",
      key: "#",
      update(colorPicker) {
        this.setValue(colorPicker.color.toHexString());
      },
      value: this.color.toHexString()})
  }

  rgbViewer() {
    const [r, g, b] = this.color.toTuple8Bit();
    return this.getSubmorphNamed("rgbViewer") || new Morph({
      name: "rgbViewer",
      layout: new VerticalLayout(),
      fill: Color.transparent,
      update(colorPicker) {
        const [r, g, b] = colorPicker.color.toTuple8Bit(),
              [rv, gv, bv] = this.submorphs;
        rv.setValue(r.toFixed()); gv.setValue(g.toFixed()); bv.setValue(b.toFixed());
      },
      submorphs: [this.keyValue({key: "R", value: r.toFixed()}),
                  this.keyValue({key: "G", value: g.toFixed()}),
                  this.keyValue({key: "B", value: b.toFixed()})]
    })
  }

  hsbViewer() {
    const [h, s, b] = this.color.toHSB();
    return this.getSubmorphNamed("hsbViewer") || new Morph({
      name: "hsbViewer",
      layout: new VerticalLayout(),
      fill: Color.transparent,
      update(colorPicker) {
        const [h, s, b] = colorPicker.color.toHSB(),
              [hm, sm, bm] = this.submorphs;
        hm.setValue(h.toFixed()); sm.setValue(s.toFixed(2)); bm.setValue(b.toFixed(2));
      },
      submorphs: [this.keyValue({key: "H", value: h.toFixed()}),
                  this.keyValue({key: "S", value: s.toFixed(2)}),
                  this.keyValue({key: "B", value: b.toFixed(2)})]
    })
  }

  colorDetails() {
    return this.getSubmorphNamed("details") || new Morph({
      name: "details",
      width: 80,
      fill: Color.transparent,
      layout: new VerticalLayout({spacing: 9}),
      submorphs: [{
        extent: pt(80,40),
        name: "colorViewer",
        fill: this.color,
        update(colorPicker) { this.fill = colorPicker.color }
      },
      this.hashViewer(),
      this.rgbViewer(),
      this.hsbViewer()]
    })
  }

  harmonies() {
    return this.getSubmorphNamed("harmonies") || new Morph({
      name: "harmonies",
      update(colorPicker) {

      }
    })
  }

}<commit_msg>[color picker] store hsb separately<commit_after>import { Window, GridLayout, FillLayout, Ellipse, Text,
         VerticalLayout, HorizontalLayout, Morph } from "../index.js";
import { Color, LinearGradient, pt } from "lively.graphics";
import { obj, num } from "lively.lang";
import { connect } from "lively.bindings";

export class ColorPicker extends Window {

  constructor(props) {
    this.color = props.color || Color.blue;
    super({
      ...props,
      title: "Color Picker",
      targetMorph: this.colorPalette()
    });
    this.update();
    connect(this, "change", this, "update", {updater: ($upd, {prop}) => ["extent"].includes(prop) && $upd()})
  }

  set color(c) {
    const [h, s, b] = c.toHSB();
    this.hue = h;
    this.saturation = s;
    this.brightness = b;
  }

  get color() {
    return Color.hsb(this.hue, this.saturation, this.brightness);
  }

  get pickerPosition() {
    // translate the hsv of color to a position
    const s = this.saturation, b = this.brightness;
    return pt(this.getSubmorphNamed("hue").width * s,
              this.getSubmorphNamed("hue").height * (1 - b))
  }

  set pickerPosition({x: light, y: dark}) {
    // translate the pos to a new hsv value
    var {width, height} = this.getSubmorphNamed("hue");
    this.saturation = Math.max(0, Math.min(light / width, 1));
    this.brightness = Math.max(0, Math.min(1 - (dark / height), 1));
    this.update();
  }

  get scalePosition() {
    return pt(this.getSubmorphNamed("scale").width / 2, this.getSubmorphNamed("hueGradient").height * (this.hue / 360));
  }

  set scalePosition(pos) {
    console.log(pos.y / this.getSubmorphNamed("hueGradient").height)
    this.hue = Math.max(0, Math.min((pos.y / this.getSubmorphNamed("hueGradient").height) * 360, 359));
    this.update();
  }

  update() {
     [this.getSubmorphNamed("field"),
      this.getSubmorphNamed("colorViewer"),
      this.getSubmorphNamed("picker"),
      this.getSubmorphNamed("slider"),
      //this.getSubmorphNamed("harmonies"),
      this.getSubmorphNamed("hashViewer"),
      this.getSubmorphNamed("hsbViewer"),
      this.getSubmorphNamed("rgbViewer")].forEach(p => p && p.update(this));
  }

  colorPalette() {
    const colorPalette = this.getSubmorphNamed("colorPalette") || new Morph({
      name: "colorPalette",
      fill: Color.transparent,
      layout: new GridLayout({grid: [["field", "scale", "details"]
                                     //["harmonies", "harmonies", "harmonies"]
                                     ]}),
      submorphs: [this.fieldPicker(), this.scalePicker(), this.colorDetails()]
    })
    colorPalette.layout.col(1).fixed = 55;
    colorPalette.layout.col(2).fixed = 100;
    return colorPalette;
  }

  fieldPicker() {
    return this.getSubmorphNamed("field") || new Morph({
      layout: new FillLayout({morphs: ["hue", "shade", "light"], spacing: 9}),
      name: "field",
      fill: Color.transparent,
      update(colorPicker) {
        this.getSubmorphNamed("hue").fill = Color.hsb(colorPicker.hue, 1, 1);
      },
      submorphs: [{
        borderRadius: 3,
        name: "hue"
      },{
        borderRadius: 3,
        name: "shade",
        fill: new LinearGradient([{color: Color.white, offset: "0%"},
                                  {color: Color.transparent, offset: "100%"}],
                                  "eastwest")
      },{
        borderRadius: 3,
        name: "light",
        fill: new LinearGradient([{color: Color.black, offset: "0%"},
                                  {color: Color.transparent, offset: "100%"}],
                                  "southnorth"),
        onMouseDown: (evt) => {
          this.pickerPosition = evt.positionIn(this.getSubmorphNamed("light"));
        },
        onDrag: (evt) => {
          this.pickerPosition = this.pickerPosition.addPt(evt.state.dragDelta)
        },
        submorphs: [{
          name: "picker",
          type: "ellipse",
          draggable: false,
          fill: Color.transparent,
          borderColor: Color.black,
          borderWidth: 3,
          extent: pt(18,18),
          update(colorPicker) {
            this.center = colorPicker.pickerPosition;
          },
          submorphs: [{
            type: "ellipse",
            fill: Color.transparent,
            borderColor: Color.white,
            onDrag: (evt) => {
              this.pickerPosition = this.pickerPosition.addPt(evt.state.dragDelta)
            },
            borderWidth: 3,
            center: pt(8,8),
            extent: pt(12,12)
          }]
      }]
     }]
    });
  }

  scalePicker() {
    return this.getSubmorphNamed("scale") || new Morph({
      layout: new FillLayout({morphs: ["hueGradient"], spacing: 9}),
      name: "scale",
      fill: Color.transparent,
      submorphs: [{
        name: "hueGradient",
        borderRadius: 3,
        fill: new LinearGradient([
          {color: Color.rgb(255,0,0), offset: "0%"},
          {color: Color.rgb(255,255,0), offset: "17%"},
          {color: Color.limeGreen, offset: "33%"},
          {color: Color.cyan, offset: "50%"},
          {color: Color.blue, offset: "66%"},
          {color: Color.magenta, offset: "83%"},
          {color: Color.rgb(255,0,0), offset: "100%"}],
         "northsouth"),
        onMouseDown: (evt) => {
          this.scalePosition = pt(0, evt.positionIn(this.getSubmorphNamed("hueGradient")).y);
        },
        onDrag: (evt) => {
          this.scalePosition = this.scalePosition.addPt(pt(0, evt.state.dragDelta.y));
        }
      },{
        name: "slider",
        height: 10,
        width: 50,
        borderRadius: 3,
        nativeCursor: "ns-resize",
        borderColor: Color.black,
        fill: Color.transparent,
        borderWidth: 2,
        update(colorPicker) {
          this.center = colorPicker.scalePosition.addPt(pt(0,10));
        },
        onDrag: (evt) => {
          this.scalePosition = this.scalePosition.addPt(pt(0, evt.state.dragDelta.y));
        }
      }]
    });
  }

  keyValue({name, key, value, update}) {
    return new Morph({
      update,
      name: name || key,
      fill: Color.transparent,
      layout: new HorizontalLayout({spacing: 5}),
      setValue(value) {
        this.submorphs[1].textString = obj.safeToString(value);
      },
      submorphs: [
        new Text({
          fill: Color.transparent,
          textString: key,
          fontColor: Color.darkgray,
          fontWeight: "bold"}),
        new Text({
          fill: Color.transparent,
          textString: obj.safeToString(value),
          fixedWidth: true})]
    })
  }

  hashViewer() {
    return this.getSubmorphNamed("hashViewer") || this.keyValue({
      name: "hashViewer",
      key: "#",
      update(colorPicker) {
        this.setValue(colorPicker.color.toHexString());
      },
      value: this.color.toHexString()})
  }

  rgbViewer() {
    const [r, g, b] = this.color.toTuple8Bit();
    return this.getSubmorphNamed("rgbViewer") || new Morph({
      name: "rgbViewer",
      layout: new VerticalLayout(),
      fill: Color.transparent,
      update(colorPicker) {
        const [r, g, b] = colorPicker.color.toTuple8Bit(),
              [rv, gv, bv] = this.submorphs;
        rv.setValue(r.toFixed()); gv.setValue(g.toFixed()); bv.setValue(b.toFixed());
      },
      submorphs: [this.keyValue({key: "R", value: r.toFixed()}),
                  this.keyValue({key: "G", value: g.toFixed()}),
                  this.keyValue({key: "B", value: b.toFixed()})]
    })
  }

  hsbViewer() {
    const [h, s, b] = this.color.toHSB();
    return this.getSubmorphNamed("hsbViewer") || new Morph({
      name: "hsbViewer",
      layout: new VerticalLayout(),
      fill: Color.transparent,
      update(colorPicker) {
        const [h, s, b] = colorPicker.color.toHSB(),
              [hm, sm, bm] = this.submorphs;
        hm.setValue(h.toFixed()); sm.setValue(s.toFixed(2)); bm.setValue(b.toFixed(2));
      },
      submorphs: [this.keyValue({key: "H", value: h.toFixed()}),
                  this.keyValue({key: "S", value: s.toFixed(2)}),
                  this.keyValue({key: "B", value: b.toFixed(2)})]
    })
  }

  colorDetails() {
    return this.getSubmorphNamed("details") || new Morph({
      name: "details",
      width: 80,
      fill: Color.transparent,
      layout: new VerticalLayout({spacing: 9}),
      submorphs: [{
        type: "ellipse",
        extent: pt(50,50),
        name: "colorViewer",
        fill: this.color,
        update(colorPicker) { this.fill = colorPicker.color }
      },
      this.hashViewer(),
      this.rgbViewer(),
      this.hsbViewer()]
    })
  }

  harmonies() {
    return this.getSubmorphNamed("harmonies") || new Morph({
      name: "harmonies",
      update(colorPicker) {

      }
    })
  }

}<|endoftext|>


<commit_before>import Sequelize from 'sequelize';
import database from '../';

export default database.define('user', {
  id: {
    type: Sequelize.STRING,
    field: 'id',
    primaryKey: true,
    allowNull: false
  },
  authenticationProvider: {
    type: Sequelize.ENUM,
    values: ['github', 'stack_exchange', 'wordpress'],
    field: 'authentication_provider',
    allowNull: false
  },
  firstName: {
    type: Sequelize.STRING,
    field: 'first_name',
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING,
    field: 'last_name',
    allowNull: false
  },
  emailAddress: {
    type: Sequelize.STRING,
    field: 'email_address',
    allowNull: false
  },
  profilePicture: {
    type: Sequelize.STRING,
    field: 'profile_picture',
    allowNull: false
  },
  bio: {
    type: Sequelize.TEXT,
    field: 'bio',
    allowNull: false
  },
  websiteURI: {
    type: Sequelize.STRING,
    field: 'website_uri'
  },
  blogURI: {
    type: Sequelize.STRING,
    field: 'blog_uri'
  },
  blogFeedURI: {
    type: Sequelize.STRING,
    field: 'blog_feed_uri'
  },
  cvURI: {
    type: Sequelize.STRING,
    field: 'cv_uri'
  },
  linkedInURI: {
    type: Sequelize.STRING,
    field: 'linkedin_uri'
  },
  githubUsername: {
    type: Sequelize.STRING,
    field: 'github_username'
  },
  twitterUsername: {
    type: Sequelize.STRING,
    field: 'twitter_username'
  }
});
<commit_msg>Added feedLastModified field to user so we know which date our if modified request should send<commit_after>import Sequelize from 'sequelize';
import database from '../';

export default database.define('user', {
  id: {
    type: Sequelize.STRING,
    field: 'id',
    primaryKey: true,
    allowNull: false
  },
  authenticationProvider: {
    type: Sequelize.ENUM,
    values: ['github', 'stack_exchange', 'wordpress'],
    field: 'authentication_provider',
    allowNull: false
  },
  firstName: {
    type: Sequelize.STRING,
    field: 'first_name',
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING,
    field: 'last_name',
    allowNull: false
  },
  emailAddress: {
    type: Sequelize.STRING,
    field: 'email_address',
    allowNull: false
  },
  profilePicture: {
    type: Sequelize.STRING,
    field: 'profile_picture',
    allowNull: false
  },
  bio: {
    type: Sequelize.TEXT,
    field: 'bio',
    allowNull: false
  },
  websiteURI: {
    type: Sequelize.STRING,
    field: 'website_uri'
  },
  blogURI: {
    type: Sequelize.STRING,
    field: 'blog_uri'
  },
  blogFeedURI: {
    type: Sequelize.STRING,
    field: 'blog_feed_uri'
  },
  cvURI: {
    type: Sequelize.STRING,
    field: 'cv_uri'
  },
  linkedInURI: {
    type: Sequelize.STRING,
    field: 'linkedin_uri'
  },
  githubUsername: {
    type: Sequelize.STRING,
    field: 'github_username'
  },
  twitterUsername: {
    type: Sequelize.STRING,
    field: 'twitter_username'
  },
  feedLastModified: {
    type: Sequelize.DATE,
    field: 'feed_last_modified'
  }
});
<|endoftext|>


<commit_before>'use strict';

var utils = require('lightning-client-utils');
var inherits = require('inherits');
var d3 = require('d3');
var _ = require('lodash');
var validator = require("geojson-validation");
var L = require('leaflet');
var F = require('leaflet.freedraw-browserify');
F(L);

// code adopted from http://kempe.net/blog/2014/06/14/leaflet-pan-zoom-image.html

var ImgDraw = function(selector, data, images, opts) {

    if(!opts) {
        opts = {};
    }

    this.opts = opts

    this.data = this._formatData(data)
    this.images = images
    this.selector = selector;

    this._init();
}

inherits(ImgDraw, require('events').EventEmitter);

ImgDraw.prototype._init = function() {

    var opts = this.opts;
    var data = this.data ? this.data : {};
    var images = this.images;
    var selector = this.selector;
    var self = this;

    this.mid = utils.getUniqueId();
    this.markup = '<link rel="stylesheet" href="//cdn.leafletjs.com/leaflet-0.7.3/leaflet.css"/>

';

    var image = images[0];
    var coords = [];

    this.$el = $(selector).first();
    this.$el.append(this.markup);

    var maxWidth = this.$el.width();

    // create an image so we can get aspect ratio
    this.img = new Image();
    var img = this.img;
    img.src = (window.lightning && window.lightning.host) ? window.lightning.host + image : image;

    img.onload = function() {

        // get image dimensions
        var imw = img.width;
        var imh = img.height;

        // use image dimensions to set css
        var w = maxWidth,
            h = maxWidth * (imh / imw);

        self.$el.find('#image-map-' + self.mid).width(w).height(h);

        //create the map
        if(self.map) {
            self.map.remove();
        }
        self.map = L.map('image-map-' + self.mid, {
            minZoom: 1,
            maxZoom: 8,
            center: [w/2, h/2],
            zoom: 1,
            attributionControl: false,
            zoomControl: false,
            crs: L.CRS.Simple,
        });

        var map = self.map;

        // calculate the edges of the image, in coordinate space
        var southWest = map.unproject([0, h], 1);
        var northEast = map.unproject([w, 0], 1);
        var bounds = new L.LatLngBounds(southWest, northEast);

        // add the image overlay to cover the map
        var overlay = L.imageOverlay(img.src, bounds);
        map.addLayer(overlay)

        // tell leaflet that the map is exactly as big as the image
        map.setMaxBounds(bounds);

        // add free drawing
        var freeDraw = new L.FreeDraw({
          mode: L.FreeDraw.MODES.CREATE | L.FreeDraw.MODES.DELETE | L.FreeDraw.MODES.DELETE,
        });

        // set free drawing options
        freeDraw.options.attemptMerge = false;
        freeDraw.options.setHullAlgorithm('brian3kb/graham_scan_js');
        freeDraw.options.setSmoothFactor(0);

        // add the free drawing layer
        map.addLayer(freeDraw);

        // initialize with any polygons from the data
        if (!_.isEmpty(data)) {

            console.log("we got here")

            var polygons = data.polygons;

            polygons = polygons.map(function (g) {
                var converted = [];
                g.map(function (p) {
                    var newp = new L.point(p[0] / (imw / w), p[1] / (imh / h), false);
                    var newpoint = map.unproject(newp, 1);
                    converted.push(newpoint);
                });
                return converted;
            });

            freeDraw.options.simplifyPolygon = false;
            polygons.forEach(function (g) {
                freeDraw.createPolygon(g, true);
            });
            freeDraw.options.simplifyPolygon = true;

            var COLOR_MODES = ['white', 'bright', 'data-white'];
            var colorIndex = 2;

        } else {

            var COLOR_MODES = ['white', 'bright'];
            var colorIndex = 0;

        }

        d3.select('body').on('keydown', keydown).on('keyup', keyup);

        updateStyles();

        function updateStyles() {

            var c;
            if(COLOR_MODES[colorIndex].indexOf('white') > -1) {
                c = d3.hsl('rgb(255,255,255)');
            } else if (COLOR_MODES[colorIndex].indexOf('bright') > -1) {
                c = d3.hsl('rgb(240,30,110)');
            }

            var isData = (data.color && COLOR_MODES[colorIndex].indexOf('data') > -1);

            d3.select(self.$el[0])
               .selectAll('.image-map g path')
               .style('stroke', function(d, i) {
                if(isData && i < data.color.length-1) {
                    return data.color[i];
                }
                return c;
               })
               .style('fill', function(d, i) {
                var fill;
                if(isData && i < data.color.length-1) {
                    fill = d3.hsl(data.color[i]);
                } else {
                    fill = c;
                }
                fill.l = fill.l * 1.3;
                return fill.toString();
               });

        }

        var mod = function(x, n) {
            return ((x%n)+n)%n;
        };
        function keydown() {
            if (d3.event.altKey) {
                freeDraw.setMode(L.FreeDraw.MODES.EDIT);
            }
            if (d3.event.metaKey | d3.event.shiftKey) {
                freeDraw.setMode(L.FreeDraw.MODES.VIEW);
            }
            if (d3.event.shiftKey & (d3.event.keyCode == 37 | d3.event.keyCode == 39)) {
                d3.event.preventDefault();
                if (d3.event.keyCode == 37) {
                    colorIndex = mod(colorIndex - 1, COLOR_MODES.length);
                }
                if (d3.event.keyCode == 39) {
                    colorIndex = mod(colorIndex + 1, COLOR_MODES.length);
                }
                updateStyles();
            }
        }

        function keyup() {
            freeDraw.setMode(L.FreeDraw.MODES.CREATE | L.FreeDraw.MODES.DELETE)
        }

        self.emit('image:loaded');

        self.$el.unbind().click(function() {

            // extract coordinates from regions
            var n = freeDraw.memory.states.length;
            var coords = freeDraw.memory.states[n-1].map( function(d) {
                var points = [];
                d.forEach(function (p) {
                    var newpoint = map.project(p, 1);
                    newpoint.x *= (imw / w);
                    newpoint.y *= (imh / h);
                    points.push([newpoint.x, newpoint.y]);
                });
                return points;
            });

            utils.updateSettings(self, {
                coords: coords
            }, function(err) {
                console.log('saved user data');
                console.log(coords);
            });
        });

        utils.getSettings(self, function(err, settings) {

            console.log(settings);
            if(!err) {
                coords = settings.coords;
            }

        });

        freeDraw.on('markers', updateStyles);

        self.map = map
        self.bounds = bounds
        self.overlay = overlay

    }

};

module.exports = ImgDraw;

ImgDraw.prototype._formatData = function(data) {

    if (!_.isEmpty(data)) {

        var polygons = []

        if (validator.isFeatureCollection(data)) {
            data.features.forEach(function(d) {
                if (validator.isFeature(d)) {
                    if (validator.isPolygon(d.geometry)) {
                        polygons.push(d.geometry.coordinates[0])
                    }
                }
            })
        } else if (data.coordinates) {
            polygons = data.coordinates
        } else {
            throw "Input data not understood"
        }

        var retColor = utils.getColorFromData(data);
        if (retColor.length == 0) {
            retColor = utils.getColors(polygons.length + 1)
        } else if (retColor.length == 1) {
            retColor = _.range(polygons.length + 1).map(function () { return retColor })
        }

        data.color = retColor

        console.log(data.color.length)
        console.log(polygons.length)

        data.polygons = polygons
    }
    return data
}

ImgDraw.prototype.setImage = function(image) {
    this.img.src = image;
};

ImgDraw.prototype.updateData = function(image) {

    var map = this.map
    var overlay = this.overlay
    var bounds = this.bounds

    // get the new image
    var img = new Image();
    img.src = (window.lightning && window.lightning.host) ? window.lightning.host + image : image;

    // replace the overlay and make sure it's behind other graphics
    map.removeLayer(overlay);
    overlay = new L.ImageOverlay(img.src, bounds).addTo(map);
    overlay.bringToBack()

    this.overlay = overlay

};
<commit_msg>Cleaner refresh<commit_after>'use strict';

var utils = require('lightning-client-utils');
var inherits = require('inherits');
var d3 = require('d3');
var _ = require('lodash');
var validator = require("geojson-validation");
var L = require('leaflet');
var F = require('leaflet.freedraw-browserify');
F(L);

// code adopted from http://kempe.net/blog/2014/06/14/leaflet-pan-zoom-image.html

var ImgDraw = function(selector, data, images, opts) {

    if(!opts) {
        opts = {};
    }

    this.opts = opts

    this.data = this._formatData(data)
    this.images = images
    this.selector = selector;

    this._init();
}

inherits(ImgDraw, require('events').EventEmitter);

ImgDraw.prototype._init = function() {

    var opts = this.opts;
    var data = this.data ? this.data : {};
    var images = this.images;
    var selector = this.selector;
    var self = this;

    this.mid = utils.getUniqueId();
    this.markup = '<link rel="stylesheet" href="//cdn.leafletjs.com/leaflet-0.7.3/leaflet.css"/>

';

    var image = images[0];
    var coords = [];

    this.$el = $(selector).first();
    this.$el.append(this.markup);

    var maxWidth = this.$el.width();

    // create an image so we can get aspect ratio
    this.img = new Image();
    var img = this.img;
    img.src = (window.lightning && window.lightning.host) ? window.lightning.host + image : image;

    img.onload = function() {

        // get image dimensions
        var imw = img.width;
        var imh = img.height;

        // use image dimensions to set css
        var w = maxWidth,
            h = maxWidth * (imh / imw);

        self.$el.find('#image-map-' + self.mid).width(w).height(h);

        //create the map
        if(self.map) {
            self.map.remove();
        }
        self.map = L.map('image-map-' + self.mid, {
            minZoom: 1,
            maxZoom: 8,
            center: [w/2, h/2],
            zoom: 1,
            attributionControl: false,
            zoomControl: false,
            crs: L.CRS.Simple,
        });

        var map = self.map;

        // calculate the edges of the image, in coordinate space
        var southWest = map.unproject([0, h], 1);
        var northEast = map.unproject([w, 0], 1);
        var bounds = new L.LatLngBounds(southWest, northEast);

        // add the image overlay to cover the map
        var overlay = L.imageOverlay(img.src, bounds);
        map.addLayer(overlay)

        // tell leaflet that the map is exactly as big as the image
        map.setMaxBounds(bounds);

        // add free drawing
        var freeDraw = new L.FreeDraw({
          mode: L.FreeDraw.MODES.CREATE | L.FreeDraw.MODES.DELETE | L.FreeDraw.MODES.DELETE,
        });

        // set free drawing options
        freeDraw.options.attemptMerge = false;
        freeDraw.options.setHullAlgorithm('brian3kb/graham_scan_js');
        freeDraw.options.setSmoothFactor(0);

        // add the free drawing layer
        map.addLayer(freeDraw);

        // initialize with any polygons from the data
        if (!_.isEmpty(data)) {

            console.log("we got here")

            var polygons = data.polygons;

            polygons = polygons.map(function (g) {
                var converted = [];
                g.map(function (p) {
                    var newp = new L.point(p[0] / (imw / w), p[1] / (imh / h), false);
                    var newpoint = map.unproject(newp, 1);
                    converted.push(newpoint);
                });
                return converted;
            });

            freeDraw.options.simplifyPolygon = false;
            polygons.forEach(function (g) {
                freeDraw.createPolygon(g, true);
            });
            freeDraw.options.simplifyPolygon = true;

            var COLOR_MODES = ['white', 'bright', 'data-white'];
            var colorIndex = 2;

        } else {

            var COLOR_MODES = ['white', 'bright'];
            var colorIndex = 0;

        }

        d3.select('body').on('keydown', keydown).on('keyup', keyup);

        updateStyles();

        function updateStyles() {

            var c;
            if(COLOR_MODES[colorIndex].indexOf('white') > -1) {
                c = d3.hsl('rgb(255,255,255)');
            } else if (COLOR_MODES[colorIndex].indexOf('bright') > -1) {
                c = d3.hsl('rgb(240,30,110)');
            }

            var isData = (data.color && COLOR_MODES[colorIndex].indexOf('data') > -1);

            d3.select(self.$el[0])
               .selectAll('.image-map g path')
               .style('stroke', function(d, i) {
                if(isData && i < data.color.length-1) {
                    return data.color[i];
                }
                return c;
               })
               .style('fill', function(d, i) {
                var fill;
                if(isData && i < data.color.length-1) {
                    fill = d3.hsl(data.color[i]);
                } else {
                    fill = c;
                }
                fill.l = fill.l * 1.3;
                return fill.toString();
               });

        }

        var mod = function(x, n) {
            return ((x%n)+n)%n;
        };
        function keydown() {
            if (d3.event.altKey) {
                freeDraw.setMode(L.FreeDraw.MODES.EDIT);
            }
            if (d3.event.metaKey | d3.event.shiftKey) {
                freeDraw.setMode(L.FreeDraw.MODES.VIEW);
            }
            if (d3.event.shiftKey & (d3.event.keyCode == 37 | d3.event.keyCode == 39)) {
                d3.event.preventDefault();
                if (d3.event.keyCode == 37) {
                    colorIndex = mod(colorIndex - 1, COLOR_MODES.length);
                }
                if (d3.event.keyCode == 39) {
                    colorIndex = mod(colorIndex + 1, COLOR_MODES.length);
                }
                updateStyles();
            }
        }

        function keyup() {
            freeDraw.setMode(L.FreeDraw.MODES.CREATE | L.FreeDraw.MODES.DELETE)
        }

        self.emit('image:loaded');

        self.$el.unbind().click(function() {

            // extract coordinates from regions
            var n = freeDraw.memory.states.length;
            var coords = freeDraw.memory.states[n-1].map( function(d) {
                var points = [];
                d.forEach(function (p) {
                    var newpoint = map.project(p, 1);
                    newpoint.x *= (imw / w);
                    newpoint.y *= (imh / h);
                    points.push([newpoint.x, newpoint.y]);
                });
                return points;
            });

            utils.updateSettings(self, {
                coords: coords
            }, function(err) {
                console.log('saved user data');
                console.log(coords);
            });
        });

        utils.getSettings(self, function(err, settings) {

            console.log(settings);
            if(!err) {
                coords = settings.coords;
            }

        });

        freeDraw.on('markers', updateStyles);

        self.map = map
        self.bounds = bounds
        self.overlay = overlay

    }

};

module.exports = ImgDraw;

ImgDraw.prototype._formatData = function(data) {

    if (!_.isEmpty(data)) {

        var polygons = []

        if (validator.isFeatureCollection(data)) {
            data.features.forEach(function(d) {
                if (validator.isFeature(d)) {
                    if (validator.isPolygon(d.geometry)) {
                        polygons.push(d.geometry.coordinates[0])
                    }
                }
            })
        } else if (data.coordinates) {
            polygons = data.coordinates
        } else {
            throw "Input data not understood"
        }

        var retColor = utils.getColorFromData(data);
        if (retColor.length == 0) {
            retColor = utils.getColors(polygons.length + 1)
        } else if (retColor.length == 1) {
            retColor = _.range(polygons.length + 1).map(function () { return retColor })
        }

        data.color = retColor

        console.log(data.color.length)
        console.log(polygons.length)

        data.polygons = polygons
    }
    return data
}

ImgDraw.prototype.setImage = function(image) {
    this.img.src = image;
};

ImgDraw.prototype.updateData = function(image) {

    var map = this.map
    var overlay = this.overlay
    var bounds = this.bounds
    var self = this

    // get the new image
    var img = new Image();
    img.src = (window.lightning && window.lightning.host) ? window.lightning.host + image : image;
    img.onload = function() {
        // replace the overlay and make sure it's behind other graphics
        map.removeLayer(overlay);
        overlay = new L.ImageOverlay(img.src, bounds).addTo(map);
        overlay.bringToBack()
        self.overlay = overlay
    }

};
<|endoftext|>


<commit_before>const angular = require('angular');

module.exports = function ($scope) {
  $scope.todoList = [
    { text: 'learn angular', done: true },
    { text: 'build an angular app', done: false }];

  $scope.todoList.addTodo = function () {
    $scope.todoList.push({ text: $scope.todoList.todoText, done: false });
    $scope.todoList.todoText = '';
    console.log($scope.todoList);
  };

  $scope.todoList.remaining = function () {
    var count = 0;
    angular.forEach($scope.todoList, function (todo) {
      count += todo.done ? 0 : 2;
    });
    return count;
  };

  $scope.todoList.archive = function () {
    var oldTodos = $scope.todoList;
    $scope.todoList = [];
    angular.forEach(oldTodos, function (todo) {
      if (!todo.done) {
        $scope.todoList.push(todo);
      }
    });
  };
}<commit_msg>Fixed #22<commit_after>const angular = require('angular');

module.exports = function ($scope) {
  $scope.todoList = [
    { text: 'learn angular', done: true },
    { text: 'build an angular app', done: false }];

  $scope.todoList.addTodo = function () {
    $scope.todoList.push({ text: $scope.todoList.todoText, done: false });
    $scope.todoList.todoText = '';
    console.log($scope.todoList);
  };

  $scope.todoList.remaining = function () {
    var count = 0;
    angular.forEach($scope.todoList, function (todo) {
      count += todo.done ? 0 : 1;
    });
    return count;
  };

  $scope.todoList.archive = function () {
    var oldTodos = $scope.todoList;
    $scope.todoList = [];
    angular.forEach(oldTodos, function (todo) {
      if (!todo.done) {
        $scope.todoList.push(todo);
      }
    });
  };
}<|endoftext|>


<commit_before>/*!
 * zeus-tabs.js v2.0.0
 * https://github.com/GetOlympus/Zeus-Core
 *
 * This plugin creates a categories tabs component 100% WordPress compliant.
 *
 * Example of JS:
 *      $('div.wp-component').zeusTabs({
 *          identifier: 'my-identifier',                // set identifier to create search box
 *          lists: {                                    // list of new tabs to create dynamically
 *              search: 'Search posts',                 // couple of id - title block
 *          },
 *          type: 'posts'                               // set what kind of contents to get
 *      });
 *
 * Example of HTML:
 *

 *

 *

 *                  Most used
 *

 *

 *

 *

 *
 * Copyright 2016 Achraf Chouk
 * Achraf Chouk (https://github.com/crewstyle)
 */

(function ($) {
    "use strict";

    var Tabs = function ($el,options) {
        // vars
        var _this = this;

        // this plugin works ONLY with WordPress wpTemplate and wpList function
        if (!wp || !wp.template || !$.fn.wpList) {
            return;
        }

        _this.$el = $el;
        _this.options = options;

        // initialize
        _this.init();
    };

    Tabs.prototype.$el = null;
    Tabs.prototype.options = null;

    Tabs.prototype.init = function () {
        var _this = this;

        // check tabs list
        if ($.isEmptyObject(_this.options.lists)) {
            return;
        }

        var func = '';

        // add panels and tabs
        $.each(_this.options.lists, function (key, title) {
            func = 'func' + key.charAt(0).toUpperCase() + key.slice(1);

            _this.addPanel(key, title);
            _this.addTab(key, title);

            if ('undefined' !== typeof _this[func] && $.isFunction(_this[func])) {
                _this[func]();
            }
        });

        // bind events on click
        _this.$el.find('.category-tabs a').on('click', $.proxy(_this.changeTab, _this));
    };

    Tabs.prototype.addPanel = function (id,label) {
        var _this = this;

        // vars
        var $panel = $(document.createElement('div')).addClass('tabs-panel')
            .attr('id', _this.options.identifier + '-' + id)
            .hide();

        // create content from template and append to panel
        var _template = wp.template(_this.options.identifier + '-' + id),
            $html = $(_template({
                id: _this.options.identifier + '-' + id,
                identifier: _this.options.identifier,
                key: id,
                label: label
            }));
            $panel.append($html);

        // append to final target
        _this.$el.find('.tabs-panel').last().after($panel);
    };

    Tabs.prototype.addTab = function (id,label) {
        var _this = this;

        // node elements
        var $link = $(document.createElement('a'))
            .attr('href', '#'+_this.options.identifier+'-'+id)
            .text(label);

        var $tab = $(document.createElement('li'));
        $tab.append($link);

        // append to final target
        _this.$el.find('.category-tabs').append($tab);
    };

    Tabs.prototype.changeTab = function (e) {
        e.preventDefault();
        var _this = this;

        // vars
        var $self = $(e.target || e.currentTarget);

        // update tabs
        _this.$el.find('.category-tabs .tabs').removeClass('tabs');
        $self.parent().addClass('tabs');

        // update panels
        _this.$el.find('.tabs-panel').hide();
        $($self.attr('href')).show();
    };

    Tabs.prototype.funcSearch = function () {
        var _this = this;

        // vars
        _this.$el.find('#' + _this.options.identifier + '-quick').on('keyup', function (e) {
            e.preventDefault();

            $('#' + _this.options.identifier + '-checklist').wpList({
                /**
                 * Add current post_ID to request to fetch custom fields
                 *
                 * @ignore
                 *
                 * @param {Object} s Request object.
                 *
                 * @returns {Object} Data modified with post_ID attached.
                 */
                addBefore: function (s) {
                    s.data += '&post_type=[' + _this.options.type + ']';
                    return s;
                },

                /**
                 * Show the listing of custom fields after fetching.
                 *
                 * @ignore
                 */
                addAfter: function () {
                    // $('table#list-table').show();
                }
            });
        });

    };

    var methods = {
        init: function (options) {
            if (!this.length) {
                return false;
            }

            var settings = {
                identifier: 'my-identifier',
                lists: {
                    search: 'Search posts'
                },
                type: 'posts'
            };

            return this.each(function () {
                if (options) {
                    $.extend(settings, options);
                }

                new Tabs($(this), settings);
            });
        },
        update: function (){},
        destroy: function (){}
    };

    $.fn.zeusTabs = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method '+method+' does not exist on zeusTabs');
            return false;
        }
    };
})(window.jQuery);
<commit_msg>add WordPress source reference<commit_after>/*!
 * zeus-tabs.js v2.0.0
 * https://github.com/GetOlympus/Zeus-Core
 *
 * This plugin creates a categories tabs component 100% WordPress compliant.
 * @see wp-includes/js/wp-lists.js
 *
 * Example of JS:
 *      $('div.wp-component').zeusTabs({
 *          identifier: 'my-identifier',                // set identifier to create search box
 *          lists: {                                    // list of new tabs to create dynamically
 *              search: 'Search posts',                 // couple of id - title block
 *          },
 *          type: 'posts'                               // set what kind of contents to get
 *      });
 *
 * Example of HTML:
 *

 *

 *

 *                  Most used
 *

 *

 *

 *

 *
 * Copyright 2016 Achraf Chouk
 * Achraf Chouk (https://github.com/crewstyle)
 */

(function ($) {
    "use strict";

    var Tabs = function ($el,options) {
        // vars
        var _this = this;

        // this plugin works ONLY with WordPress wpTemplate and wpList function
        if (!wp || !wp.template || !$.fn.wpList) {
            return;
        }

        _this.$el = $el;
        _this.options = options;

        // initialize
        _this.init();
    };

    Tabs.prototype.$el = null;
    Tabs.prototype.options = null;

    Tabs.prototype.init = function () {
        var _this = this;

        // check tabs list
        if ($.isEmptyObject(_this.options.lists)) {
            return;
        }

        var func = '';

        // add panels and tabs
        $.each(_this.options.lists, function (key, title) {
            func = 'func' + key.charAt(0).toUpperCase() + key.slice(1);

            _this.addPanel(key, title);
            _this.addTab(key, title);

            if ('undefined' !== typeof _this[func] && $.isFunction(_this[func])) {
                _this[func]();
            }
        });

        // bind events on click
        _this.$el.find('.category-tabs a').on('click', $.proxy(_this.changeTab, _this));
    };

    Tabs.prototype.addPanel = function (id,label) {
        var _this = this;

        // vars
        var $panel = $(document.createElement('div')).addClass('tabs-panel')
            .attr('id', _this.options.identifier + '-' + id)
            .hide();

        // create content from template and append to panel
        var _template = wp.template(_this.options.identifier + '-' + id),
            $html = $(_template({
                id: _this.options.identifier + '-' + id,
                identifier: _this.options.identifier,
                key: id,
                label: label
            }));
            $panel.append($html);

        // append to final target
        _this.$el.find('.tabs-panel').last().after($panel);
    };

    Tabs.prototype.addTab = function (id,label) {
        var _this = this;

        // node elements
        var $link = $(document.createElement('a'))
            .attr('href', '#'+_this.options.identifier+'-'+id)
            .text(label);

        var $tab = $(document.createElement('li'));
        $tab.append($link);

        // append to final target
        _this.$el.find('.category-tabs').append($tab);
    };

    Tabs.prototype.changeTab = function (e) {
        e.preventDefault();
        var _this = this;

        // vars
        var $self = $(e.target || e.currentTarget);

        // update tabs
        _this.$el.find('.category-tabs .tabs').removeClass('tabs');
        $self.parent().addClass('tabs');

        // update panels
        _this.$el.find('.tabs-panel').hide();
        $($self.attr('href')).show();
    };

    Tabs.prototype.funcSearch = function () {
        var _this = this;

        // vars
        _this.$el.find('#' + _this.options.identifier + '-quick').on('keyup', function (e) {
            e.preventDefault();

            $('#' + _this.options.identifier + '-checklist').wpList({
                /**
                 * Add current post_ID to request to fetch custom fields
                 *
                 * @ignore
                 *
                 * @param {Object} s Request object.
                 *
                 * @returns {Object} Data modified with post_ID attached.
                 */
                addBefore: function (s) {
                    s.data += '&post_type=[' + _this.options.type + ']';
                    return s;
                },

                /**
                 * Show the listing of custom fields after fetching.
                 *
                 * @ignore
                 */
                addAfter: function () {
                    // $('table#list-table').show();
                }
            });
        });

    };

    var methods = {
        init: function (options) {
            if (!this.length) {
                return false;
            }

            var settings = {
                identifier: 'my-identifier',
                lists: {
                    search: 'Search posts'
                },
                type: 'posts'
            };

            return this.each(function () {
                if (options) {
                    $.extend(settings, options);
                }

                new Tabs($(this), settings);
            });
        },
        update: function (){},
        destroy: function (){}
    };

    $.fn.zeusTabs = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method '+method+' does not exist on zeusTabs');
            return false;
        }
    };
})(window.jQuery);
<|endoftext|>


<commit_before>'use strict';
var S = S || {};

S.user = {
    _current : {
        restoreSession : function()  {
          var last = JSON.parse(localStorage["sofia-last-login"])
          console.log("Restoring previous session:"+last);

          $.extend(S.user._current, last.doc);
        },
        wasLoggedIn : function(){
          //S.config.db._full_url || S.db.remoteDB._db_name, S.config.user.username, S.config.user.userpass
          if(typeof localStorage["sofia-last-login"] !== "string"){
            return false; //No trace of login
          }

          var last = JSON.parse(localStorage["sofia-last-login"])

          if(last.db !== S.db.remoteDB._db_name){
            return false; //Not same remote DB
          }

          if(last.user.name !== S.config.user.username || last.user.pass !== S.config.user.userpass){
            return false; //Not same cred
          }

          var ThreeHourSooner = new Date();
          ThreeHourSooner.setHours(ThreeHourSooner.getHours() - 3);
          if(last.at < ThreeHourSooner){
            return false; //Not logged in since 3 Hours
          }

          return true; //All good

        },
        isLogged : function(){
            return (typeof S.user._current.name !== "undefined" && (S.user._current.name !== null || S.user._current.roles[0] === "_admin" ) ) ;
        },
        isAdmin : function(){
            //console.log("isAdmin ? ", S.user._current.isLogged && ($.inArray("_admin", S.user._current.roles)!==-1 || $.inArray("sofia-admin", S.user._current.roles)!==-1));
            return S.user._current.isLogged && ($.inArray("_admin", S.user._current.roles)!==-1 || $.inArray("sofia-admin", S.user._current.roles)!==-1);
        }
    },
    login : function(user,pass,silent){
      console.log("Trying to login : ", user,pass,silent);
      if(typeof silent === "undefined"){
        silent = false;
      }
      return S.db.users.login(user,pass,silent).then(function(doc){
        //We are logged in
        localStorage["sofia-last-login"] = JSON.stringify({
            db :  S.db.remoteDB._db_name,
            user : {
              name : user,
              pass : pass
            },
            doc : doc,
            at :  new Date()
          });
        return doc;
      });
    },
    set : function(user,pass,doc){
      console.log("Setting user in memory", user, pass, doc);
      S.config.user = {
          username : user,
          userpass : pass
      };
      localStorage["sofia-user-config"] = JSON.stringify(S.config.user);
      if(typeof doc !== "undefined"){
        $.extend(S.user._current, doc);
      }
    },
    /*
    logout : function(){
      S.user._current.name !== null; //logout
      //TODO redirect to login
    },
    */
    reset : function(){
      //S.config.user.username=""; // We don't reset in case the team really exist
      S.config.user.userpass="";
      delete localStorage['sofia-user-config'];
    }
};
<commit_msg>Fix #68<commit_after>'use strict';
var S = S || {};

S.user = {
    _current : {
        restoreSession : function()  {
          var last = JSON.parse(localStorage["sofia-last-login"])
          console.log("Restoring previous session:"+last);

          $.extend(S.user._current, last.doc);
        },
        wasLoggedIn : function(){
          //S.config.db._full_url || S.db.remoteDB._db_name, S.config.user.username, S.config.user.userpass
          if(typeof localStorage["sofia-last-login"] !== "string"){
            return false; //No trace of login
          }

          var last = JSON.parse(localStorage["sofia-last-login"])

          if(last.db !== S.db.remoteDB._db_name){
            return false; //Not same remote DB
          }

          if(last.user.name !== S.config.user.username || last.user.pass !== S.config.user.userpass){
            return false; //Not same cred
          }

          var ThreeHourSooner = new Date();
          ThreeHourSooner.setHours(ThreeHourSooner.getHours() - 3);
          if(last.at < ThreeHourSooner){
            return false; //Not logged in since 3 Hours
          }

          return true; //All good

        },
        isLogged : function(){
            return (typeof S.user._current.name !== "undefined" && (S.user._current.name !== null || S.user._current.roles[0] === "_admin" ) ) ;
        },
        isAdmin : function(){
            //console.log("isAdmin ? ", S.user._current.isLogged && ($.inArray("_admin", S.user._current.roles)!==-1 || $.inArray("sofia-admin", S.user._current.roles)!==-1));
            return S.user._current.isLogged && ($.inArray("_admin", S.user._current.roles)!==-1 || $.inArray("sofia-admin", S.user._current.roles)!==-1);
        }
    },
    login : function(user,pass,silent){
      console.log("Trying to login : ", user,pass,silent);
      if(typeof silent === "undefined"){
        silent = false;
      }
      return S.db.users.login(user,pass,silent).then(function(doc){
        //We are logged in
        localStorage["sofia-last-login"] = JSON.stringify({
            db :  S.db.remoteDB._db_name,
            user : {
              name : user,
              pass : pass
            },
            doc : doc,
            at :  new Date()
          });
        return doc;
      });
    },
    set : function(user,pass,doc){
      console.log("Setting user in memory", user, pass, doc);
      S.config.user = {
          username : user,
          userpass : pass
      };
      localStorage["sofia-user-config"] = JSON.stringify(S.config.user);
      if(typeof doc !== "undefined"){
        $.extend(S.user._current, doc);
      }
      if(S.user._current.name === null){
        S.user._current.name = S.config.user.username //Default to username ( admin case )
      }
    },
    /*
    logout : function(){
      S.user._current.name !== null; //logout
      //TODO redirect to login
    },
    */
    reset : function(){
      //S.config.user.username=""; // We don't reset in case the team really exist
      S.config.user.userpass="";
      delete localStorage['sofia-user-config'];
    }
};
<|endoftext|>


<commit_before>'use strict';

app.directive('toolbar', [
  'pageService', function (page) {
    return {
      restrict: 'E',
      templateUrl: 'site/toolbar.html',
      scope: {},
      link: function ($scope) {
        $scope.page = page;
        $scope.hoverUserToggle = function ($event) {
          $scope.hoverUser = !$scope.hoverUser;
          if ($event)
            $event.stopPropagation();
        };
        $scope.$on('$locationChangeStart', function () {
          $scope.hoverUser = false;
        });
        $scope.hoverSearchToggle = function ($event) {
          $scope.hoverSearch = !$scope.hoverSearch;
          if ($event)
            $event.stopPropagation();
        };
        page.$rootScope.$on('$locationChangeStart', function () {
          $scope.hoverSearch = false;
        });

        $scope.search = function () {
          page.$location.path(page.router.search()).search($scope.search.data);
        };
        $scope.search.data = {};
      }
    };
  }
]);
<commit_msg>Cleanup toolbar locationChangeStart handling<commit_after>'use strict';

app.directive('toolbar', [
  'pageService', function (page) {
    return {
      restrict: 'E',
      templateUrl: 'site/toolbar.html',
      scope: {},
      link: function ($scope) {
        $scope.page = page;
        $scope.hoverUserToggle = function ($event) {
          $scope.hoverUser = !$scope.hoverUser;
          if ($event)
            $event.stopPropagation();
        };
        $scope.hoverSearchToggle = function ($event) {
          $scope.hoverSearch = !$scope.hoverSearch;
          if ($event)
            $event.stopPropagation();
        };
        $scope.$on('$locationChangeStart', function () {
          $scope.hoverUser = false;
          $scope.hoverSearch = false;
        });

        $scope.search = function () {
          page.$location.path(page.router.search()).search($scope.search.data);
        };
        $scope.search.data = {};
      }
    };
  }
]);
<|endoftext|>


<commit_before>(function() {
'use strict';

// authoring
angular.module('authoringTool.authoring', ['ngRoute','authoringTool.authoring.defaultOptionsBlock','authoringTool.authoring.questionSet', 'authoringTool.authoring.answerPanel'])

.config(['$routeProvider', function($routeProvider) {
	$routeProvider.when('/authoring', {
		templateUrl: 'authoring/authoring.html',
		controller: 'MainCtrl'
	});
}])

.controller('MainCtrl', function ($scope) {
	$scope.data = {

	};
})

.controller('AccordionCtrl', function ($scope) {
	$scope.oneAtATime = true;

	$scope.status = {
		isFirstOpen: true,
		isFirstDisabled: false
	};
})

.controller('AuthoringVideoCtrl', function($scope, $sce) {
	$scope.config = {
		autoHide: false,
		autoHideTime: 3000,
		sources: [
			{
				src: $sce.trustAsResourceUrl("caesar-cipher.mp4"), type: "video/mp4"
			},
		],
		theme: {
			url: "authoring/videogular.css"
		},
		plugins: {
			cuepoints: {
				theme: {
					url: "bower_components/videogular-cuepoints/cuepoints.css",
				},
			},
		}
	};
})

.controller('SetAddCtrl',  function ($scope){
	$scope.sets = ['Question Set 1'];

	$scope.addQuestionSet = function() {
		var newSetNo = $scope.sets.length + 1;
		$scope.sets.push('Question Set ' + newSetNo);
	};
})

// authoring.defaultOptionsBlock
angular.module('authoringTool.authoring.defaultOptionsBlock',[])

.directive('defaultOptionsBlock', function(){
	return {
		restrict: 'E',
		templateUrl: 'authoring/defaultOptions.html',
		scope: {
			heading: '@'
		},
	};
});

// authoring.questionSet
angular.module('authoringTool.authoring.questionSet', ['authoringTool.authoring.questionSet.questionBlock','authoringTool.authoring.questionSet.timeChoose'])

.controller('SectionAddCtrl',  function ($scope){
	$scope.questions = [
		{
			name:'Question 1',
			type:'quiz'
		}, {
			name: 'Question 2',
			type:'quiz'
		},{
			name:'Poll 1',
			type:'poll'
		}
	];

	var pollNo = 1;
	var quizNo = 2;

	$scope.addPoll = function() {
		pollNo = pollNo + 1;

		return $scope.questions.push({
			name:'Poll ' + pollNo,
			type:'poll'
		});

		console.dir($scope.questions);
	};

	$scope.addQuestion = function() {
		quizNo = quizNo + 1;
		return $scope.questions.push({name:'Question ' + quizNo, type:'quiz'});
		console.dir($scope.questions);
	};

	Array.prototype.swap = function (x,y) {
		var b = this[x];
		this[x] = this[y];
		this[y] = b;
		return this;
	}

	Array.prototype.getIndexByVal = function (toGet) {
		var index = -1;
		for (var i = 0, len = this.length; i < len; i++) {
			if (this[i].name === toGet.name) index=i;
		}
		return index;
	}

	$scope.moveQuestionUp = function(event,toMove) {
		event.preventDefault();
		event.stopPropagation();

		var index = $scope.questions.getIndexByVal(toMove);
		console.dir(index);
		if (index > 0){
			$scope.questions.swap(index, index-1);
		}
		console.dir($scope.questions);
	};

	$scope.moveQuestionDown = function(event,toMove) {
		event.preventDefault();
		event.stopPropagation();

		var index = $scope.questions.getIndexByVal(toMove);
		console.dir(index);
		if (index > 0){
			$scope.questions.swap(index, index+1);
		}
		console.dir($scope.questions);
	};
})

.directive('questionSet', function(){
	return {
		restrict: 'E',
		templateUrl: 'authoring/questionSet.html',
		scope: {
			heading: '@'
		},
	};
});

// authoring.questionSet.questionBlock
angular.module('authoringTool.authoring.questionSet.questionBlock',[])

.directive('questionBlock', function(){
	return {
		restrict: 'E',
		require: '^questionSet',
		templateUrl: 'authoring/questionBlock.html',
		scope: {
			heading: '@',
			type: '@'
		},
		controller: ['$scope', function($scope) {
			this.getType = function() {
				return $scope.type;
			}
		}]
	};
});

// authoring.questionSet.timeChoose
angular.module('authoringTool.authoring.questionSet.timeChoose',[])

.directive('timeChoose', function(){
	return {
		restrict: 'E',
		require: '^questionSet',
		templateUrl: 'authoring/timeChoose.html'
	};
});

// authoring.answerPanel
angular.module('authoringTool.authoring.answerPanel',['authoringTool.authoring.answerPanel.multiple','authoringTool.authoring.answerPanel.stars','authoringTool.authoring.answerPanel.pairs']);

// authoring.answerPanel.multiple
angular.module('authoringTool.authoring.answerPanel.multiple',[])

.directive('multipleChoice', function(){
	return{
		restrict: 'E',
		require: '^questionBlock',
		templateUrl: 'authoring/answerPanel/multipleChoice.html',
		scope: {
			single: '@'
		},
		link: function(scope, element, attrs, ctrl) {
			scope.type = ctrl.getType();
		}
	};
})

.controller('AddAnswerCtrl',  function ($scope){
	$scope.answers = [];
	$scope.correct;

	$scope.addAnswer = function(newAnswer) {
		if (newAnswer.length>0) {
			if ($scope.answers.indexOf(newAnswer)==-1){
				$scope.answers.push(newAnswer);
			}
		}
	};

	$scope.removeAnswer = function(toRemove) {
		var index = $scope.answers.indexOf(toRemove);
		if (index > -1) {
			$scope.answers.splice(index, 1);
		}
	};

	$scope.moveAnswerUp = function(toMove) {
		var index =  $scope.answers.indexOf(toMove);
		if (index > 0){
			var temp = $scope.answers[index - 1];
			$scope.answers[index - 1] = $scope.answers[index];
			$scope.answers[index] = temp;
		}
	};

	$scope.moveAnswerDown = function(toMove) {
		var index =  $scope.answers.indexOf(toMove);
		if (index < ($scope.answers.length -1)){
			var temp = $scope.answers[index];
			$scope.answers[index] = $scope.answers[index + 1];
			$scope.answers[index + 1] = temp;
		}
	};

	$scope.setCorrect = function (toSet) {
		$scope.correct = toSet;
	}
});

// authoring.answerPanel.stars
angular.module('authoringTool.authoring.answerPanel.stars',[])

.directive('stars', function(){
	return {
		restrict: 'E',
		require: '^questionBlock',
		templateUrl: 'authoring/answerPanel/stars.html'
	};
});

// authoring.answerPanel.pairs
angular.module('authoringTool.authoring.answerPanel.pairs',[])

.directive('matchingPairs', function(){
	return {
		restrict: 'E',
		require: '^questionBlock',
		templateUrl: 'authoring/answerPanel/matchingPairs.html'
	};
});

})();
<commit_msg>Add beginings of data export functionality<commit_after>(function() {
'use strict';

// authoring
angular.module('authoringTool.authoring', ['ngRoute','authoringTool.authoring.defaultOptionsBlock','authoringTool.authoring.questionSet', 'authoringTool.authoring.answerPanel'])

.config(['$routeProvider', function($routeProvider) {
	$routeProvider.when('/authoring', {
		templateUrl: 'authoring/authoring.html',
		controller: 'MainCtrl'
	});
}])

.controller('MainCtrl', function ($scope) {
	$scope.data = {

	};
})

.controller('AccordionCtrl', function ($scope) {
	$scope.oneAtATime = true;

	$scope.status = {
		isFirstOpen: true,
		isFirstDisabled: false
	};
})

.controller('AuthoringVideoCtrl', function($scope, $sce) {
	$scope.config = {
		autoHide: false,
		autoHideTime: 3000,
		sources: [
			{
				src: $sce.trustAsResourceUrl("caesar-cipher.mp4"), type: "video/mp4"
			},
		],
		theme: {
			url: "authoring/videogular.css"
		},
		plugins: {
			cuepoints: {
				theme: {
					url: "bower_components/videogular-cuepoints/cuepoints.css",
				},
			},
		}
	};
})

.controller('SetAddCtrl',  function ($scope){
	$scope.sets = ['Question Set 1'];

	$scope.addQuestionSet = function() {
		var newSetNo = $scope.sets.length + 1;
		$scope.sets.push('Question Set ' + newSetNo);
	};
})

// authoring.defaultOptionsBlock
angular.module('authoringTool.authoring.defaultOptionsBlock',[])

.directive('defaultOptionsBlock', function(){
	return {
		restrict: 'E',
		templateUrl: 'authoring/defaultOptions.html',
		scope: {
			heading: '@'
		},
	};
});

// authoring.questionSet
angular.module('authoringTool.authoring.questionSet', ['authoringTool.authoring.questionSet.questionBlock','authoringTool.authoring.questionSet.timeChoose'])

.controller('SectionAddCtrl',  function ($scope){
	$scope.questions = [
		{
			name:'Question 1',
			type:'quiz'
		}, {
			name: 'Question 2',
			type:'quiz'
		},{
			name:'Poll 1',
			type:'poll'
		}
	];

	var pollNo = 1;
	var quizNo = 2;

	$scope.addPoll = function() {
		pollNo = pollNo + 1;

		return $scope.questions.push({
			name:'Poll ' + pollNo,
			type:'poll'
		});

		console.dir($scope.questions);
	};

	$scope.addQuestion = function() {
		quizNo = quizNo + 1;
		return $scope.questions.push({name:'Question ' + quizNo, type:'quiz'});
		console.dir($scope.questions);
	};

	Array.prototype.swap = function (x,y) {
		var b = this[x];
		this[x] = this[y];
		this[y] = b;
		return this;
	}

	Array.prototype.getIndexByVal = function (toGet) {
		var index = -1;
		for (var i = 0, len = this.length; i < len; i++) {
			if (this[i].name === toGet.name) index=i;
		}
		return index;
	}

	$scope.moveQuestionUp = function(event,toMove) {
		event.preventDefault();
		event.stopPropagation();

		var index = $scope.questions.getIndexByVal(toMove);
		console.dir(index);
		if (index > 0){
			$scope.questions.swap(index, index-1);
		}
		console.dir($scope.questions);
	};

	$scope.moveQuestionDown = function(event,toMove) {
		event.preventDefault();
		event.stopPropagation();

		var index = $scope.questions.getIndexByVal(toMove);
		console.dir(index);
		if (index > 0){
			$scope.questions.swap(index, index+1);
		}
		console.dir($scope.questions);
	};
})

.directive('questionSet', function(){
	return {
		restrict: 'E',
		templateUrl: 'authoring/questionSet.html',
		scope: {
			heading: '@'
		},
	};
});

// authoring.questionSet.questionBlock
angular.module('authoringTool.authoring.questionSet.questionBlock',[])

.directive('questionBlock', function(){
	return {
		restrict: 'E',
		require: '^questionSet',
		templateUrl: 'authoring/questionBlock.html',
		scope: {
			heading: '@',
			type: '@'
		},
		controller: ['$scope', function($scope) {
			this.getType = function() {
				return $scope.type;
			}
		}]
	};
});

// authoring.questionSet.timeChoose
angular.module('authoringTool.authoring.questionSet.timeChoose',[])

.directive('timeChoose', function(){
	return {
		restrict: 'E',
		require: '^questionSet',
		templateUrl: 'authoring/timeChoose.html'
	};
});

// authoring.answerPanel
angular.module('authoringTool.authoring.answerPanel',['authoringTool.authoring.answerPanel.multiple','authoringTool.authoring.answerPanel.stars','authoringTool.authoring.answerPanel.pairs']);

// authoring.answerPanel.multiple
angular.module('authoringTool.authoring.answerPanel.multiple',[])

.directive('multipleChoice', function(){
	return{
		restrict: 'E',
		require: '^questionBlock',
		templateUrl: 'authoring/answerPanel/multipleChoice.html',
		scope: {
			single: '@'
		},
		link: function(scope, element, attrs, ctrl) {
			scope.type = ctrl.getType();
		}
	};
})

.controller('AddAnswerCtrl',  function ($scope){
	$scope.answers = [];
	$scope.correct;

	$scope.addAnswer = function(newAnswer) {
		if (newAnswer.length>0) {
			if ($scope.answers.indexOf(newAnswer)==-1){
				$scope.answers.push(newAnswer);
			}
		}
	};

	$scope.removeAnswer = function(toRemove) {
		var index = $scope.answers.indexOf(toRemove);
		if (index > -1) {
			$scope.answers.splice(index, 1);
		}
	};

	$scope.moveAnswerUp = function(toMove) {
		var index =  $scope.answers.indexOf(toMove);
		if (index > 0){
			var temp = $scope.answers[index - 1];
			$scope.answers[index - 1] = $scope.answers[index];
			$scope.answers[index] = temp;
		}
	};

	$scope.moveAnswerDown = function(toMove) {
		var index =  $scope.answers.indexOf(toMove);
		if (index < ($scope.answers.length -1)){
			var temp = $scope.answers[index];
			$scope.answers[index] = $scope.answers[index + 1];
			$scope.answers[index + 1] = temp;
		}
	};

	$scope.setCorrect = function (toSet) {
		$scope.correct = toSet;
	}
});

// authoring.answerPanel.stars
angular.module('authoringTool.authoring.answerPanel.stars',[])

.directive('stars', function(){
	return {
		restrict: 'E',
		require: '^questionBlock',
		templateUrl: 'authoring/answerPanel/stars.html'
	};
});

// authoring.answerPanel.pairs
angular.module('authoringTool.authoring.answerPanel.pairs',[])

.directive('matchingPairs', function(){
	return {
		restrict: 'E',
		require: '^questionBlock',
		templateUrl: 'authoring/answerPanel/matchingPairs.html'
	};
});

function questionAnsweredIncorrectly(questionId, time) {

	var template = '{\
		id: "incorrect-QUESTION_ID",\
		type: "single",\
		question: "Answer incorrect, do you want to review the video",\
		options: [\
			{\
				name: "Yes"\
			},\
			{\
				name: "No"\
			}\
		],\
		action: function(questions, video) {\
			var question = questions.get("QUESTION_ID");\
			if (question.response !== question.correctAnswer) {\
				video.setTime(TIME);\
			}\
		},\
		condition: function(questions) {\
			return questions.get("QUESTION_ID").isNotCorrect();\
		}\
	}';

	template.replace("QUESTION_ID", questionId);
	template.replace("TIME", time);

	return template;
}

function exportWebWorker(data) {

}

})();
<|endoftext|>


<commit_before>"use strict";

// A button or anchor provides:
//     disabled="disabled": it should start disabled
//     data-always-enable: true if it should always be enabled
//     data-href: the URL that will either be a direct link or a "next=" after login
//     data-disabled-title (optional) = a title to set on the disabled element
//
// If data-always-enable is true, enable the button/anchor.
// If it's false then check config.loggedIn and determine whether to
// modify the button or anchor into a loginUrl redirector or to
// leave disabled and set the disabled text.
//
// When an anchor tag gets enabled, its href is set to its data-href.

var $ = require('jquery'),
    _ = require('lodash'),

    enablePermAttr = 'data-always-enable',
    disabledTitleAttr = 'data-disabled-title',
    redirectUrlAttr = 'data-redirect-url',
    hrefAttr = 'data-href',
    enablePermSelector = '[' + enablePermAttr + ']',
    config;

function removeActionableDataAttributes($el) {
    // in case it triggers a modal
    $el.removeAttr('data-target');
    // in case an event is bound to this element
    $el.removeAttr('data-action');
}

function makeRedirectToLogin($el, href) {

    var fullHref = config.loginUrl + href;

    $el.attr('disabled', false);
    removeActionableDataAttributes($el);

    if ($el.is('a')) { $el.attr('href', fullHref); }
    else if ($el.is('button')) {
        $el.off('click');
        $el.click(function () {
            window.location = fullHref;
        });
    }
}

function fullyEnable($el, href) {
    $el.attr('disabled', false);
    if ($el.is('a')) { $el.attr('href', href); }
}

function fullyDisable($el, disabledTitle) {
    $el.off('click');
    removeActionableDataAttributes($el);
    if (disabledTitle) { $el.attr('title', disabledTitle); }
}

exports.run = function (options) {
    var $elements = $(enablePermSelector);

    config = options.config;

    _.each($elements, function(element) {
        var $element = $(element),
            hasPerm = $element.attr(enablePermAttr),
            disabledTitle = $element.attr(disabledTitleAttr),
            href = $element.attr(hrefAttr);

        if (hasPerm === 'True') {
            fullyEnable($element, href);
        } else if (!config.loggedIn) {
            makeRedirectToLogin($element, href);
        } else {
            fullyDisable($element, disabledTitle);
        }
    });
};
<commit_msg>Wrap disabled buttons in a titled label element<commit_after>"use strict";

// A button or anchor provides:
//     disabled="disabled": it should start disabled
//     data-always-enable: true if it should always be enabled
//     data-href: the URL that will either be a direct link or a "next=" after login
//     data-disabled-title (optional) = a title to set on the disabled element
//
// If data-always-enable is true, enable the button/anchor.
// If it's false then check config.loggedIn and determine whether to
// modify the button or anchor into a loginUrl redirector or to
// leave disabled and set the disabled text.
//
// When an anchor tag gets enabled, its href is set to its data-href.

var $ = require('jquery'),
    _ = require('lodash'),
    format = require('util').format,

    enablePermAttr = 'data-always-enable',
    disabledTitleAttr = 'data-disabled-title',
    redirectUrlAttr = 'data-redirect-url',
    hrefAttr = 'data-href',
    enablePermSelector = '[' + enablePermAttr + ']',
    disabledButtonWrapperAttrPair = 'data-class="disabled-button-wrapper"',
    disabledButtonWrapperSelector = '[' + disabledButtonWrapperAttrPair + ']',
    config;

function removeActionableDataAttributes($el) {
    // in case it triggers a modal
    $el.removeAttr('data-target');
    // in case an event is bound to this element
    $el.removeAttr('data-action');
}

function makeRedirectToLogin($el, href) {

    var fullHref = config.loginUrl + href;

    $el.attr('disabled', false);
    removeActionableDataAttributes($el);

    if ($el.is('a')) { $el.attr('href', fullHref); }
    else if ($el.is('button')) {
        $el.off('click');
        $el.click(function () {
            window.location = fullHref;
        });
    }
}

function fullyEnable($el, href) {
    $el.attr('disabled', false);
    if ($el.is('a')) { $el.attr('href', href); }
}

function fullyDisable($el, disabledTitle) {
    var wrapperTemplate =
            '<label ' + disabledButtonWrapperAttrPair +
            ' title="%s"></label>';

    $el.off('click');
    removeActionableDataAttributes($el);
    if (disabledTitle && !$el.parent().is(disabledButtonWrapperSelector)) {
        $el.wrap(format(wrapperTemplate, disabledTitle));
    }
}

exports.run = function (options) {
    var $elements = $(enablePermSelector);

    config = options.config;

    _.each($elements, function(element) {
        var $element = $(element),
            hasPerm = $element.attr(enablePermAttr),
            disabledTitle = $element.attr(disabledTitleAttr),
            href = $element.attr(hrefAttr);

        if (hasPerm === 'True') {
            fullyEnable($element, href);
        } else if (!config.loggedIn) {
            makeRedirectToLogin($element, href);
        } else {
            fullyDisable($element, disabledTitle);
        }
    });
};
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { action } from '@ember/object';

export default class Dropdown extends Component {
  tagName = '';

  dropdownExpanded = false;

  @action
  toggleDropdown() {
    this.toggleProperty('dropdownExpanded');
  }
}
<commit_msg>Dropdown: Convert `dropdownExpanded` to tracked property<commit_after>import Component from '@ember/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class Dropdown extends Component {
  tagName = '';

  @tracked dropdownExpanded = false;

  @action
  toggleDropdown() {
    this.dropdownExpanded = !this.dropdownExpanded;
  }
}
<|endoftext|>