<commit_before>import Recorder from './Recorder';

const defaultConfig = {
  worker: null,
  workerPath: 'recordWorker'
};

const audio_context = new AudioContext();
export const events = {
  PLAY: 'play',
  PAUSE: 'pause',
  ENDED: 'ended',
  START_REC: 'startRecording',
  STOP_REC: 'stopRecording',
  PROGRESS: 'progress',
  REWIND: 'rewind',
  ERROR: 'error'
};

export default class Dictaphone {
  constructor(player, config) {
    this.config = Object.assign({}, defaultConfig, config);
    this.player = player;
    this.recorder = null;
    this.playing = false;
    this.recording = false;
    this.master_recording = null;
    this.progressBarStep = 0.1; // in sec;
    this.subscribers = {};

  }

  destroy() {
    this.subscribers = {};
    // todo remove media URL
  }

  on(message, callback) {
    if (!this.subscribers[message]) {
      this.subscribers[message] = [];
    }
    this.subscribers[message].push(callback);
  }

  emit(message, data) {
    if(!this.subscribers[message]) return;
    this.subscribers[message].forEach(e => e(data));
  }

  startRecording () {
    if (this.recording || this.playing) {
      return;
    }

    this.setRecorder(() => {
      this.recorder && this.recorder.record();
      this.recording = true;
      this.emit(events.START_REC, {position: this.player.currentTime});
    });
  }

  stopRecording() {
    const that = this;

    if (!this.recording) {
      return;
    }

    this.recorder && this.recorder.stop();
    this.recording = false;
    this._createMasterRecording(() => {
      setTimeout(() => {
        this.emit(events.STOP_REC, {duration: that.player.duration});
        this.closeRecorder();
      }, 200);
    });
    this.recorder.clear();
  }

  togglePlayback () {
    this.playing ? this.pause() : this.play();
  }

  play() {
    let _time = this.player.currentTime;

    if (_time >= this.player.duration) {
      return;
    }

    this.playing = true;
    this.emit(events.PLAY, {time: this.player.currentTime});
    this.player.play();

    const loop = setInterval(() => {
      if( this.playing && _time < this.player.duration ) {
        this.emit(events.PROGRESS, {time: this.player.currentTime, duration: this.player.duration});
        _time = _time + this.progressBarStep;
      } else {
        clearInterval(loop);
        this.playing = false;
        this.emit(events.PAUSE, {time: this.player.currentTime})
      }
    }, this.progressBarStep * 1000);
  }

  pause() {
    if (this.recording) {
      this.emit(events.ERROR, 'Protect to call pause while recording');
    }
    this.playing = false;
    this.player.pause();
    this.emit(events.PAUSE, {time: this.player.currentTime})
  }

  rewind(time) {
    let _time = time;

    if (this.recording || time < 0) {
      this.emit(events.ERROR, 'Protect to call rewind while recording');
      return;
    }

    this.playing && this.pause();

    if (time > this.player.duration) {
      _time = this.player.duration;
    }

    this.player.currentTime = _time;

    this.emit(events.REWIND, {toTime: _time});
  }

  rewindToBegin() {
    this.rewind(0);
  }

  rewindToEnd() {
    this.rewind(this.player.duration);
  }

  _createMasterRecording(callback) {
    const that = this;
    this.recorder && this.recorder.exportWAV((blob) => {
      if(that.master_recording){
        that._concatenateRecordings(that.master_recording, blob, (blob) => callback(blob));
      } else {
        that.master_recording = blob;
        that.player.src = URL.createObjectURL(that.master_recording);
        callback(blob);
      }
    });
  }

  _concatenateRecordings(blob1, blob2, callback) {
    const duration = this.player.duration;
    const position = this.player.currentTime;
    const blob1Size = blob1.size-44;
    let blob2_data = blob2.slice(44);
    let blob1_data = blob1.slice(44, (blob1Size/duration)*position)

    if(blob1_data.size%2 != 0)
      blob1_data = new Blob([blob1_data, new Blob([0])], {type: 'audio/wav'})

    if(blob2_data.size%2 != 0)
      blob2_data = new Blob([blob2_data, new Blob([0])], {type: 'audio/wav'})

    let concatenated_blob = new Blob([blob1_data, blob2_data], {type: 'audio/wav'})

    if(concatenated_blob.size % 2 != 0)
      concatenated_blob = new Blob([concatenated_blob, new Blob([0])], {type: 'audio/wav'})

    let header = blob2.slice(0,44)

    let fr = new FileReader()
    fr.readAsArrayBuffer(header)

    fr.onload = () => {
      const view = new DataView(fr.result)
      view.setUint32(4, 36+concatenated_blob.size, true)
      view.setUint32(40, concatenated_blob.size, true)
      this.master_recording = new Blob([view, concatenated_blob], {type: 'audio/wav'})
      this.player.src = URL.createObjectURL(this.master_recording);
      callback(this.master_recording);
    }
  }

  setRecorder(cb) {
    try{
      window.AudioContext = window.AudioContext || window.webkitAudioContext;
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
      window.URL = window.URL || window.webkitURL;
    } catch(e){
      console.warn('No web audio support in this browser!');
      this.emit('error', 'No web audio support in this browser!')
    }

    const startUserMedia = (stream) => {
      const input = audio_context.createMediaStreamSource(stream);
      this.recorder = new Recorder(input, this.config);
      this.stream = stream;
      cb();
      window.s = stream;
    };

    navigator.getUserMedia({audio: true}, stream => startUserMedia(stream), (e) => {
      console.warn('No live audio input: ' + e);
      this.emit('error', 'No live audio input: ' + e);
    });
  }

  closeRecorder() {
    this.stream.getTracks()[0].stop();
    console.log(this.stream.getTracks())
  }
}
<commit_msg>method #isSupport has been added<commit_after>import Recorder from './Recorder';

const defaultConfig = {
  worker: null,
  workerPath: 'recordWorker'
};

const audio_context = new AudioContext();
export const events = {
  PLAY: 'play',
  PAUSE: 'pause',
  ENDED: 'ended',
  START_REC: 'startRecording',
  STOP_REC: 'stopRecording',
  PROGRESS: 'progress',
  REWIND: 'rewind',
  ERROR: 'error'
};

export default class Dictaphone {
  constructor(player, config) {
    this.config = Object.assign({}, defaultConfig, config);
    this.player = player;
    this.recorder = null;
    this.playing = false;
    this.recording = false;
    this.master_recording = null;
    this.progressBarStep = 0.1; // in sec;
    this.subscribers = {};
    this.supported = true;
  }

  isSupported() {
    return this.supported;
  }

  destroy() {
    this.subscribers = {};
    // todo remove media URL
  }

  on(message, callback) {
    if (!this.subscribers[message]) {
      this.subscribers[message] = [];
    }
    this.subscribers[message].push(callback);
  }

  emit(message, data) {
    if(!this.subscribers[message]) return;
    this.subscribers[message].forEach(e => e(data));
  }

  startRecording () {
    if (this.recording || this.playing) {
      return;
    }

    this.setRecorder(() => {
      this.recorder && this.recorder.record();
      this.recording = true;
      this.emit(events.START_REC, {position: this.player.currentTime});
    });
  }

  stopRecording() {
    const that = this;

    if (!this.recording) {
      return;
    }

    this.recorder && this.recorder.stop();
    this.recording = false;
    this._createMasterRecording(() => {
      setTimeout(() => {
        this.emit(events.STOP_REC, {duration: that.player.duration});
        this.closeRecorder();
      }, 200);
    });
    this.recorder.clear();
  }

  togglePlayback () {
    this.playing ? this.pause() : this.play();
  }

  play() {
    let _time = this.player.currentTime;

    if (_time >= this.player.duration) {
      return;
    }

    this.playing = true;
    this.emit(events.PLAY, {time: this.player.currentTime});
    this.player.play();

    const loop = setInterval(() => {
      if( this.playing && _time < this.player.duration ) {
        this.emit(events.PROGRESS, {time: this.player.currentTime, duration: this.player.duration});
        _time = _time + this.progressBarStep;
      } else {
        clearInterval(loop);
        this.playing = false;
        this.emit(events.PAUSE, {time: this.player.currentTime})
      }
    }, this.progressBarStep * 1000);
  }

  pause() {
    if (this.recording) {
      this.emit(events.ERROR, 'Protect to call pause while recording');
    }
    this.playing = false;
    this.player.pause();
    this.emit(events.PAUSE, {time: this.player.currentTime})
  }

  rewind(time) {
    let _time = time;

    if (this.recording || time < 0) {
      this.emit(events.ERROR, 'Protect to call rewind while recording');
      return;
    }

    this.playing && this.pause();

    if (time > this.player.duration) {
      _time = this.player.duration;
    }

    this.player.currentTime = _time;

    this.emit(events.REWIND, {toTime: _time});
  }

  rewindToBegin() {
    this.rewind(0);
  }

  rewindToEnd() {
    this.rewind(this.player.duration);
  }

  _createMasterRecording(callback) {
    const that = this;
    this.recorder && this.recorder.exportWAV((blob) => {
      if(that.master_recording){
        that._concatenateRecordings(that.master_recording, blob, (blob) => callback(blob));
      } else {
        that.master_recording = blob;
        that.player.src = URL.createObjectURL(that.master_recording);
        callback(blob);
      }
    });
  }

  _concatenateRecordings(blob1, blob2, callback) {
    const duration = this.player.duration;
    const position = this.player.currentTime;
    const blob1Size = blob1.size-44;
    let blob2_data = blob2.slice(44);
    let blob1_data = blob1.slice(44, (blob1Size/duration)*position)

    if(blob1_data.size%2 != 0)
      blob1_data = new Blob([blob1_data, new Blob([0])], {type: 'audio/wav'})

    if(blob2_data.size%2 != 0)
      blob2_data = new Blob([blob2_data, new Blob([0])], {type: 'audio/wav'})

    let concatenated_blob = new Blob([blob1_data, blob2_data], {type: 'audio/wav'})

    if(concatenated_blob.size % 2 != 0)
      concatenated_blob = new Blob([concatenated_blob, new Blob([0])], {type: 'audio/wav'})

    let header = blob2.slice(0,44)

    let fr = new FileReader()
    fr.readAsArrayBuffer(header)

    fr.onload = () => {
      const view = new DataView(fr.result)
      view.setUint32(4, 36+concatenated_blob.size, true)
      view.setUint32(40, concatenated_blob.size, true)
      this.master_recording = new Blob([view, concatenated_blob], {type: 'audio/wav'})
      this.player.src = URL.createObjectURL(this.master_recording);
      callback(this.master_recording);
    }
  }

  setRecorder(cb) {
    try{
      window.AudioContext = window.AudioContext || window.webkitAudioContext;
      navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
      window.URL = window.URL || window.webkitURL;
    } catch(e){
      console.warn('No web audio support in this browser!');
      this.emit('error', 'No web audio support in this browser!')
    }

    if (!window.AudioContext || !navigator.getUserMedia || !window.URL) {
      return this.supported = false;
    }

    const startUserMedia = (stream) => {
      const input = audio_context.createMediaStreamSource(stream);
      this.recorder = new Recorder(input, this.config);
      this.stream = stream;
      cb();
      window.s = stream;
    };

    navigator.getUserMedia({audio: true}, stream => startUserMedia(stream), (e) => {
      console.warn('No live audio input: ' + e);
      this.emit('error', 'No live audio input: ' + e);
    });
  }

  closeRecorder() {
    this.stream.getTracks()[0].stop();
    console.log(this.stream.getTracks())
  }
}
<|endoftext|>


<commit_before>import { Component, PropTypes } from 'react';

function dispatch(store, atom, action) {
  return store(atom, action);
}

export default class Dispatcher extends Component {
  static propTypes = {
    store: PropTypes.func.isRequired,
    children: PropTypes.func.isRequired
  };

  static childContextTypes = {
    redux: PropTypes.object.isRequired
  };

  getChildContext() {
    return { redux: this };
  }

  constructor(props, context) {
    super(props, context);

    this.subscriptions = [];
    this.emitChange = this.emitChange.bind(this);
    this.dispatch = this.dispatch.bind(this);

    const initialAtom = dispatch(props.store, undefined, {});
    this.setAtom(initialAtom);
  }

  dispatch(action) {
    const nextAtom = dispatch(this.props.store, this.atom, action);
    this.setAtom(nextAtom);
  }

  setAtom(atom) {
    this.atom = atom;
    if (this.state) {
      this.setState({ atom });
    } else {
      this.state = { atom };
    }
    this.emitChange();
  }

  subscribe(listener) {
    this.subscriptions.push(listener);
    listener(this.atom);

    return () => {
      const index = this.subscriptions.indexOf(listener);
      this.subscriptions.splice(index, 1);
    };
  }

  emitChange() {
    const { atom, subscriptions } = this;
    subscriptions.forEach(listener => listener(atom));
  }

  render() {
    const { children } = this.props;
    return children();
  }
}
<commit_msg>Remove atom from Dispatcher state<commit_after>import { PropTypes } from 'react';

function dispatch(store, atom, action) {
  return store(atom, action);
}

export default class Dispatcher {
  static propTypes = {
    store: PropTypes.func.isRequired,
    children: PropTypes.func.isRequired
  };

  static childContextTypes = {
    redux: PropTypes.object.isRequired
  };

  getChildContext() {
    return { redux: this };
  }

  constructor(props) {
    this.subscriptions = [];
    this.emitChange = this.emitChange.bind(this);
    this.dispatch = this.dispatch.bind(this);

    const initialAtom = dispatch(props.store, undefined, {});
    this.setAtom(initialAtom);
  }

  dispatch(action) {
    const nextAtom = dispatch(this.props.store, this.atom, action);
    this.setAtom(nextAtom);
  }

  setAtom(atom) {
    this.atom = atom;
    this.emitChange();
  }

  subscribe(listener) {
    this.subscriptions.push(listener);
    listener(this.atom);

    return () => {
      const index = this.subscriptions.indexOf(listener);
      this.subscriptions.splice(index, 1);
    };
  }

  emitChange() {
    const { atom, subscriptions } = this;
    subscriptions.forEach(listener => listener(atom));
  }

  render() {
    const { children } = this.props;
    return children();
  }
}
<|endoftext|>


<commit_before>
<commit_msg>Update DocTyp.min.js<commit_after>var DocTyp=function(e){function t(t,n){var o=document.createElement("article");o.setAttribute("class","doctyp"),o.innerHTML=n,t.parentNode.replaceChild(o,t),o.querySelectorAll("pre").length>0&&e.Syntax(o.querySelectorAll("pre"))}function n(n){var o=n.innerHTML;o=e.Header(o),o=e.Style(o),o=e.Rule(o),o=e.Quote(o),o=e.Code(o),o=e.List(o),o=e.Link(o),o=e.Image(o),o=e.Table(o),o=e.Clean(o),t(n,o)}function o(n){if(!(n.length>0))throw"The element is not defined or is not a DOM element.";for(var o=0;o<n.length;o++){var a=n[o],l=a.innerHTML;l=e.Header(l),l=e.Style(l),l=e.Rule(l),l=e.Quote(l),l=e.Code(l),l=e.List(l),l=e.Link(l),l=e.Image(l),l=e.Table(l),l=e.Clean(l),t(a,l)}}return e.Docify=function(t,a){if(void 0!==a?(e.theme=a.toLowerCase(),e.LoadStyle("Style/"+a.toLowerCase()+".css")):e.theme="light",t.nodeType&&1==t.nodeType)n(t);else{var l=document.querySelectorAll(t);o(l)}},e.LoadScript=function(e){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://doctyp.github.io/src/"+e,document.getElementsByTagName("head")[0].appendChild(t)},e.LoadStyle=function(e){var t=document.createElement("link");t.type="text/css",t.rel="stylesheet",t.href="https://doctyp.github.io/src/"+e,t.media="none",t.onload=function(){"all"!=t.media&&(t.media="all")},document.getElementsByTagName("head")[0].appendChild(t)},e}({});DocTyp.LoadScript("extension.js");
<|endoftext|>


<commit_before>'use strict'

const Store = require('orbit-db-store')
const EventIndex = require('./EventIndex')

// TODO: generalize the Iterator functions and spin to its own module

class EventStore extends Store {
  constructor(ipfs, id, dbname, options = {}) {
    if(options.Index === undefined) Object.assign(options, { Index: EventIndex })
    super(ipfs, id, dbname, options)
  }

  add(data) {
    return this._addOperation({
      op: 'ADD',
      key: null,
      value: data,
      meta: {
        ts: new Date().getTime()
      }
    })
  }

  get(hash) {
    return this.iterator({ gte: hash, limit: 1 }).collect()[0]
  }

  iterator(options) {
    const messages = this._query(options)
    let currentIndex = 0
    let iterator = {
      [Symbol.iterator]() {
        return this
      },
      next() {
        let item = { value: null, done: true }
        if(currentIndex < messages.length) {
          item = { value: messages[currentIndex], done: false }
          currentIndex ++
        }
        return item
      },
      collect: () => messages
    }

    return iterator
  }

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

    const amount = opts.limit ? (opts.limit > -1 ? opts.limit : this._index.get().length) : 1 // Return 1 if no limit is provided
    const events = this._index.get().slice()
    let result = []

    if(opts.gt || opts.gte) {
      // Greater than case
      result = this._read(events, opts.gt ? opts.gt : opts.gte, amount, opts.gte ? true : false)
    } else {
      // Lower than and lastN case, search latest first by reversing the sequence
      result = this._read(events.reverse(), opts.lt ? opts.lt : opts.lte, amount, opts.lte || !opts.lt).reverse()
    }

    return result
  }

  _read(ops, hash, amount, inclusive) {
    // Find the index of the gt/lt hash, or start from the beginning of the array if not found
    const index = ops.map((e) => e.hash).indexOf(hash)
    let startIndex = Math.max(index, 0)
    // If gte/lte is set, we include the given hash, if not, start from the next element
    startIndex += inclusive ? 0 : 1
    // Slice the array to its requested size
    const res = ops.slice(startIndex).slice(0, amount)
    return res
  }
}

module.exports = EventStore
<commit_msg>Remove timestamp<commit_after>'use strict'

const Store = require('orbit-db-store')
const EventIndex = require('./EventIndex')

// TODO: generalize the Iterator functions and spin to its own module

class EventStore extends Store {
  constructor(ipfs, id, dbname, options = {}) {
    if(options.Index === undefined) Object.assign(options, { Index: EventIndex })
    super(ipfs, id, dbname, options)
  }

  add(data) {
    return this._addOperation({
      op: 'ADD',
      key: null,
      value: data
    })
  }

  get(hash) {
    return this.iterator({ gte: hash, limit: 1 }).collect()[0]
  }

  iterator(options) {
    const messages = this._query(options)
    let currentIndex = 0
    let iterator = {
      [Symbol.iterator]() {
        return this
      },
      next() {
        let item = { value: null, done: true }
        if(currentIndex < messages.length) {
          item = { value: messages[currentIndex], done: false }
          currentIndex ++
        }
        return item
      },
      collect: () => messages
    }

    return iterator
  }

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

    const amount = opts.limit ? (opts.limit > -1 ? opts.limit : this._index.get().length) : 1 // Return 1 if no limit is provided
    const events = this._index.get().slice()
    let result = []

    if(opts.gt || opts.gte) {
      // Greater than case
      result = this._read(events, opts.gt ? opts.gt : opts.gte, amount, opts.gte ? true : false)
    } else {
      // Lower than and lastN case, search latest first by reversing the sequence
      result = this._read(events.reverse(), opts.lt ? opts.lt : opts.lte, amount, opts.lte || !opts.lt).reverse()
    }

    return result
  }

  _read(ops, hash, amount, inclusive) {
    // Find the index of the gt/lt hash, or start from the beginning of the array if not found
    const index = ops.map((e) => e.hash).indexOf(hash)
    let startIndex = Math.max(index, 0)
    // If gte/lte is set, we include the given hash, if not, start from the next element
    startIndex += inclusive ? 0 : 1
    // Slice the array to its requested size
    const res = ops.slice(startIndex).slice(0, amount)
    return res
  }
}

module.exports = EventStore
<|endoftext|>


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

angular
  .module('secondLead')

  .controller('DramasCtrl', [
    'DramaModel',
    'Gridster',
    'ListModel',
    'Restangular',
    'UserModel',
    function(DramaModel, Gridster, ListModel, Restangular, UserModel) {
    var ctrl = this;

    ctrl.items = DramaModel.getAll;
    ctrl.user = UserModel.currentUser();

    ctrl.userLists = ListModel.currentUserLists();
    ctrl.selectedList = {};

    ctrl.gridsterOpts = {
      columns: 6
    }
    ctrl.currentPage = 1;
    ctrl.pageSize = 30;
  }])

})();
<commit_msg>added more gridster options<commit_after>(function(){
'use strict';

angular
  .module('secondLead')

  .controller('DramasCtrl', [
    'DramaModel',
    'Gridster',
    'ListModel',
    'Restangular',
    'UserModel',
    function(DramaModel, Gridster, ListModel, Restangular, UserModel) {
    var ctrl = this;

    ctrl.items = DramaModel.getAll;
    ctrl.user = UserModel.currentUser();

    ctrl.userLists = ListModel.currentUserLists();
    ctrl.selectedList = {};

    ctrl.gridsterOpts = {
        columns: 4, // the width of the grid, in columns
        pushing: false, // whether to push other items out of the way on move or resize
        floating: false, // whether to automatically float items up so they stack (you can temporarily disable if you are adding unsorted items with ng-repeat)
        swapping: false, // whether or not to have items of the same size switch places instead of pushing down if they are the same size
        width: 'auto', // can be an integer or 'auto'. 'auto' scales gridster to be the full width of its containing element
        colWidth: 'auto', // can be an integer or 'auto'.  'auto' uses the pixel width of the element divided by 'columns'
        rowHeight: 'match', // can be an integer or 'match'.  Match uses the colWidth, giving you square widgets.
        margins: [5, 5], // the pixel distance between each widget
        outerMargin: true, // whether margins apply to outer edges of the grid
        isMobile: false, // stacks the grid items if true
        mobileBreakPoint: 750, // if the screen is not wider that this, remove the grid layout and stack the items
        mobileModeEnabled: true, // whether or not to toggle mobile mode when screen width is less than mobileBreakPoint
        minColumns: 1, // the minimum columns the grid must have
        minRows: 2, // the minimum height of the grid, in rows
        maxRows: 100,
        defaultSizeX: 1, // the default width of a gridster item, if not specifed
        defaultSizeY: 1, // the default height of a gridster item, if not specified
        minSizeX: 1, // minimum column width of an item
        maxSizeX: null, // maximum column width of an item
        minSizeY: 1, // minumum row height of an item
        maxSizeY: null, // maximum row height of an item
        resizable: {
           enabled: false
        },
        draggable: {
           enabled: false
        }
    };
    ctrl.currentPage = 1;
    ctrl.pageSize = 32;
  }])

})();
<|endoftext|>


<commit_before>/**
 * The CountrySelectionView view.
 *
 * @return CountrySelectionView view (extends Backbone.View)
 */
define([
  'underscore',
  'handlebars',
  'mps',
  'map/services/LayerSpecService',
  'map/services/CountryService',
  'text!connect/templates/countrySelection.handlebars',
  'text!connect/templates/layerSelection.handlebars',
], function(_, Handlebars, mps, LayerSpecService, CountryService, countryTpl, layerTpl) {

  'use strict';

  var CountrySelectionView = Backbone.View.extend({
    model: new (Backbone.Model.extend({
      country: null,
      layers: null,
    })),

    el: '#layer-selection',

    templateCountries: Handlebars.compile(countryTpl),
    templateLayers: Handlebars.compile(layerTpl),

    events: {
      'change .js-select-country' : 'onChangeCountry',
      'change .js-select-layer' : 'onChangeLayer',
    },

    initialize: function(map) {
      if (!this.$el.length) {
        return;
      }

      this.map = map;
      this.cache();
      this.listeners();

      // Load global layers
      LayerSpecService._getAllLayers(
        // Filter
        function(layer){
          return !layer.iso && !!layer.analyzable;
        }.bind(this),

        // Success
        function(layers){
          this.layers = _.groupBy(_.sortBy(layers, 'title'), 'category_name');
          this.renderLayers();
        }.bind(this),

        // Error
        function(error){
          console.log(error);
        }.bind(this)
      );

      // Load countries
      CountryService.get()
        .then(function(results) {
          this.countries = results.countries;
          this.renderCountries();
          this.renderCountryLayers();
        }.bind(this))

        .error(function(error) {
          console.log(error);
        }.bind(this))
    },

    listeners: function() {
      // We should start using listenTo and handle the remove views
      this.model.on('change:country', this.changeCountry.bind(this));
      this.model.on('change:layers', this.changeLayers.bind(this));
    },

    cache: function() {
      this.$layersField = this.$el.find('#layers-field');
      this.$layersCountryField = this.$el.find('#layers-country-field');
      this.$countryField = this.$el.find('#country-field');
    },

    /**
     * CHANGE EVENTS
    */
    changeCountry: function() {
      var country = this.model.get('country');

      LayerSpecService._getAllLayers(
        // Filter
        function(layer){
          return layer.iso == country && !!layer.analyzable;
        }.bind(this),

        // Success
        function(layers){
          this.countryLayers = _.groupBy(_.sortBy(layers, 'title'), 'category_name');
          this.renderCountryLayers();
        }.bind(this),

        // Error
        function(error){
          console.log(error);
        }.bind(this)
      );

    },

    changeLayers: function() {
      var layers = this.model.get('layers');
      var where = [{ slug: layers[0] }];

      LayerSpecService._removeAllLayers();

      LayerSpecService.toggle(where,
        function(layerSpec) {
          mps.publish('LayerNav/change', [layerSpec]);
          mps.publish('Place/update', [{go: false}]);
        }.bind(this));
    },

    /**
     * RENDERS
    */
    renderCountries: function() {
      this.$countryField.html(this.templateCountries({
        name: 'Country layers',
        placeholder: 'Select a country',
        countries: this.countries
      }));
      this.renderChosen();
    },

    renderLayers: function() {
      this.$layersField.html(this.templateLayers({
        name: 'Global layers',
        placeholder: 'Select a global layer',
        layers: this.layers
      }));
      this.renderChosen();
    },

    renderCountryLayers: function() {
      this.$layersCountryField.html(this.templateLayers({
        name: '',
        placeholder: 'Select a country layer',
        layers: (!_.isEmpty(this.countryLayers)) ? this.countryLayers : null
      }));
      this.renderChosen();
    },

    renderChosen: function() {
      _.each(this.$el.find('select'), function(select){
        var $select = $(select);
        if (! !!$select.data('chosen')) {
          $select.chosen({
            width: '100%',
            disable_search: true,
            inherit_select_classes: true,
            no_results_text: "Oops, nothing found!"
          });
        }
      });
    },

    /**
     * UI EVENTS
     * - onChangeCountry
     * - onChangeLayer
    */
    onChangeCountry: function(e) {
      e && e.preventDefault();
      var country = $(e.currentTarget).val();
      this.model.set({
        country: country,
      });
    },

    onChangeLayer: function(e) {
      e && e.preventDefault();
      var layers = [$(e.currentTarget).val()];
      this.model.set({
        layers: _.clone(layers)
      });
    }
  });

  return CountrySelectionView;

});
<commit_msg>Subscription: filter countries. Show only the ones that have layers<commit_after>/**
 * The CountrySelectionView view.
 *
 * @return CountrySelectionView view (extends Backbone.View)
 */
define([
  'underscore',
  'handlebars',
  'mps',
  'map/services/LayerSpecService',
  'map/services/CountryService',
  'text!connect/templates/countrySelection.handlebars',
  'text!connect/templates/layerSelection.handlebars',
], function(_, Handlebars, mps, LayerSpecService, CountryService, countryTpl, layerTpl) {

  'use strict';

  var CountrySelectionView = Backbone.View.extend({
    model: new (Backbone.Model.extend({
      country: null,
      layers: null,
    })),

    el: '#layer-selection',

    templateCountries: Handlebars.compile(countryTpl),
    templateLayers: Handlebars.compile(layerTpl),

    events: {
      'change .js-select-country' : 'onChangeCountry',
      'change .js-select-layer' : 'onChangeLayer',
    },

    initialize: function(map) {
      if (!this.$el.length) {
        return;
      }

      this.map = map;
      this.cache();
      this.listeners();

      // Load global layers
      LayerSpecService._getAllLayers(
        // Filter
        function(layer){
          return !layer.iso && !!layer.analyzable;
        }.bind(this),

        // Success
        function(layers){
          this.layers = _.groupBy(_.sortBy(layers, 'title'), 'category_name');
          this.renderLayers();
        }.bind(this),

        // Error
        function(error){
          console.log(error);
        }.bind(this)
      );

      // Load countries
      CountryService.get()
        .then(function(results) {
          this.countries = results.countries;
          this.renderCountries();
          this.renderCountryLayers();
        }.bind(this))

        .error(function(error) {
          console.log(error);
        }.bind(this))
    },

    listeners: function() {
      // We should start using listenTo and handle the remove views
      this.model.on('change:country', this.changeCountry.bind(this));
      this.model.on('change:layers', this.changeLayers.bind(this));
    },

    cache: function() {
      this.$layersField = this.$el.find('#layers-field');
      this.$layersCountryField = this.$el.find('#layers-country-field');
      this.$countryField = this.$el.find('#country-field');
    },

    /**
     * CHANGE EVENTS
    */
    changeCountry: function() {
      var country = this.model.get('country');

      LayerSpecService._getAllLayers(
        // Filter
        function(layer){
          return layer.iso == country && !!layer.analyzable;
        }.bind(this),

        // Success
        function(layers){
          this.countryLayers = _.groupBy(_.sortBy(layers, 'title'), 'category_name');
          this.renderCountryLayers();
        }.bind(this),

        // Error
        function(error){
          console.log(error);
        }.bind(this)
      );

    },

    changeLayers: function() {
      var layers = this.model.get('layers');
      var where = [{ slug: layers[0] }];

      LayerSpecService._removeAllLayers();

      LayerSpecService.toggle(where,
        function(layerSpec) {
          mps.publish('LayerNav/change', [layerSpec]);
          mps.publish('Place/update', [{go: false}]);
        }.bind(this));
    },

    /**
     * RENDERS
    */
    renderCountries: function() {
      // Filter to show only the countries that have layers
      LayerSpecService._getAllLayers(
        // Filter
        function(layer){
          return !!layer.iso && !!layer.analyzable;
        }.bind(this),

        // Success
        function(layers){
          var isos = _.uniq(_.pluck(layers, 'iso'));

          this.$countryField.html(this.templateCountries({
            name: 'Country layers',
            placeholder: 'Select a country',
            countries: _.filter(this.countries, function(country) {
              return (isos.indexOf(country.iso) != -1)
            })
          }));
          this.renderChosen();

        }.bind(this),

        // Error
        function(error){
          console.log(error);
        }.bind(this)
      );
    },

    renderLayers: function() {
      this.$layersField.html(this.templateLayers({
        name: 'Global layers',
        placeholder: 'Select a global layer',
        layers: this.layers
      }));
      this.renderChosen();
    },

    renderCountryLayers: function() {
      this.$layersCountryField.html(this.templateLayers({
        name: '',
        placeholder: 'Select a country layer',
        layers: (!_.isEmpty(this.countryLayers)) ? this.countryLayers : null
      }));
      this.renderChosen();
    },

    renderChosen: function() {
      _.each(this.$el.find('select'), function(select){
        var $select = $(select);
        if (! !!$select.data('chosen')) {
          $select.chosen({
            width: '100%',
            disable_search: true,
            inherit_select_classes: true,
            no_results_text: "Oops, nothing found!"
          });
        }
      });
    },

    /**
     * UI EVENTS
     * - onChangeCountry
     * - onChangeLayer
    */
    onChangeCountry: function(e) {
      e && e.preventDefault();
      var country = $(e.currentTarget).val();
      this.model.set({
        country: country,
      });
    },

    onChangeLayer: function(e) {
      e && e.preventDefault();
      var layers = [$(e.currentTarget).val()];
      this.model.set({
        layers: _.clone(layers)
      });
    }
  });

  return CountrySelectionView;

});
<|endoftext|>


<commit_before>import { Component, PropTypes, createElement } from 'react'
import invariant from 'invariant'
import createConnectedFieldArray from './ConnectedFieldArray'
import prefixName from './util/prefixName'

const toArray = value => Array.isArray(value) ? value : [ value ]

const wrapError = (fn, key) => fn && ((...args) => {
  const validators = toArray(fn)
  for (let i = 0; i < validators.length; i++) {
    const result = validators[i](...args)
    if (result) {
      return { [key]: result }
    }
  }
})

const createFieldArray = ({ deepEqual, getIn, size }) => {

  const ConnectedFieldArray = createConnectedFieldArray({ deepEqual, getIn, size })

  class FieldArray extends Component {
    constructor(props, context) {
      super(props, context)
      if (!context._reduxForm) {
        throw new Error('FieldArray must be inside a component decorated with reduxForm()')
      }
    }

    componentWillMount() {
      this.context._reduxForm.register(
        this.name,
        'FieldArray',
        () => wrapError(this.props.validate, '_error'),
        () => wrapError(this.props.warn, '_warning')
      )
    }

    componentWillReceiveProps(nextProps) {
      if (this.props.name !== nextProps.name) {
        // unregister old name
        this.context._reduxForm.unregister(this.name)
        // register new name
        this.context._reduxForm.register(prefixName(this.context, nextProps.name), 'FieldArray')
      }
    }

    componentWillUnmount() {
      this.context._reduxForm.unregister(this.name)
    }

    get name() {
      return prefixName(this.context, this.props.name)
    }

    get dirty() {
      return this.refs.connected.getWrappedInstance().dirty
    }

    get pristine() {
      return this.refs.connected.getWrappedInstance().pristine
    }

    get value() {
      return this.refs.connected.getWrappedInstance().value
    }

    getRenderedComponent() {
      invariant(this.props.withRef,
        'If you want to access getRenderedComponent(), ' +
        'you must specify a withRef prop to FieldArray')
      return this.refs.connected.getWrappedInstance().getRenderedComponent()
    }

    render() {
      return createElement(ConnectedFieldArray, {
        ...this.props,
        name: this.name,
        syncError: this.syncError,
        syncWarning: this.syncWarning,
        _reduxForm: this.context._reduxForm,
        ref: 'connected'
      })
    }
  }

  FieldArray.propTypes = {
    name: PropTypes.string.isRequired,
    component: PropTypes.func.isRequired,
    props: PropTypes.object,
    validate: PropTypes.func,
    warn: PropTypes.func,
    withRef: PropTypes.bool
  }
  FieldArray.contextTypes = {
    _reduxForm: PropTypes.object
  }

  return FieldArray
}

export default createFieldArray
<commit_msg>Fixed FieldArray validate and warn propTypes (#2775)<commit_after>import { Component, PropTypes, createElement } from 'react'
import invariant from 'invariant'
import createConnectedFieldArray from './ConnectedFieldArray'
import prefixName from './util/prefixName'

const toArray = value => Array.isArray(value) ? value : [ value ]

const wrapError = (fn, key) => fn && ((...args) => {
  const validators = toArray(fn)
  for (let i = 0; i < validators.length; i++) {
    const result = validators[i](...args)
    if (result) {
      return { [key]: result }
    }
  }
})

const createFieldArray = ({ deepEqual, getIn, size }) => {

  const ConnectedFieldArray = createConnectedFieldArray({ deepEqual, getIn, size })

  class FieldArray extends Component {
    constructor(props, context) {
      super(props, context)
      if (!context._reduxForm) {
        throw new Error('FieldArray must be inside a component decorated with reduxForm()')
      }
    }

    componentWillMount() {
      this.context._reduxForm.register(
        this.name,
        'FieldArray',
        () => wrapError(this.props.validate, '_error'),
        () => wrapError(this.props.warn, '_warning')
      )
    }

    componentWillReceiveProps(nextProps) {
      if (this.props.name !== nextProps.name) {
        // unregister old name
        this.context._reduxForm.unregister(this.name)
        // register new name
        this.context._reduxForm.register(prefixName(this.context, nextProps.name), 'FieldArray')
      }
    }

    componentWillUnmount() {
      this.context._reduxForm.unregister(this.name)
    }

    get name() {
      return prefixName(this.context, this.props.name)
    }

    get dirty() {
      return this.refs.connected.getWrappedInstance().dirty
    }

    get pristine() {
      return this.refs.connected.getWrappedInstance().pristine
    }

    get value() {
      return this.refs.connected.getWrappedInstance().value
    }

    getRenderedComponent() {
      invariant(this.props.withRef,
        'If you want to access getRenderedComponent(), ' +
        'you must specify a withRef prop to FieldArray')
      return this.refs.connected.getWrappedInstance().getRenderedComponent()
    }

    render() {
      return createElement(ConnectedFieldArray, {
        ...this.props,
        name: this.name,
        syncError: this.syncError,
        syncWarning: this.syncWarning,
        _reduxForm: this.context._reduxForm,
        ref: 'connected'
      })
    }
  }

  FieldArray.propTypes = {
    name: PropTypes.string.isRequired,
    component: PropTypes.func.isRequired,
    props: PropTypes.object,
    validate: PropTypes.oneOfType([ PropTypes.func, PropTypes.arrayOf(PropTypes.func) ]),
    warn: PropTypes.oneOfType([ PropTypes.func, PropTypes.arrayOf(PropTypes.func) ]),
    withRef: PropTypes.bool
  }
  FieldArray.contextTypes = {
    _reduxForm: PropTypes.object
  }

  return FieldArray
}

export default createFieldArray
<|endoftext|>


<commit_before>import { setting } from 'discourse/lib/computed';
import logout from 'discourse/lib/logout';
import showModal from 'discourse/lib/show-modal';
import OpenComposer from "discourse/mixins/open-composer";
import Category from 'discourse/models/category';

function unlessReadOnly(method, message) {
  return function() {
    if (this.site.get("isReadOnly")) {
      bootbox.alert(message);
    } else {
      this[method]();
    }
  };
}

const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
  siteTitle: setting('title'),

  actions: {

    logout: unlessReadOnly('_handleLogout', I18n.t("read_only_mode.logout_disabled")),

    _handleLogout() {
      if (this.currentUser) {
        this.currentUser.destroySession().then(() => logout(this.siteSettings, this.keyValueStore));
      }
    },

    _collectTitleTokens(tokens) {
      tokens.push(this.get('siteTitle'));
      Discourse.set('_docTitle', tokens.join(' - '));
    },

    // Ember doesn't provider a router `willTransition` event so let's make one
    willTransition() {
      var router = this.container.lookup('router:main');
      Ember.run.once(router, router.trigger, 'willTransition');
      return this._super();
    },

    showTopicEntrance(data) {
      this.controllerFor('topic-entrance').send('show', data);
    },

    postWasEnqueued(details) {
      const title = details.reason ? 'queue_reason.' + details.reason + '.title' : 'queue.approval.title';
      showModal('post-enqueued', {model: details, title });
    },

    composePrivateMessage(user, post) {

      const recipient = user ? user.get('username') : '',
          reply = post ? window.location.protocol + "//" + window.location.host + post.get("url") : null;

      // used only once, one less dependency
      const Composer = require('discourse/models/composer').default;
      return this.controllerFor('composer').open({
        action: Composer.PRIVATE_MESSAGE,
        usernames: recipient,
        archetypeId: 'private_message',
        draftKey: 'new_private_message',
        reply: reply
      });
    },

    error(err, transition) {
      let xhr = {};
      if (err.jqXHR) {
        xhr = err.jqXHR;
      }

      const xhrOrErr = err.jqXHR ? xhr : err;

      const exceptionController = this.controllerFor('exception');

      const c = window.console;
      if (c && c.error) {
        c.error(xhrOrErr);
      }

      exceptionController.setProperties({ lastTransition: transition, thrown: xhrOrErr });

      this.intermediateTransitionTo('exception');
      return true;
    },

    showLogin: unlessReadOnly('handleShowLogin', I18n.t("read_only_mode.login_disabled")),

    showCreateAccount: unlessReadOnly('handleShowCreateAccount', I18n.t("read_only_mode.login_disabled")),

    showForgotPassword() {
      showModal('forgotPassword', { title: 'forgot_password.title' });
    },

    showNotActivated(props) {
      showModal('not-activated', {title: 'log_in' }).setProperties(props);
    },

    showUploadSelector(toolbarEvent) {
      showModal('uploadSelector').setProperties({ toolbarEvent, imageUrl: null, imageLink: null });
    },

    showKeyboardShortcutsHelp() {
      showModal('keyboard-shortcuts-help', { title: 'keyboard_shortcuts_help.title'});
    },

    // Close the current modal, and destroy its state.
    closeModal() {
      this.render('hide-modal', { into: 'modal', outlet: 'modalBody' });
    },

    /**
      Hide the modal, but keep it with all its state so that it can be shown again later.
      This is useful if you want to prompt for confirmation. hideModal, ask "Are you sure?",
      user clicks "No", reopenModal. If user clicks "Yes", be sure to call closeModal.
    **/
    hideModal() {
      $('#discourse-modal').modal('hide');
    },

    reopenModal() {
      $('#discourse-modal').modal('show');
    },

    editCategory(category) {
      Category.reloadById(category.get('id')).then((atts) => {
        const model = this.store.createRecord('category', atts.category);
        model.setupGroupsAndPermissions();
        this.site.updateCategory(model);
        showModal('editCategory', { model });
        this.controllerFor('editCategory').set('selectedTab', 'general');
      });
    },

    deleteSpammer(user) {
      this.send('closeModal');
      user.deleteAsSpammer(function() { window.location.reload(); });
    },

    checkEmail(user) {
      user.checkEmail();
    },

    changeBulkTemplate(w) {
      const controllerName = w.replace('modal/', ''),
            factory = this.container.lookupFactory('controller:' + controllerName);

      this.render(w, {into: 'modal/topic-bulk-actions', outlet: 'bulkOutlet', controller: factory ? controllerName : 'topic-bulk-actions'});
    },

    createNewTopicViaParams(title, body, category_id, category) {
      this.openComposerWithTopicParams(this.controllerFor('discovery/topics'), title, body, category_id, category);
    },

    createNewMessageViaParams(username, title, body) {
      this.openComposerWithMessageParams(username, title, body);
    }
  },

  activate() {
    this._super();
    Em.run.next(function() {
      // Support for callbacks once the application has activated
      ApplicationRoute.trigger('activate');
    });
  },

  handleShowLogin() {
    if (this.siteSettings.enable_sso) {
      const returnPath = encodeURIComponent(window.location.pathname);
      window.location = Discourse.getURL('/session/sso?return_path=' + returnPath);
    } else {
      this._autoLogin('login', 'login-modal', () => this.controllerFor('login').resetForm());
    }
  },

  handleShowCreateAccount() {
    if (this.siteSettings.enable_sso) {
      const returnPath = encodeURIComponent(window.location.pathname);
      window.location = Discourse.getURL('/session/sso?return_path=' + returnPath);
    } else {
      this._autoLogin('createAccount', 'create-account');
    }
  },

  _autoLogin(modal, modalClass, notAuto) {
    const methods = Em.get('Discourse.LoginMethod.all');
    if (!this.siteSettings.enable_local_logins && methods.length === 1) {
      this.controllerFor('login').send('externalLogin', methods[0]);
    } else {
      showModal(modal);
      this.controllerFor('modal').set('modalClass', modalClass);
      if (notAuto) { notAuto(); }
    }
  },

});

RSVP.EventTarget.mixin(ApplicationRoute);
export default ApplicationRoute;
<commit_msg>FIX: logout not working<commit_after>import { setting } from 'discourse/lib/computed';
import logout from 'discourse/lib/logout';
import showModal from 'discourse/lib/show-modal';
import OpenComposer from "discourse/mixins/open-composer";
import Category from 'discourse/models/category';

function unlessReadOnly(method, message) {
  return function() {
    if (this.site.get("isReadOnly")) {
      bootbox.alert(message);
    } else {
      this[method]();
    }
  };
}

const ApplicationRoute = Discourse.Route.extend(OpenComposer, {
  siteTitle: setting('title'),

  _handleLogout() {
    if (this.currentUser) {
      this.currentUser.destroySession().then(() => logout(this.siteSettings, this.keyValueStore));
    }
  },

  actions: {

    logout: unlessReadOnly('_handleLogout', I18n.t("read_only_mode.logout_disabled")),

    _collectTitleTokens(tokens) {
      tokens.push(this.get('siteTitle'));
      Discourse.set('_docTitle', tokens.join(' - '));
    },

    // Ember doesn't provider a router `willTransition` event so let's make one
    willTransition() {
      var router = this.container.lookup('router:main');
      Ember.run.once(router, router.trigger, 'willTransition');
      return this._super();
    },

    showTopicEntrance(data) {
      this.controllerFor('topic-entrance').send('show', data);
    },

    postWasEnqueued(details) {
      const title = details.reason ? 'queue_reason.' + details.reason + '.title' : 'queue.approval.title';
      showModal('post-enqueued', {model: details, title });
    },

    composePrivateMessage(user, post) {

      const recipient = user ? user.get('username') : '',
          reply = post ? window.location.protocol + "//" + window.location.host + post.get("url") : null;

      // used only once, one less dependency
      const Composer = require('discourse/models/composer').default;
      return this.controllerFor('composer').open({
        action: Composer.PRIVATE_MESSAGE,
        usernames: recipient,
        archetypeId: 'private_message',
        draftKey: 'new_private_message',
        reply: reply
      });
    },

    error(err, transition) {
      let xhr = {};
      if (err.jqXHR) {
        xhr = err.jqXHR;
      }

      const xhrOrErr = err.jqXHR ? xhr : err;

      const exceptionController = this.controllerFor('exception');

      const c = window.console;
      if (c && c.error) {
        c.error(xhrOrErr);
      }

      exceptionController.setProperties({ lastTransition: transition, thrown: xhrOrErr });

      this.intermediateTransitionTo('exception');
      return true;
    },

    showLogin: unlessReadOnly('handleShowLogin', I18n.t("read_only_mode.login_disabled")),

    showCreateAccount: unlessReadOnly('handleShowCreateAccount', I18n.t("read_only_mode.login_disabled")),

    showForgotPassword() {
      showModal('forgotPassword', { title: 'forgot_password.title' });
    },

    showNotActivated(props) {
      showModal('not-activated', {title: 'log_in' }).setProperties(props);
    },

    showUploadSelector(toolbarEvent) {
      showModal('uploadSelector').setProperties({ toolbarEvent, imageUrl: null, imageLink: null });
    },

    showKeyboardShortcutsHelp() {
      showModal('keyboard-shortcuts-help', { title: 'keyboard_shortcuts_help.title'});
    },

    // Close the current modal, and destroy its state.
    closeModal() {
      this.render('hide-modal', { into: 'modal', outlet: 'modalBody' });
    },

    /**
      Hide the modal, but keep it with all its state so that it can be shown again later.
      This is useful if you want to prompt for confirmation. hideModal, ask "Are you sure?",
      user clicks "No", reopenModal. If user clicks "Yes", be sure to call closeModal.
    **/
    hideModal() {
      $('#discourse-modal').modal('hide');
    },

    reopenModal() {
      $('#discourse-modal').modal('show');
    },

    editCategory(category) {
      Category.reloadById(category.get('id')).then((atts) => {
        const model = this.store.createRecord('category', atts.category);
        model.setupGroupsAndPermissions();
        this.site.updateCategory(model);
        showModal('editCategory', { model });
        this.controllerFor('editCategory').set('selectedTab', 'general');
      });
    },

    deleteSpammer(user) {
      this.send('closeModal');
      user.deleteAsSpammer(function() { window.location.reload(); });
    },

    checkEmail(user) {
      user.checkEmail();
    },

    changeBulkTemplate(w) {
      const controllerName = w.replace('modal/', ''),
            factory = this.container.lookupFactory('controller:' + controllerName);

      this.render(w, {into: 'modal/topic-bulk-actions', outlet: 'bulkOutlet', controller: factory ? controllerName : 'topic-bulk-actions'});
    },

    createNewTopicViaParams(title, body, category_id, category) {
      this.openComposerWithTopicParams(this.controllerFor('discovery/topics'), title, body, category_id, category);
    },

    createNewMessageViaParams(username, title, body) {
      this.openComposerWithMessageParams(username, title, body);
    }
  },

  activate() {
    this._super();
    Em.run.next(function() {
      // Support for callbacks once the application has activated
      ApplicationRoute.trigger('activate');
    });
  },

  handleShowLogin() {
    if (this.siteSettings.enable_sso) {
      const returnPath = encodeURIComponent(window.location.pathname);
      window.location = Discourse.getURL('/session/sso?return_path=' + returnPath);
    } else {
      this._autoLogin('login', 'login-modal', () => this.controllerFor('login').resetForm());
    }
  },

  handleShowCreateAccount() {
    if (this.siteSettings.enable_sso) {
      const returnPath = encodeURIComponent(window.location.pathname);
      window.location = Discourse.getURL('/session/sso?return_path=' + returnPath);
    } else {
      this._autoLogin('createAccount', 'create-account');
    }
  },

  _autoLogin(modal, modalClass, notAuto) {
    const methods = Em.get('Discourse.LoginMethod.all');
    if (!this.siteSettings.enable_local_logins && methods.length === 1) {
      this.controllerFor('login').send('externalLogin', methods[0]);
    } else {
      showModal(modal);
      this.controllerFor('modal').set('modalClass', modalClass);
      if (notAuto) { notAuto(); }
    }
  },

});

RSVP.EventTarget.mixin(ApplicationRoute);
export default ApplicationRoute;
<|endoftext|>


<commit_before>moj.Modules.ReAllocation = {
  $CheckedClaimIdTemplate: $('<input type="hidden" name="allocation[claim_ids][]">'),
  $form: $('#new_allocation'),

  init: function (){
    var self = this;

    //Only work on the re-allocation page
    if($('.js-reallocation-report').length > 0){
      $('.report').on('change', ':checkbox', function (){
        var $element = $(this);

        if($element.is(':checked')){
          self.addCheckedClaim($element.val());
        }else{
          //TODO investigate why this was needed?
          self.removeUnCheckedClaim($element.val());
        }
      });
    }
  },

  addCheckedClaim: function (claim_id){
    var $clonedElement = this.$CheckedClaimIdTemplate.clone();
    var id = 'allocation_claim_ids_' + claim_id;

    $clonedElement
      .attr('id', id)
      .val(claim_id);

    //Add the new element to the form
    this.$form.append($clonedElement);
  },

  removeUnCheckedClaim: function (claim_id){
    var $form = this.$form;

    $form
      .find('#allocation_claim_ids_' + claim_id)
      .remove();
  }

};
<commit_msg>Add show/hide case worker select list based on what allocation option the user selected<commit_after>moj.Modules.ReAllocation = {
  $CheckedClaimIdTemplate: $('<input type="hidden" name="allocation[claim_ids][]">'),
  $form: $('#new_allocation'),
  $ReAllocationRadioButtons: $('.js-re-allocation-options'),
  $CaseWorkerList: $('.js-case-worker-list'),

  init: function (){
    var self = this;

    //Only work on the re-allocation page
    if($('.js-re-allocation-page').length > 0){

      //Show/Hide Case Workers select lists
      self.showHideCaseWorkersList();

      this.$ReAllocationRadioButtons.on('change', ':radio', function(){
        self.showHideCaseWorkersList();
      });

      //Selecting claims to be re-allocated functionality
      $('.report').on('change', ':checkbox', function (){
        var $element = $(this);

        if($element.is(':checked')){
          self.addCheckedClaim($element.val());
        }else{
          //TODO investigate why this was needed?
          self.removeUnCheckedClaim($element.val());
        }
      });
    }
  },

  showHideCaseWorkersList: function(){
    if(this.$ReAllocationRadioButtons.find(':checked').val() === 'false' ){
      this.$CaseWorkerList.slideDown();
    }else{
      this.$CaseWorkerList.slideUp();
    }
  },

  addCheckedClaim: function (claim_id){
    var $clonedElement = this.$CheckedClaimIdTemplate.clone();
    var id = 'allocation_claim_ids_' + claim_id;

    $clonedElement
      .attr('id', id)
      .val(claim_id);

    //Add the new element to the form
    this.$form.append($clonedElement);
  },

  removeUnCheckedClaim: function (claim_id){
    var $form = this.$form;

    $form
      .find('#allocation_claim_ids_' + claim_id)
      .remove();
  }

};
<|endoftext|>


<commit_before>/* global Vue, gl */
/* eslint-disable no-param-reassign */
((gl) => {
  gl.VueTimeAgo = Vue.extend({
    props: [
      'pipeline',
    ],
    computed: {
      localTimeFinished() {
        return gl.utils.formatDate(this.pipeline.details.finished_at);
      },
    },
    methods: {
      formatSection(section) {
        if (`${section}`.split('').length <= 1) return `0${section}`;
        return `${section}`;
      },
      hours(date) {
        return this.formatSection(date.getHours());
      },
      minutes(date) {
        return this.formatSection(date.getMinutes());
      },
      seconds(date) {
        return this.formatSection(date.getSeconds());
      },
      finishdate() {
        const date = new Date(
          new Date(
            this.pipeline.details.finished_at
          ).getTime() - new Date(
            this.pipeline.created_at
          ).getTime()
        );
        return (
          `${this.hours(date)}:${this.minutes(date)}:${this.seconds(date)}`
        );
      },
      runningdate() {
        const date = new Date(
          new Date().getTime() - new Date(this.pipeline.created_at).getTime()
        );
        return (
          `${this.hours(date)}:${this.minutes(date)}:${this.seconds(date)}`
        );
      },
      timeStopped() {
        const options = {
          weekday: 'long',
          year: 'numeric',
          month: 'short',
          day: 'numeric',
        };

        options.timeZoneName = 'short';

        const finished = this.pipeline.details.finished_at;

        if (!finished) return false;

        return {
          words: gl.utils.getTimeago().format(finished),
        };
      },
      duration() {
        // if (this.timeStopped()) return this.finishdate();
        // return this.runningdate();
        const { duration } = this.pipeline.details;
        if (duration === 0) return '00:00:00';
        if (duration !== null) return duration;
        return false;
      },
    },
    template: `

          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="40"
            height="40"
            viewBox="0 0 40 40"
          >
            <g fill="#8F8F8F" fill-rule="evenodd">
              <path d="M29.513 10.134A15.922 15.922 0 0 0 23 7.28V6h2.993C26.55 6 27 5.552 27 5V2a1 1 0 0 0-1.007-1H14.007C13.45 1 13 1.448 13 2v3a1 1 0 0 0 1.007 1H17v1.28C9.597 8.686 4 15.19 4 23c0 8.837 7.163 16 16 16s16-7.163 16-16c0-3.461-1.099-6.665-2.967-9.283l1.327-1.58a2.498 2.498 0 0 0-.303-3.53 2.499 2.499 0 0 0-3.528.315l-1.016 1.212zM20 34c6.075 0 11-4.925 11-11s-4.925-11-11-11S9 16.925 9 23s4.925 11 11 11z"></path><path d="M19 21h-4.002c-.552 0-.998.452-.998 1.01v1.98c0 .567.447 1.01.998 1.01h7.004c.274 0 .521-.111.701-.291a.979.979 0 0 0 .297-.704v-8.01c0-.54-.452-.995-1.01-.995h-1.98a.997.997 0 0 0-1.01.995V21z"></path>
            </g>
          </svg>
          {{duration()}}

          <time
            data-toggle="tooltip"
            data-placement="top"
            data-container="body"
            :data-original-title='localTimeFinished'
          >
            {{timeStopped().words}}
          </time>

    `,
  });
})(window.gl || (window.gl = {}));
<commit_msg>clean up on time_ago [ci skip]<commit_after>/* global Vue, gl */
/* eslint-disable no-param-reassign */
((gl) => {
  gl.VueTimeAgo = Vue.extend({
    props: [
      'pipeline',
    ],
    computed: {
      localTimeFinished() {
        return gl.utils.formatDate(this.pipeline.details.finished_at);
      },
    },
    methods: {
      timeStopped() {
        const options = {
          weekday: 'long',
          year: 'numeric',
          month: 'short',
          day: 'numeric',
        };

        options.timeZoneName = 'short';

        const finished = this.pipeline.details.finished_at;

        if (!finished) return false;

        return {
          words: gl.utils.getTimeago().format(finished),
        };
      },
      duration() {
        const { duration } = this.pipeline.details;
        if (duration === 0) return '00:00:00';
        if (duration !== null) return duration;
        return false;
      },
    },
    template: `

          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="40"
            height="40"
            viewBox="0 0 40 40"
          >
            <g fill="#8F8F8F" fill-rule="evenodd">
              <path d="M29.513 10.134A15.922 15.922 0 0 0 23 7.28V6h2.993C26.55 6 27 5.552 27 5V2a1 1 0 0 0-1.007-1H14.007C13.45 1 13 1.448 13 2v3a1 1 0 0 0 1.007 1H17v1.28C9.597 8.686 4 15.19 4 23c0 8.837 7.163 16 16 16s16-7.163 16-16c0-3.461-1.099-6.665-2.967-9.283l1.327-1.58a2.498 2.498 0 0 0-.303-3.53 2.499 2.499 0 0 0-3.528.315l-1.016 1.212zM20 34c6.075 0 11-4.925 11-11s-4.925-11-11-11S9 16.925 9 23s4.925 11 11 11z"></path><path d="M19 21h-4.002c-.552 0-.998.452-.998 1.01v1.98c0 .567.447 1.01.998 1.01h7.004c.274 0 .521-.111.701-.291a.979.979 0 0 0 .297-.704v-8.01c0-.54-.452-.995-1.01-.995h-1.98a.997.997 0 0 0-1.01.995V21z"></path>
            </g>
          </svg>
          {{duration()}}

          <time
            data-toggle="tooltip"
            data-placement="top"
            data-container="body"
            :data-original-title='localTimeFinished'
          >
            {{timeStopped().words}}
          </time>

    `,
  });
})(window.gl || (window.gl = {}));
<|endoftext|>


<commit_before>var formfiller = new FormFiller();
formfiller.loadForm();

/**
 * FormFiller
 *
 * Main FormFiller class, which handles all requests
 * @returns {FormFiller}
 */
function FormFiller() {

    var _version = '2.0.0';
    var _context = this;
    this.jsCode = 'javascript:var d=document;function i(a){return d.getElementById(a)}function n(a){return d.getElementsByName(a)}';

    this.loadForm = function () {
        _loadJQuery();
    };

    var _loadJQuery = function () {
        if (typeof jQuery === 'undefined') {
            new Loader().script('//code.jquery.com/jquery-1.11.1.min.js', function(context){context.doLoadForm();}, _context);
        } else {
            this.doLoadForm();
        }
    };

    this.doLoadForm = function () {
        console.log('doLoadForm!');
        var html = '

Form Filler
 <input style="margin-bottom:18px"> <input type="button" value="Save" onclick="javascript:formfiller.save();return false;">
 Click and drag this link to the bookmarks bar: My bookmarklet
×

';
        $('body').append(html);
    };

    this.save = function() {
        $('form input:not(:hidden,:radio,:checkbox,:submit), form textarea, form select, form input[type="radio"]:checked, form input[type="checkbox"]:checked').each(function(){
            if($(this).attr('name') !== undefined){
                var attrName = $(this).attr('name');
                var attrId = $(this).attr('id');

                if((attrName.indexOf('[]') >= 0) || ($(this).attr('type') === 'radio')){
                    // Handle checkboxes and radio buttons
                    //formfiller.jsCode += '$("#' + attrId + '").prop("checked", true).change();';
                    formfiller.jsCode += 'i("'+attrId+'").checked=true;';
                } else {
                    // Set field value
                    //formfiller.jsCode += '$("*[name=' + attrName + ']").val("' + $(this).val() + '").change();';
                    formfiller.jsCode += 'n("'+attrName+'")[0].value="'+$(this).val()+'";';
                }
            }
        });
        $('#bookmarklet').attr('href', this.jsCode + 'void(0);');
    };

}

/**
 * Loader
 *
 * Class for loading external files
 * Supported tags:
 *   - script
 *   - link
 * @returns {Loader}
 */
function Loader() {

    var TYPE = {
        SCRIPT: 'script'
        , STYLE: 'link'
    };

    var _fileLoaded = false;
    var _callback = null;
    var _context = null;

    this.script = function (url, callback, context) {
        _callback = callback;
        _context = context;
        _appendNewElementToBody(
                TYPE.SCRIPT
                , {
                    src: url
                    , type: 'text/javascript'
                }
        );
        _cleanup();
    };

    this.style = function (url) {
        _appendNewElementToHead(
                TYPE.STYLE
                , {
                    href: url
                    , rel: 'stylesheet'
                    , type: 'text/css'
                }
        );
        _cleanup();
    };

    var _appendNewElementToBody = function (type, attrs) {
        _appendToBody(_createElement(type, attrs));
    };

    var _appendToBody = function (element) {
        _getFirstElementByTagName('body').appendChild(element);
    };

    var _appendNewElementToHead = function (type, attrs) {
        _appendToHead(_createElement(type, attrs));
    };

    var _appendToHead = function (element) {
        _getFirstElementByTagName('head').appendChild(element);
    };

    var _getFirstElementByTagName = function (name) {
        return document.getElementsByTagName(name)[0];
    };

    var _createElement = function (type, attrs) {
        var element = document.createElement(type);

        for (var key in attrs) {
            element.setAttribute(key, attrs[key]);
        }

        element.onload = element.onreadystatechage = function () {
            if (!_fileLoaded && (!this.readyState || ['loaded', 'complete'].indexOf(this.readyState) !== -1)) {
                _fileLoaded = true;
                element.onload = element.onreadystatechange = null;
                _getFirstElementByTagName('body').removeChild(element);
                _callback(_context);
            }
        };

        return element;
    };

    var _cleanup = function () {
        _fileLoaded = false;
    };

}<commit_msg>Fix checkboxes and general cleanup of code<commit_after>var formfiller = new FormFiller();
formfiller.loadForm();

/**
 * FormFiller
 *
 * Main FormFiller class, which handles all requests
 * @returns {FormFiller}
 */
function FormFiller() {

    var _version = '0.1.1';
    var _context = this;
    this.jsCode = 'javascript:/* Created With FormFiller v'+_version+' */var d=document;function i(a){return d.getElementById(a)}function n(a){return d.getElementsByName(a)}';

    this.loadForm = function () {
        _loadJQuery();
    };

    var _loadJQuery = function () {
        if (typeof jQuery === 'undefined') {
            new Loader().script('//code.jquery.com/jquery-1.11.1.min.js', function(context){context.doLoadForm();}, _context);
        } else {
            this.doLoadForm();
        }
    };

    this.doLoadForm = function () {
        var html = '

Form Filler v'+_version+'

<input id="formfiller-bookmarkletname" style="margin-bottom:18px" value="'+document.title+'"> <input type="button" value="Save" onclick="javascript:formfiller.save();return false;">

 Click and drag this link to the bookmarks bar: My bookmarklet
×

';
        $('body').append(html);
    };

    this.save = function() {
        $('form input:not(:hidden,:radio,:checkbox,:submit), form textarea, form select, form input[type="radio"]:checked, form input[type="checkbox"]:checked').each(function(){
            if($(this).attr('name') !== undefined){
                var attrName = $(this).attr('name');
                var attrId = $(this).attr('id');

                if((attrName.indexOf('[]') >= 0) || ($.inArray($(this).attr('type'), ['radio', 'checkbox']))){
                    // Handle checkboxes and radio buttons
                    formfiller.jsCode += 'i("'+attrId+'").checked=true;';
                } else {
                    // Set field value
                    formfiller.jsCode += 'n("'+attrName+'")[0].value="'+$(this).val()+'";';
                }
            }
        });
        this.jsCode += 'console.log("FormFiller: Form Repopulated.");';
        $('#bookmarklet').attr('href', this.jsCode + 'void(0);').html($('#formfiller-bookmarkletname').val()).parent('p').show();
        $('#formfiller-formwrapper').hide();
    };

}

/**
 * Loader
 *
 * Class for loading external files
 * Supported tags:
 *   - script
 *   - link
 * @returns {Loader}
 */
function Loader() {

    var TYPE = {
        SCRIPT: 'script'
    };

    var _fileLoaded = false;
    var _callback = null;
    var _context = null;

    this.script = function (url, callback, context) {
        _callback = callback;
        _context = context;
        _appendNewElementToBody(
            TYPE.SCRIPT
            , {
                src: url
                , type: 'text/javascript'
            }
        );
        _cleanup();
    };

    var _appendNewElementToBody = function (type, attrs) {
        _getFirstElementByTagName('body').appendChild(_createElement(type, attrs));
    };

    var _getFirstElementByTagName = function (name) {
        return document.getElementsByTagName(name)[0];
    };

    var _createElement = function (type, attrs) {
        var element = document.createElement(type);

        for (var key in attrs) {
            element.setAttribute(key, attrs[key]);
        }

        element.onload = element.onreadystatechage = function () {
            if (!_fileLoaded && (!this.readyState || ['loaded', 'complete'].indexOf(this.readyState) !== -1)) {
                _fileLoaded = true;
                element.onload = element.onreadystatechange = null;
                _getFirstElementByTagName('body').removeChild(element);
                _callback(_context);
            }
        };

        return element;
    };

    var _cleanup = function () {
        _fileLoaded = false;
    };

}<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Immutable from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import punycode from 'punycode';
import classnames from 'classnames';

const IDNA_PREFIX = 'xn--';

const decodeIDNA = domain => {
  return domain
    .split('.')
    .map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)
    .join('.');
};

const getHostname = url => {
  const parser = document.createElement('a');
  parser.href = url;
  return parser.hostname;
};

const trim = (text, len) => {
  const cut = text.indexOf(' ', len);

  if (cut === -1) {
    return text;
  }

  return text.substring(0, cut) + (text.length > len ? '…' : '');
};

const domParser = new DOMParser();

const addAutoPlay = html => {
  const document = domParser.parseFromString(html, 'text/html').documentElement;
  const iframe = document.querySelector('iframe');

  if (iframe) {
    if (iframe.src.indexOf('?') !== -1) {
      iframe.src += '&';
    } else {
      iframe.src += '?';
    }

    iframe.src += 'autoplay=1&auto_play=1';

    // DOM parser creates html/body elements around original HTML fragment,
    // so we need to get innerHTML out of the body and not the entire document
    return document.querySelector('body').innerHTML;
  }

  return html;
};

export default class Card extends React.PureComponent {

  static propTypes = {
    card: ImmutablePropTypes.map,
    maxDescription: PropTypes.number,
    onOpenMedia: PropTypes.func.isRequired,
    compact: PropTypes.bool,
  };

  static defaultProps = {
    maxDescription: 50,
    compact: false,
  };

  state = {
    width: 280,
    embedded: false,
  };

  componentWillReceiveProps (nextProps) {
    if (this.props.card !== nextProps.card) {
      this.setState({ embedded: false });
    }
  }

  handlePhotoClick = () => {
    const { card, onOpenMedia } = this.props;

    onOpenMedia(
      Immutable.fromJS([
        {
          type: 'image',
          url: card.get('embed_url'),
          description: card.get('title'),
          meta: {
            original: {
              width: card.get('width'),
              height: card.get('height'),
            },
          },
        },
      ]),
      0
    );
  };

  handleEmbedClick = () => {
    const { card } = this.props;

    if (card.get('type') === 'photo') {
      this.handlePhotoClick();
    } else {
      this.setState({ embedded: true });
    }
  }

  setRef = c => {
    if (c) {
      this.setState({ width: c.offsetWidth });
    }
  }

  renderVideo () {
    const { card }  = this.props;
    const content   = { __html: addAutoPlay(card.get('html')) };
    const { width } = this.state;
    const ratio     = card.get('width') / card.get('height');
    const height    = width / ratio;

    return (

    );
  }

  render () {
    const { card, maxDescription, compact } = this.props;
    const { width, embedded } = this.state;

    if (card === null) {
      return null;
    }

    const provider    = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name');
    const horizontal  = (!compact && card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded;
    const interactive = card.get('type') !== 'link';
    const className   = classnames('status-card', { horizontal, compact, interactive });
    const title       = interactive ? {card.get('title')} : {card.get('title')};
    const ratio       = card.get('width') / card.get('height');
    const height      = (compact && !embedded) ? (width / (16 / 9)) : (width / ratio);

    const description = (

        {title}
        {!(horizontal || compact) &&
{trim(card.get('description') || '', maxDescription)}
}
        {provider}

    );

    let embed     = '';
    let thumbnail = <div style={{ backgroundImage: `url(${card.get('image')})`, width: horizontal ? width : null, height: horizontal ? height : null }} className='status-card__image-image' />;

    if (interactive) {
      if (embedded) {
        embed = this.renderVideo();
      } else {
        let iconVariant = 'play';

        if (card.get('type') === 'photo') {
          iconVariant = 'search-plus';
        }

        embed = (

            {thumbnail}

                <button onClick={this.handleEmbedClick}><i className={`fa fa-${iconVariant}`} /></button>
                {horizontal && }

        );
      }

      return (

          {embed}
          {!compact && description}

      );
    } else if (card.get('image')) {
      embed = (

          {thumbnail}

      );
    }

    return (

        {embed}
        {description}

    );
  }

}
<commit_msg>Perform deep comparison for card data when receiving new props (#9270)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Immutable from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import punycode from 'punycode';
import classnames from 'classnames';

const IDNA_PREFIX = 'xn--';

const decodeIDNA = domain => {
  return domain
    .split('.')
    .map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)
    .join('.');
};

const getHostname = url => {
  const parser = document.createElement('a');
  parser.href = url;
  return parser.hostname;
};

const trim = (text, len) => {
  const cut = text.indexOf(' ', len);

  if (cut === -1) {
    return text;
  }

  return text.substring(0, cut) + (text.length > len ? '…' : '');
};

const domParser = new DOMParser();

const addAutoPlay = html => {
  const document = domParser.parseFromString(html, 'text/html').documentElement;
  const iframe = document.querySelector('iframe');

  if (iframe) {
    if (iframe.src.indexOf('?') !== -1) {
      iframe.src += '&';
    } else {
      iframe.src += '?';
    }

    iframe.src += 'autoplay=1&auto_play=1';

    // DOM parser creates html/body elements around original HTML fragment,
    // so we need to get innerHTML out of the body and not the entire document
    return document.querySelector('body').innerHTML;
  }

  return html;
};

export default class Card extends React.PureComponent {

  static propTypes = {
    card: ImmutablePropTypes.map,
    maxDescription: PropTypes.number,
    onOpenMedia: PropTypes.func.isRequired,
    compact: PropTypes.bool,
  };

  static defaultProps = {
    maxDescription: 50,
    compact: false,
  };

  state = {
    width: 280,
    embedded: false,
  };

  componentWillReceiveProps (nextProps) {
    if (!this.props.card.equals(nextProps.card)) {
      this.setState({ embedded: false });
    }
  }

  handlePhotoClick = () => {
    const { card, onOpenMedia } = this.props;

    onOpenMedia(
      Immutable.fromJS([
        {
          type: 'image',
          url: card.get('embed_url'),
          description: card.get('title'),
          meta: {
            original: {
              width: card.get('width'),
              height: card.get('height'),
            },
          },
        },
      ]),
      0
    );
  };

  handleEmbedClick = () => {
    const { card } = this.props;

    if (card.get('type') === 'photo') {
      this.handlePhotoClick();
    } else {
      this.setState({ embedded: true });
    }
  }

  setRef = c => {
    if (c) {
      this.setState({ width: c.offsetWidth });
    }
  }

  renderVideo () {
    const { card }  = this.props;
    const content   = { __html: addAutoPlay(card.get('html')) };
    const { width } = this.state;
    const ratio     = card.get('width') / card.get('height');
    const height    = width / ratio;

    return (

    );
  }

  render () {
    const { card, maxDescription, compact } = this.props;
    const { width, embedded } = this.state;

    if (card === null) {
      return null;
    }

    const provider    = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name');
    const horizontal  = (!compact && card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded;
    const interactive = card.get('type') !== 'link';
    const className   = classnames('status-card', { horizontal, compact, interactive });
    const title       = interactive ? {card.get('title')} : {card.get('title')};
    const ratio       = card.get('width') / card.get('height');
    const height      = (compact && !embedded) ? (width / (16 / 9)) : (width / ratio);

    const description = (

        {title}
        {!(horizontal || compact) &&
{trim(card.get('description') || '', maxDescription)}
}
        {provider}

    );

    let embed     = '';
    let thumbnail = <div style={{ backgroundImage: `url(${card.get('image')})`, width: horizontal ? width : null, height: horizontal ? height : null }} className='status-card__image-image' />;

    if (interactive) {
      if (embedded) {
        embed = this.renderVideo();
      } else {
        let iconVariant = 'play';

        if (card.get('type') === 'photo') {
          iconVariant = 'search-plus';
        }

        embed = (

            {thumbnail}

                <button onClick={this.handleEmbedClick}><i className={`fa fa-${iconVariant}`} /></button>
                {horizontal && }

        );
      }

      return (

          {embed}
          {!compact && description}

      );
    } else if (card.get('image')) {
      embed = (

          {thumbnail}

      );
    }

    return (

        {embed}
        {description}

    );
  }

}
<|endoftext|>


<commit_before>var fs = require('fs');
var fx = require('./fx');
var Stripe = require('stripe');

module.exports = function(wagner) {
  var stripe =

  // TODO: Make Stripe depend on the Config service and use its `stripeKey`
  // property to get the Stripe API key.
  wagner.factory('Stripe', function() {
    return Stripe(process.env.STRIPE_API_KEY);
  });

  wagner.factory('fx', fx);

  wagner.factory('Config', function() {
    return JSON.parse(fs.readFileSync('./config.json').toString());
  });
};
<commit_msg>Config is congiured in hw-3<commit_after>var fs = require('fs');
var fx = require('./fx');
var Stripe = require('stripe');

module.exports = function (wagner) {
  var stripe =

    // TODO: Make Stripe depend on the Config service and use its `stripeKey`
    // property to get the Stripe API key.
    wagner.factory('Stripe', function () {
      return Stripe(wagner.invoke(function (Config) {
        return Config.stripeKey;
      }));
    });

  wagner.factory('fx', fx);

  wagner.factory('Config', function () {
    return JSON.parse(fs.readFileSync('~/tmp/m101x/config.json').toString());
  });
};<|endoftext|>


<commit_before>/**
 * @name dom-aspect.js AOP cross-cutting advice for mag.js
 * @link https://github.com/magnumjs/mag.js
 * @license MIT
 * @owner copyright (c) 2013, 2014 Michael Glazer
 */
;
'use strict';
mag.aspect = {
  injectors: [],
  namespace: null,
  add: function(type, name, fun) {
    mag.aspect.injectors.push({
      type: type,
      name: name,
      fun: fun
    });
  },
  attach: function() {
    for (var i in mag.aspect.injectors) {
      var inject = mag.aspect.injectors[i];
      if (mag.aspect[inject.type]) {
        mag.aspect[inject.type](inject.name, inject.fun);
      }
    }
  },
  around: function(pointcut, advice) {
    var ns = mag.aspect.namespace;
    for (var member in mag.aspect.namespace) {
      if (typeof ns[member] == 'function' && member.match(pointcut)) {
        (function(fn, fnName, ns) {
          ns[fnName] = function() {
            return advice.call(ns, {
              fn: fn,
              fnName: fnName,
              arguments: arguments
            });
          };
        })(ns[member], member, ns);
      }
    }
  },
  before: function(pointcut, advice) {
    mag.aspect.around(pointcut,
      function(f) {
        advice.apply(mag.aspect.namespace, f.arguments);
        return mag.aspect.next(f)
      });
  },
  after: function(pointcut, advice) {
    mag.aspect.around(pointcut,
      function(f) {
        var ret = mag.aspect.next(f);
        advice.apply(mag.aspect.namespace, f.arguments);
        return ret;
      });
  },
  next: function(f) {
    return f.fn.apply(mag.aspect.namespace, f.arguments);
  }
};
mag.injection = function(ns) {
  mag.aspect.namespace = ns;
  mag.aspect.attach();
};
<commit_msg>Update mag-aspect.js<commit_after>/**
 * @name mag-aspect.js AOP cross-cutting advice for mag.js
 * @link https://github.com/magnumjs/mag.js
 * @license MIT
 * @owner copyright (c) 2013, 2014 Michael Glazer
 */
;
'use strict';
mag.aspect = {
  injectors: [],
  namespace: null,
  add: function(type, name, fun) {
    mag.aspect.injectors.push({
      type: type,
      name: name,
      fun: fun
    });
  },
  attach: function() {
    for (var i in mag.aspect.injectors) {
      var inject = mag.aspect.injectors[i];
      if (mag.aspect[inject.type]) {
        mag.aspect[inject.type](inject.name, inject.fun);
      }
    }
  },
  around: function(pointcut, advice) {
    var ns = mag.aspect.namespace;
    for (var member in mag.aspect.namespace) {
      if (typeof ns[member] == 'function' && member.match(pointcut)) {
        (function(fn, fnName, ns) {
          ns[fnName] = function() {
            return advice.call(ns, {
              fn: fn,
              fnName: fnName,
              arguments: arguments
            });
          };
        })(ns[member], member, ns);
      }
    }
  },
  before: function(pointcut, advice) {
    mag.aspect.around(pointcut,
      function(f) {
        advice.apply(mag.aspect.namespace, f.arguments);
        return mag.aspect.next(f)
      });
  },
  after: function(pointcut, advice) {
    mag.aspect.around(pointcut,
      function(f) {
        var ret = mag.aspect.next(f);
        advice.apply(mag.aspect.namespace, f.arguments);
        return ret;
      });
  },
  next: function(f) {
    return f.fn.apply(mag.aspect.namespace, f.arguments);
  }
};
mag.injection = function(ns) {
  mag.aspect.namespace = ns;
  mag.aspect.attach();
};
<|endoftext|>


<commit_before>import * as React from 'react';
import {Table} from "react-bootstrap";
import 'whatwg-fetch';
import * as moment from "moment-timezone";

class Intentions extends React.Component {
    constructor(props) {
        super(props);

        this.intentionsStore = props.intentionsStore;
        this.messagesStore = props.messagesStore;

        this.state = {
            items: null,
            messages: null
        };
    }

    componentDidMount() {
        this.load();
        this.intentionsStore.subscribe(() => this.load());
        this.loadMessage();
        this.messagesStore.subscribe(() => this.loadMessage());
    }

    load() {
        this.intentionsStore.getIntentions().then((json) => {
            console.log("Items: " + JSON.stringify(json));
            this.setState({items: json})
        })
    }

    loadMessage() {
        this.messagesStore.getMessages().then((json) => {
            this.setState({messages: json });
        });
    }

    formatVisitTime(time) {
        return moment(time, 'HH:mm').format("h:mm A");
    }

    render() {
        var messageMap = (this.state.messages || []).reduce(function(map, json) {
            map[json.name] = json.message;
            return map;
        }, {});

        let tableContent = null
        if (this.state.items === null) {
           tableContent = null;
        }
        else if (this.state.items.length === 0) {
            tableContent = (
 Be the first to go to the downs
 )
        } else {
            let sortedItems = this.state.items;
            sortedItems.sort((a, b) => moment(a.visitTime, 'HH:mm').valueOf() - moment(b.visitTime).valueOf());
            tableContent = this.state.items.sort().map(item=> (

                    {item.name}
                    {this.formatVisitTime(item.visitTime)}
                    {messageMap[item.name]}

            ))
        }

        return (

                    Name
                    Time
                    Message

                {tableContent}

        );
    }
}

export default Intentions;<commit_msg>Sort properly; add a loading indicator<commit_after>import * as React from 'react';
import {Table} from "react-bootstrap";
import 'whatwg-fetch';
import * as moment from "moment-timezone";

class Intentions extends React.Component {
    constructor(props) {
        super(props);

        this.intentionsStore = props.intentionsStore;
        this.messagesStore = props.messagesStore;

        this.state = {
            items: null,
            messages: null
        };
    }

    componentDidMount() {
        this.load();
        this.intentionsStore.subscribe(() => this.load());
        this.loadMessage();
        this.messagesStore.subscribe(() => this.loadMessage());
    }

    load() {
        this.intentionsStore.getIntentions().then((json) => {
            console.log("Items: " + JSON.stringify(json));
            this.setState({items: json})
        })
    }

    loadMessage() {
        this.messagesStore.getMessages().then((json) => {
            this.setState({messages: json });
        });
    }

    formatVisitTime(time) {
        return moment(time, 'HH:mm').format("h:mm A");
    }

    render() {
        var messageMap = (this.state.messages || []).reduce(function(map, json) {
            map[json.name] = json.message;
            return map;
        }, {});

        let tableContent = null
        if (this.state.items === null) {
            tableContent = (
 ... Loading ...
 )
        }
        else if (this.state.items.length === 0) {
            tableContent = (
 Be the first to go to the downs
 )
        } else {
            let sortedItems = this.state.items;
            sortedItems.sort((a, b) => moment(a.visitTime, 'HH:mm').valueOf() - moment(b.visitTime, 'HH:mm').valueOf());
            tableContent = this.state.items.sort().map(item=> (

                    {item.name}
                    {this.formatVisitTime(item.visitTime)}
                    {messageMap[item.name]}

            ))
        }

        return (

                    Name
                    Time
                    Message

                {tableContent}

        );
    }
}

export default Intentions;<|endoftext|>


<commit_before>let CookieStore = require('./Stores/Cookie');
let LocalStore = require('./Stores/Local');
const JWTDecode = require('jwt-decode');

class JWTManager {
    /**
     * Construct the class
     */
    constructor() {
        this.config = {
            store: 'cookie',
            secondsInterval: 3
        };
        this.store = null;
    }

    /**
     * Set the token
     *
     * @param token
     * @returns {string}
     */
    setToken(token) {
        let Store = this.getStore();

        Store.store(token);

        return token;
    }

    /**
     * Get the JWT Token
     *
     * @returns {string|null}
     */
    getToken() {
        let Store = this.getStore();

        return Store.retrieve();
    }

    /**
     * Forget the current token
     */
    forget() {
        let Store = this.getStore();

        Store.forget();
    }

    /**
     * Forget the old token and set the new token
     *
     * @param token
     */
    refresh(token)
    {
        let Store = this.getStore();
        Store.forget();
        Store.store(token);
    }

    /**
     * Decode the current token
     *
     * @return {object}
     */
    decode()
    {
        let token = this.getToken();

        if (token) {
            return JWTDecode(token);
        }
    }

    /**
     * Run the callback automatically when the token is
     * due to expire within the given remainingSeconds
     *
     * @param {callable} callback
     * @param {int} remainingSeconds
     */
    monitor(callback, remainingSeconds = 60)
    {
        setInterval(() => {
            let decoded = this.decode();

            if (decoded) {
                let secondsUntilExpiry = decoded.exp - (Date.now() / 1000);

                if (secondsUntilExpiry <= remainingSeconds) {
                    callback(this.getToken());
                }
            }
        }, this.config.secondsInterval);
    }

    /**
     * Get the store
     */
    getStore() {
        if (! this.store) {
            this.resolveStore();
        }

        return this.store;
    }

    /**
     * Resolve the store and cache it
     *
     * @return {void}
     */
    resolveStore()
    {
        if (this.config.store === 'local') {
            this.store = new LocalStore();
        } else if (this.config.store === 'cookie') {
            this.store = new CookieStore();
        }
    }
}

module.exports = JWTManager;<commit_msg>Fix spacing<commit_after>let CookieStore = require('./Stores/Cookie');
let LocalStore = require('./Stores/Local');
const JWTDecode = require('jwt-decode');

class JWTManager {
    /**
     * Construct the class
     */
    constructor() {
        this.config = {
            store: 'cookie',
            secondsInterval: 3
        };
        this.store = null;
    }

    /**
     * Set the token
     *
     * @param token
     * @returns {string}
     */
    setToken(token) {
        let Store = this.getStore();

        Store.store(token);

        return token;
    }

    /**
     * Get the JWT Token
     *
     * @returns {string|null}
     */
    getToken() {
        let Store = this.getStore();

        return Store.retrieve();
    }

    /**
     * Forget the current token
     */
    forget() {
        let Store = this.getStore();

        Store.forget();
    }

    /**
     * Forget the old token and set the new token
     *
     * @param token
     */
    refresh(token)
    {
        let Store = this.getStore();
        Store.forget();
        Store.store(token);
    }

    /**
     * Decode the current token
     *
     * @return {object}
     */
    decode()
    {
        let token = this.getToken();

        if (token) {
            return JWTDecode(token);
        }
    }

    /**
     * Run the callback automatically when the token is
     * due to expire within the given remainingSeconds
     *
     * @param {callable} callback
     * @param {int} remainingSeconds
     */
    monitor(callback, remainingSeconds = 60)
    {
        setInterval(() => {
            let decoded = this.decode();

            if (decoded) {
                let secondsUntilExpiry = decoded.exp - (Date.now() / 1000);

                if (secondsUntilExpiry <= remainingSeconds) {
                    callback(this.getToken());
                }
            }
        }, this.config.secondsInterval);
    }

    /**
     * Get the store
     */
    getStore() {
        if (! this.store) {
            this.resolveStore();
        }

        return this.store;
    }

    /**
     * Resolve the store and cache it
     *
     * @return {void}
     */
    resolveStore()
    {
        if (this.config.store === 'local') {
            this.store = new LocalStore();
        } else if (this.config.store === 'cookie') {
            this.store = new CookieStore();
        }
    }
}

module.exports = JWTManager;<|endoftext|>


<commit_before>/* eslint-disable no-unused-vars */
import request from 'superagent';
import { put, fork, call, select } from 'redux-saga/effects';
import { isDev, getDevelopmentPackages } from 'worona-deps';
import { toArray, uniqBy } from 'lodash';
import { flow, keyBy, mapValues } from 'lodash/fp';
import * as actions from '../actions';
import * as selectors from '../selectors';
import * as deps from '../deps';

export function* retrieveSettings() {
  yield put(actions.appSettingsRequested());
  const siteId = yield select(selectors.getSiteId);
  try {
    // Call the API.
    const env = isDev ? 'dev' : 'prod';
    const res = yield call(request.get,
      `https://cdn.worona.io/api/v1/settings/site/${siteId}/app/${env}/live`);
    const settings = flow(
      keyBy(setting => setting.woronaInfo.namespace),
      mapValues((setting) => { const { woronaInfo, ...rest } = setting; return rest; })
    )(res.body);
    // Extract the packages info from settings.
    const devPkgs = getDevelopmentPackages();
    const pkgs = uniqBy(
      toArray(devPkgs).concat(res.body).map(setting => setting.woronaInfo),
      pkg => pkg.namespace
    );
    // Inform that the API call was successful.
    yield put(actions.appSettingsSucceed({ settings, pkgs }));
    // Start activation for each downloaded package.
    yield toArray(pkgs).map(pkg => put(deps.actions.packageActivationRequested({ pkg })));
  } catch (error) {
    yield put(actions.appSettingsFailed({ error }));
  }
}

export default function* settingsSagas() {
  yield [
    fork(retrieveSettings),
  ];
}
<commit_msg>Filter general-site-settings from pkgs and add it settings.<commit_after>/* eslint-disable no-unused-vars */
import request from 'superagent';
import { put, fork, call, select } from 'redux-saga/effects';
import { isDev, getDevelopmentPackages } from 'worona-deps';
import { toArray } from 'lodash';
import { flow, values, concat, map, filter, keyBy, mapValues, uniqBy } from 'lodash/fp';
import * as actions from '../actions';
import * as selectors from '../selectors';
import * as deps from '../deps';

export function* retrieveSettings() {
  yield put(actions.appSettingsRequested());
  const siteId = yield select(selectors.getSiteId);
  try {
    // Call the API.
    const env = isDev ? 'dev' : 'prod';
    const res = yield call(request.get,
      `https://cdn.worona.io/api/v1/settings/site/${siteId}/app/${env}/live`);
    const settings = flow(
      keyBy(setting => setting.woronaInfo.namespace),
      mapValues((setting) => { const { woronaInfo, ...rest } = setting; return rest; })
    )(res.body);
    // Extract the packages info from settings.
    const devPkgs = getDevelopmentPackages();
    const pkgs = flow(
      values,
      concat(res.body),
      map(setting => setting.woronaInfo),
      filter(woronaInfo => !!woronaInfo.main),
      uniqBy(pkg => pkg.namespace)
    )(devPkgs);
    // Inform that the API call was successful.
    yield put(actions.appSettingsSucceed({ settings, pkgs }));
    // Start activation for each downloaded package.
    yield toArray(pkgs).map(pkg => put(deps.actions.packageActivationRequested({ pkg })));
  } catch (error) {
    yield put(actions.appSettingsFailed({ error }));
  }
}

export default function* settingsSagas() {
  yield [
    fork(retrieveSettings),
  ];
}
<|endoftext|>