<commit_before>var Engine = require('../Engine'),
    util = require('util'),
    url = require('url'),
    mongo = require('mongodb'),
    ObjectID = require('mongodb').ObjectID;

var Mongodb = module.exports = function Mongodb(options) {
  Engine.call(this, options);

  var self = this;

  if (options.uri) {
    var uri = url.parse(options.uri, true);
    options.host = uri.hostname;
    options.port = uri.port;

    if (uri.pathname) {
      options.database = uri.pathname.replace(/^\/|\/$/g, '');
    }
  }

  options.host     = options.host     || '127.0.0.1';
  options.port     = options.port     || 27017;
  options.database = options.database || 'test';
  options.safe     = (String(options.safe) === 'true');

  options.uri = url.format({
    protocol: 'mongodb',
    hostname: options.host,
    port: options.port,
    pathname: '/' + options.database
  });

  options.port = parseInt(options.port, 10);

  this.options = options;

  // Create a new connection to Mongo
  new mongo.Db(options.database, new mongo.Server(options.host, options.port, {}))
    .open(function(err, db) {
      self.connection = db;
      self.emit('ready');
    });

  return this;
};

util.inherits(Mongodb, Engine);

// Normalize a mongo _id property into an id property
function normalize(obj) {
  if(!obj) return;

  if(obj._id) {
    obj.id = obj._id.toString();
    delete obj._id;
  }

  return obj;
}

Mongodb.prototype.get = function get(id, namespace, callback) {
  if(id && typeof id === 'string') {
    id = {'_id': ObjectID(id)};
  }

  this.connection.collection(namespace, function(err, collection) {
    collection.findOne(id, function(err, doc) {
      if(err) return callback(err);

      callback(null, normalize(doc) || {});
    });
  });
};

Mongodb.prototype.create = function create(attrs, namespace, callback) {
  var self = this;

  this.connection.collection(namespace, function(err, collection) {
    collection.insert(attrs, {safe: self.options.self}, function(err, doc) {
      if(err) return callback(err);

      callback(null, normalize(doc[0]) || {});
    });
  });
};

Mongodb.prototype.save = function save(id, attrs, namespace, callback) {
  var self = this;

  if(id && typeof id === 'string') {
    attrs._id = ObjectID(id.toString());
    delete attrs.id;
  }

  this.connection.collection(namespace, function(err, collection) {
    collection.save(attrs, {safe: self.options.safe}, function(err, result) {
      if(err) return callback(err);
      collection.findOne(attrs, function(err, doc) {
        if(err) return callback(err);
        callback(null, normalize(doc) || {});
      });
    });
  });
};

Mongodb.prototype.destroy = function destroy(id, namespace, callback) {
  var self = this;

  if(id && typeof id === 'string') {
    id = {'_id': ObjectID(id)};
  }

  this.connection.collection(namespace, function(err, collection) {
    collection.remove(id, {safe: self.options.safe}, callback);
  });
};

Mongodb.prototype.update = function update(id, attrs, namespace, callback) {
  var self = this;

  if(id && typeof id === 'string') {
    id = {'_id': ObjectID(id)};
  }

  if(attrs.id) delete attrs.id;

  this.connection.collection(namespace, function(err, collection) {
    collection.update(id, {$set: attrs}, {safe: self.options.safe}, function(err) {
      if(err) return callback(err);
      collection.findOne(id, function(err, doc) {
        if(err) return callback(err);
        callback(null, normalize(doc) || {});
      });
    });
  });
};

Mongodb.prototype.find = function find(conditions, namespace, callback) {
  this.connection.collection(namespace, function(err, collection) {
    collection.find(conditions).toArray(function(err, results) {
      if(err) return callback(err);
      var normalized = [];
      results.forEach(function(obj) {
        normalized.push(normalize(obj));
      });

      callback(null, normalized);
    });
  });
};

Mongodb.prototype.all = function all(namespace, callback) {
  this.connection.collection(namespace, function(err, collection) {
    collection.find().toArray(function(err, results) {
      if(err) return callback(err);
      var normalized = [];
      results.forEach(function(obj) {
        normalized.push(normalize(obj));
      });

      callback(null, normalized);
    });
  });
};<commit_msg>fix typo on engine require()<commit_after>var Engine = require('../engine'),
    util = require('util'),
    url = require('url'),
    mongo = require('mongodb'),
    ObjectID = require('mongodb').ObjectID;

var Mongodb = module.exports = function Mongodb(options) {
  Engine.call(this, options);

  var self = this;

  if (options.uri) {
    var uri = url.parse(options.uri, true);
    options.host = uri.hostname;
    options.port = uri.port;

    if (uri.pathname) {
      options.database = uri.pathname.replace(/^\/|\/$/g, '');
    }
  }

  options.host     = options.host     || '127.0.0.1';
  options.port     = options.port     || 27017;
  options.database = options.database || 'test';
  options.safe     = (String(options.safe) === 'true');

  options.uri = url.format({
    protocol: 'mongodb',
    hostname: options.host,
    port: options.port,
    pathname: '/' + options.database
  });

  options.port = parseInt(options.port, 10);

  this.options = options;

  // Create a new connection to Mongo
  new mongo.Db(options.database, new mongo.Server(options.host, options.port, {}))
    .open(function(err, db) {
      self.connection = db;
      self.emit('ready');
    });

  return this;
};

util.inherits(Mongodb, Engine);

// Normalize a mongo _id property into an id property
function normalize(obj) {
  if(!obj) return;

  if(obj._id) {
    obj.id = obj._id.toString();
    delete obj._id;
  }

  return obj;
}

Mongodb.prototype.get = function get(id, namespace, callback) {
  if(id && typeof id === 'string') {
    id = {'_id': ObjectID(id)};
  }

  this.connection.collection(namespace, function(err, collection) {
    collection.findOne(id, function(err, doc) {
      if(err) return callback(err);

      callback(null, normalize(doc) || {});
    });
  });
};

Mongodb.prototype.create = function create(attrs, namespace, callback) {
  var self = this;

  this.connection.collection(namespace, function(err, collection) {
    collection.insert(attrs, {safe: self.options.self}, function(err, doc) {
      if(err) return callback(err);

      callback(null, normalize(doc[0]) || {});
    });
  });
};

Mongodb.prototype.save = function save(id, attrs, namespace, callback) {
  var self = this;

  if(id && typeof id === 'string') {
    attrs._id = ObjectID(id.toString());
    delete attrs.id;
  }

  this.connection.collection(namespace, function(err, collection) {
    collection.save(attrs, {safe: self.options.safe}, function(err, result) {
      if(err) return callback(err);
      collection.findOne(attrs, function(err, doc) {
        if(err) return callback(err);
        callback(null, normalize(doc) || {});
      });
    });
  });
};

Mongodb.prototype.destroy = function destroy(id, namespace, callback) {
  var self = this;

  if(id && typeof id === 'string') {
    id = {'_id': ObjectID(id)};
  }

  this.connection.collection(namespace, function(err, collection) {
    collection.remove(id, {safe: self.options.safe}, callback);
  });
};

Mongodb.prototype.update = function update(id, attrs, namespace, callback) {
  var self = this;

  if(id && typeof id === 'string') {
    id = {'_id': ObjectID(id)};
  }

  if(attrs.id) delete attrs.id;

  this.connection.collection(namespace, function(err, collection) {
    collection.update(id, {$set: attrs}, {safe: self.options.safe}, function(err) {
      if(err) return callback(err);
      collection.findOne(id, function(err, doc) {
        if(err) return callback(err);
        callback(null, normalize(doc) || {});
      });
    });
  });
};

Mongodb.prototype.find = function find(conditions, namespace, callback) {
  this.connection.collection(namespace, function(err, collection) {
    collection.find(conditions).toArray(function(err, results) {
      if(err) return callback(err);
      var normalized = [];
      results.forEach(function(obj) {
        normalized.push(normalize(obj));
      });

      callback(null, normalized);
    });
  });
};

Mongodb.prototype.all = function all(namespace, callback) {
  this.connection.collection(namespace, function(err, collection) {
    collection.find().toArray(function(err, results) {
      if(err) return callback(err);
      var normalized = [];
      results.forEach(function(obj) {
        normalized.push(normalize(obj));
      });

      callback(null, normalized);
    });
  });
};<|endoftext|>


<commit_before>import React from 'react';
import styled from 'styled-components';
import Icon from 'ui/components/common/Icon';

const Container = styled.div`
  display: inline-flex;
  margin-right: 10px;
`;

const Value = styled.div`
  position: relative;
  color: red;
  padding: ${(props) => props.smaller ? '0' : '2px'} 8px;
  user-select: none;
  background-color: ${(props) => props.isSelected ? props.theme.blue : '#f0f0f0'};
  color: ${(props) => props.isSelected ? 'white' : 'black'};
  cursor: ${(props) => props.isSelected ? 'default' : 'pointer'};

  &:first-child {
    border-radius: 4px 0 0 4px;
  }

  &:last-child {
    border-radius: 0 4px 4px 0;
  }

  ${({ isDisabled }) => isDisabled ? 'color: #b6b6b6; cursor: default; background-color: #f0f0f0;' : ''}
`;

const Values = ({ values, disabledValues = [], selectedValue, other, startEditing, onChange, smaller }) => (
  <Container>
    {
      values.map((value) => (
        <Value key={ value }
               isSelected={ value === selectedValue }
               isDisabled={ disabledValues.indexOf(value) !== -1 }
               onClick={ () => onChange && onChange(value) }
               smaller={ smaller }>
          { value }
        </Value>
      ))
    }

    { other && <Value isSelected={ values.indexOf(selectedValue) < 0 } onClick={ startEditing }>Other...</Value> }
  </Container>
);

const StatusForm = styled.form`
  width: 220px;
  position: relative;
`;

const CloseIcon = styled(Icon)`
  position: absolute;
  top: 4px;
  right: 4px;
  display: block;
`;

const Input = styled.input`
  border: none;
  background-color: #f0f0f0;
  outline: 0;
  border-radius: 4px;
  height: 24px;
  padding: 0 25px 0 6px;
  display: block;
  width: 100%;
  box-sizing: border-box;

  &:focus {
    border: 2px solid #b2c9ee;
    box-sizing: border-box;
    padding: 0 4px;
  }
`;

class CustomValue extends React.Component {
  handleChange = (event) => {
    event.preventDefault();
    this.props.onChange(parseInt(this.elem.value, 10));
  };

  handleKeyDown = event => {
    if (event.keyCode === 27) {
      event.preventDefault();
      event.stopPropagation();
      this.props.onChange(this.props.selectedValue);
    }
  };

  setElem = (elem) => {
    this.elem = elem;

    if (elem) {
      elem.value = this.props.selectedValue;
      setTimeout(() => elem.select(), 0);
    }
  };

  render() {
    return (
      <Container>
        <StatusForm onKeyUp={ this.handleKeyDown }>
          <Input type="text"
                 onChange={ this.handleChange }
                 innerRef={ this.setElem }
                 placeholder="Start typing an HTTP status code"/>
          <CloseIcon src="clear" onClick={ this.props.onClose }/>
        </StatusForm>
      </Container>
    );
  }
}

class SelectBar extends React.Component {

  state = {
    editing: false
  };

  setEditing = (editing) => {
    this.setState({ editing });
  };

  updateValue = (value) => {
    this.props.onChange(value);
    this.setState({ editing: false });
  };

  render() {
    return this.state.editing
      ? <CustomValue onChange={ this.updateValue }
                     selectedValue={ this.props.selectedValue }
                     onClose={ () => this.setEditing(false) }/>
      : <Values { ...this.props } smaller={ this.props.smaller } startEditing={ () => this.setEditing(true) }/>
  }
}

export default SelectBar;
<commit_msg>Add typeahead functionallity to status code edit<commit_after>import React from 'react';
import styled from 'styled-components';
import Icon from 'ui/components/common/Icon';
import HttpStatusCodes from 'http-status-codes';

const Container = styled.div`
  display: inline-flex;
  margin-right: 10px;
  position: relative;
`;

const Placeholder = styled.div`
  position: absolute;
  top: 3px;
  left: 6px;
  font-size: 11px;
  color: gray;
`;

const Value = styled.div`
  position: relative;
  color: red;
  padding: ${(props) => props.smaller ? '0' : '2px'} 8px;
  user-select: none;
  background-color: ${(props) => props.isSelected ? props.theme.blue : '#f0f0f0'};
  color: ${(props) => props.isSelected ? 'white' : 'black'};
  cursor: ${(props) => props.isSelected ? 'default' : 'pointer'};

  &:first-child {
    border-radius: 4px 0 0 4px;
  }

  &:last-child {
    border-radius: 0 4px 4px 0;
  }

  ${({ isDisabled }) => isDisabled ? 'color: #b6b6b6; cursor: default; background-color: #f0f0f0;' : ''}
`;

const Values = ({ values, disabledValues = [], selectedValue, other, startEditing, onChange, smaller }) => (
  <Container>
    {
      values.map((value) => (
        <Value key={ value }
               isSelected={ value === selectedValue }
               isDisabled={ disabledValues.indexOf(value) !== -1 }
               onClick={ () => onChange && onChange(value) }
               smaller={ smaller }>
          { value }
        </Value>
      ))
    }

    { other && <Value isSelected={ values.indexOf(selectedValue) < 0 } onClick={ startEditing }>Other...</Value> }
  </Container>
);

const StatusForm = styled.form`
  width: 220px;
  position: relative;
`;

const CloseIcon = styled(Icon)`
  position: absolute;
  top: 4px;
  right: 4px;
  display: block;
`;

const Input = styled.input`
  border: none;
  background-color: #f0f0f0;
  outline: 0;
  border-radius: 4px;
  height: 24px;
  padding: 0 25px 0 6px;
  display: block;
  width: 100%;
  box-sizing: border-box;
  color: gray;

  &:focus {
    border: 2px solid #b2c9ee;
    box-sizing: border-box;
    padding: 0 4px;
  }
`;

class CustomValue extends React.Component {
  handleChange = (event) => {
    event.preventDefault();
    this.props.onChange(parseInt(this.elem.value, 10));
  };

  handleKeyDown = event => {
    if (event.keyCode === 27) {
      event.preventDefault();
      event.stopPropagation();
      this.props.onChange(this.props.selectedValue);
    } else {
      this.forceUpdate();
    }
  };

  setElem = (elem) => {
    this.elem = elem;

    if (elem) {
      elem.value = this.props.selectedValue;
      setTimeout(() => elem.focus(), 0);
      this.forceUpdate();
    }
  };

  renderMatches() {
    if (!this.elem) {
      return null;
    }

    const value = this.elem.value;

    if (!value) {
      return null;
    }

    try {
      const statusText = HttpStatusCodes.getStatusText(value);

      return `${value} ${statusText}`;
    } catch (ex) {
      return null;
    }
  }

  render() {
    return (
      <Container>
        <StatusForm onKeyUp={ this.handleKeyDown }>
          <Placeholder>{ this.renderMatches() }</Placeholder>
          <Input type="text"
                 onBlur={ this.handleChange }
                 innerRef={ this.setElem }
                 placeholder="Start typing an HTTP status code"/>
          <CloseIcon src="clear" onClick={ this.props.onClose }/>
        </StatusForm>
      </Container>
    );
  }
}

class SelectBar extends React.Component {

  state = {
    editing: false
  };

  setEditing = (editing) => {
    this.setState({ editing });
  };

  updateValue = (value) => {
    this.props.onChange(value);
    this.setState({ editing: false });
  };

  render() {
    return this.state.editing
      ? <CustomValue onChange={ this.updateValue }
                     selectedValue={ this.props.selectedValue }
                     onClose={ () => this.setEditing(false) }/>
      : <Values { ...this.props } smaller={ this.props.smaller } startEditing={ () => this.setEditing(true) }/>
  }
}

export default SelectBar;
<|endoftext|>


<commit_before>console.log("build success, lets run script")

console.log("+++++++++++++++++++++++")

const fs = require('fs');
const BUNDLE_NAME = process.env.BUNDLE_NAME || 'bundle'
const chain = process.env.chain

var chain_folder = ""
if (chain === 'production'){
  chain_folder = ""
}else{
  chain_folder = "_" + chain
}

const file = `../app/views/swap/_index${chain_folder}.html.slim`
const ENV = process.env.ENV

console.log("bundle name ----------------___++++++", BUNDLE_NAME)
//let jsName = ENV == 'production' ? BUNDLE_NAME + '.js.gz' : BUNDLE_NAME + '.js'

var now = new Date().getTime()

let view = `
- if browser.device.mobile? || cookies[:is_visited] == 'true'
    #swap-app onClick="animateSwap()"
        div style="text-align:center"
            = render "server_rendering"
    link rel="stylesheet" href="/swap/${chain}/app.css?v=${now}" type="text/css"
    script src="https://www.google.com/recaptcha/api.js"
    script src="/swap/${chain}/app.min.js?v=${now}"
- else
    #swap-app
        div style="text-align:center" onClick="openSwap('${chain}', ${now})"
            = render "server_rendering"
    link rel="stylesheet" href="/swap/${chain}/app.css?v=${now}" type="text/css"
`

// let view = `
// #ieo-app
// script src="/${ENV ? 'bundle-ieo' : 'ieo-bundle'}/${jsName}"
// link rel="stylesheet" href="/${ENV ? 'bundle-ieo' : 'ieo-bundle'}/${BUNDLE_NAME}.css" type="text/css"
// `

console.log("------------------------")
// .loading
//     .loading-left
//       .loading-above
//         .circle-container
//           .circle.animated-background
//         .paragraph
//           .first-par.animated-background
//           p.second-par.animated-background
//           p.third-par.animated-background
//       .loading-under
//         p.animated-background
//         p.animated-background
//         p.animated-background
//         p.animated-background
//     .loading-right
//       .md-div.animated-background
//       .md-div.animated-background
//       .sm-div.first-sm-div.animated-background
//       .sm-div.animated-background
//       .list-circle-div
//         .circle-div.animated-background
//         .circle-div.animated-background
//         .circle-div.animated-background

var cleanFile = function(fileName, callback){
  fs.access(fileName, fs.constants.F_OK, (err) => {
    console.log(`${fileName} ${err ? 'does not exist' : 'exists'}`);
    if(!err) fs.unlink(fileName, callback)

    else callback()
  });
}

cleanFile(file, () => {
  fs.writeFile(file, view, (err) => {
      if (err) {
        console.log("##############")
        console.log(err)
        throw err
      }

      // success case, the file was saved
      console.log('view saved for bundle ' + BUNDLE_NAME);
  });
})

<commit_msg>fix after build<commit_after>console.log("build success, lets run script")

console.log("+++++++++++++++++++++++")

const fs = require('fs');
const BUNDLE_NAME = process.env.BUNDLE_NAME || 'bundle'
const chain = process.env.chain

var chain_folder = ""
if (chain === 'production'){
  chain_folder = ""
}else{
  chain_folder = "_" + chain
}

const file = `../app/views/swap/_index${chain_folder}.html.slim`
const ENV = process.env.ENV

console.log("bundle name ----------------___++++++", BUNDLE_NAME)
//let jsName = ENV == 'production' ? BUNDLE_NAME + '.js.gz' : BUNDLE_NAME + '.js'

var now = new Date().getTime()

let view = `
- if browser.device.mobile? || cookies[:is_visited] == 'true'
    link rel="stylesheet" href="/swap/${chain}/app.css?v=${now}" type="text/css"
    #swap-app onClick="animateSwap()"
        div style="text-align:center"
            = render "server_rendering"
    script src="https://www.google.com/recaptcha/api.js"
    script src="/swap/${chain}/app.min.js?v=${now}"
- else
    link rel="stylesheet" href="/swap/${chain}/app.css?v=${now}" type="text/css"
    #swap-app
        div style="text-align:center" onClick="openSwap('${chain}', ${now})"
            = render "server_rendering"
`

// let view = `
// #ieo-app
// script src="/${ENV ? 'bundle-ieo' : 'ieo-bundle'}/${jsName}"
// link rel="stylesheet" href="/${ENV ? 'bundle-ieo' : 'ieo-bundle'}/${BUNDLE_NAME}.css" type="text/css"
// `

console.log("------------------------")
// .loading
//     .loading-left
//       .loading-above
//         .circle-container
//           .circle.animated-background
//         .paragraph
//           .first-par.animated-background
//           p.second-par.animated-background
//           p.third-par.animated-background
//       .loading-under
//         p.animated-background
//         p.animated-background
//         p.animated-background
//         p.animated-background
//     .loading-right
//       .md-div.animated-background
//       .md-div.animated-background
//       .sm-div.first-sm-div.animated-background
//       .sm-div.animated-background
//       .list-circle-div
//         .circle-div.animated-background
//         .circle-div.animated-background
//         .circle-div.animated-background

var cleanFile = function(fileName, callback){
  fs.access(fileName, fs.constants.F_OK, (err) => {
    console.log(`${fileName} ${err ? 'does not exist' : 'exists'}`);
    if(!err) fs.unlink(fileName, callback)

    else callback()
  });
}

cleanFile(file, () => {
  fs.writeFile(file, view, (err) => {
      if (err) {
        console.log("##############")
        console.log(err)
        throw err
      }

      // success case, the file was saved
      console.log('view saved for bundle ' + BUNDLE_NAME);
  });
})

<|endoftext|>


<commit_before>var q = require('q');
var _ = require('underscore');

// Les models
var model = require('../models/blog');

// Les services
var core = new require('./core')();
var Picture = require('./picture');

var service = _.extend(core, {

  model: model,

  getCount: function() {

    var that = this;

    return q.fcall(function() {

      return that.model
                  .count()
                  .exec()
    })
  },

  getLast: function() {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({}, {}, {sort: {'created_at' : 1}}).exec();
    })
  },

  getList: function(page) {

    var that = this;
    var size = 20;
    var start = (page - 1) * size;

    return q.fcall(function() {

      return that.model
                  .find()
                  .limit(size)
                  .skip(start)
                  .sort('-created')
                  .exec()
    })
  },

  getOne: function(id) {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({_id: id}).populate('picture').exec()
    })
  },

  modify: function(id, data, deletion) {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({_id: id}).exec();
    })
    .then(function(model) {

      if (model.get('picture') && deletion) return Picture.delete(model.get('picture'));
      return that;
    })
    .then(function() {

      return that.update(id, data);
    })
  },

  delete: function(id) {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({_id: id}).exec();
    })
    .then(function(model) {

      if (model.get('picture')) return Picture.delete(model.get('picture'));
      return that;
    })
    .then(function() {

      return that.remove(id);
    })
  },

});

module.exports = service;
<commit_msg>order<commit_after>var q = require('q');
var _ = require('underscore');

// Les models
var model = require('../models/blog');

// Les services
var core = new require('./core')();
var Picture = require('./picture');

var service = _.extend(core, {

  model: model,

  getCount: function() {

    var that = this;

    return q.fcall(function() {

      return that.model
                  .count()
                  .exec()
    })
  },

  getLast: function() {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({}, {}, {sort: {'created' : -1}}).exec();
    })
  },

  getList: function(page) {

    var that = this;
    var size = 20;
    var start = (page - 1) * size;

    return q.fcall(function() {

      return that.model
                  .find()
                  .limit(size)
                  .skip(start)
                  .sort('-created')
                  .exec()
    })
  },

  getOne: function(id) {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({_id: id}).populate('picture').exec()
    })
  },

  modify: function(id, data, deletion) {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({_id: id}).exec();
    })
    .then(function(model) {

      if (model.get('picture') && deletion) return Picture.delete(model.get('picture'));
      return that;
    })
    .then(function() {

      return that.update(id, data);
    })
  },

  delete: function(id) {

    var that = this;

    return q.fcall(function() {

      return that.model.findOne({_id: id}).exec();
    })
    .then(function(model) {

      if (model.get('picture')) return Picture.delete(model.get('picture'));
      return that;
    })
    .then(function() {

      return that.remove(id);
    })
  },

});

module.exports = service;
<|endoftext|>


<commit_before>const SHOW_ALL = 'SHOW_ALL';
const SHOW_COMPLETED = 'SHOW_COMPLETED';
var counter = 0;

function findElement(id, array) {
  return array.map(function(element) {
    return element.id
  }).indexOf(id);
}

//Reducer：更新state的函式
const filter = (state = SHOW_ALL, action) => {
  switch (action.type) {
    case SHOW_ALL:
      return action.type
    case SHOW_COMPLETED:
      return action.type
    default:
      return state
  }
}

const todos = (state = [], actions) => {
  switch(actions.type) {
    case 'ADD_TODO':
      state.push({
        id: counter++,
        name: actions.name,
        completed: false
      });
      break;
    case 'DELETE_TODO':
      state.splice(findElement(actions.id, state), 1);
      break;
    case 'EDIT_TODO':
      state[findElement(actions.id, state)].name = actions.name;
      break;
    case 'COMPLETE_TODO':
      state[findElement(actions.id, state)].completed = actions.completed;
      break;
    case 'INCOMPLETE_TODO':
      state.todos[findElement(actions.id, state)].completed = actions.completed;
      break;
    default:
      break;
  }

  return state;
}

//Store：儲存state的地方
const todoApp = Redux.combineReducers({
  filter,
  todos
});
var todosStore = Redux.createStore(todoApp)

//Action：使用todosStore.dispatch來通知有事情發生，必須更新state
$('.add').click(() => {
  var newValue = $('.input_new_item').val();
  if(newValue) {
    todosStore.dispatch({
      type: 'ADD_TODO',
      name: newValue
    });
  }

  $('.input_new_item').val('');
});

$('.list').on('click', '.delete', function() {
  todosStore.dispatch({
    type: 'DELETE_TODO',
    id: $(this).parents('.item').data('id')
  });
});

$('.list').on('click', '.edit', function() {
  $(this).hide();
  $(this).parents('.item').find('.edit-block').show();
});

$('.list').on('click', '.submit', function() {
  var $item = $(this).parents('.item');

  todosStore.dispatch({
    type: 'EDIT_TODO',
    id: $item.data('id'),
    name: $item.find('.input-edit').val()
  });

  $item.find('.edit').show();
  $item.find('.edit-block').hide();
});

$('.list').on('change', '.complete-status', function() {
  var isCompleted = $(this).prop('checked');
  var actionType = 'INCOMPLETE_TODO';

  if(isCompleted) {
    actionType = 'COMPLETE_TODO'
  }

  todosStore.dispatch({
    type: actionType,
    id: $(this).parents('.item').data('id'),
    completed: isCompleted
  });

});

$('.filter-complete').click(() => {
  todosStore.dispatch({
    type: SHOW_COMPLETED
  });
});

$('.filter-all').click(() => {
  todosStore.dispatch({
    type: SHOW_ALL
  });
});

//監聽，當dispatch action執行造成state改變時就去取目前state內容，用來更新UI
todosStore.subscribe(() => {
  var state = todosStore.getState();
  var ResultHTML = '';

  for(var i = 0; i < state.todos.length; i++) {
    let HTML = '';
    let item = state.todos[i];
    let status = item.completed ? 'checked' : '';
    let hide = (state.filter === SHOW_COMPLETED && !item.completed) ? 'hide' : '';

    HTML += [
      '
',
      '  <input type="checkbox" class="complete-status"' + status +'>',
      '  ' + item.name + '',
      '  ',
      '    <input class="input-edit" />',
      '    <button class="submit">submit</button>',
      '  ',
      '  <button class="edit">edit</button>',
      '  <button class="delete">delete</button>',
      '
'
    ].join('');
    ResultHTML += HTML;
  }

  $('#todoList .list').html(ResultHTML);
});<commit_msg>remove redundant code<commit_after>const SHOW_ALL = 'SHOW_ALL';
const SHOW_COMPLETED = 'SHOW_COMPLETED';
var counter = 0;

function findElement(id, array) {
  return array.map(function(element) {
    return element.id
  }).indexOf(id);
}

//Reducer：更新state的函式
const filter = (state = SHOW_ALL, action) => {
  switch (action.type) {
    case SHOW_ALL:
      return action.type
    case SHOW_COMPLETED:
      return action.type
    default:
      return state
  }
}

const todos = (state = [], actions) => {
  switch(actions.type) {
    case 'ADD_TODO':
      state.push({
        id: counter++,
        name: actions.name,
        completed: false
      });
      break;
    case 'DELETE_TODO':
      state.splice(findElement(actions.id, state), 1);
      break;
    case 'EDIT_TODO':
      state[findElement(actions.id, state)].name = actions.name;
      break;
    case 'COMPLETE_TODO':
      state[findElement(actions.id, state)].completed = actions.completed;
      break;
    case 'INCOMPLETE_TODO':
      state.todos[findElement(actions.id, state)].completed = actions.completed;
      break;
    default:
      break;
  }

  return state;
}

//Store：儲存state的地方
const todoApp = Redux.combineReducers({
  filter,
  todos
});
var todosStore = Redux.createStore(todoApp)

//Action：使用todosStore.dispatch來通知有事情發生，必須更新state
$('.add').click(() => {
  var newValue = $('.input_new_item').val();
  if(newValue) {
    todosStore.dispatch({
      type: 'ADD_TODO',
      name: newValue
    });
  }

  $('.input_new_item').val('');
});

$('.list').on('click', '.delete', function() {
  todosStore.dispatch({
    type: 'DELETE_TODO',
    id: $(this).parents('.item').data('id')
  });
});

$('.list').on('click', '.edit', function() {
  $(this).hide();
  $(this).parents('.item').find('.edit-block').show();
});

$('.list').on('click', '.submit', function() {
  var $item = $(this).parents('.item');

  todosStore.dispatch({
    type: 'EDIT_TODO',
    id: $item.data('id'),
    name: $item.find('.input-edit').val()
  });

  $item.find('.edit').show();
  $item.find('.edit-block').hide();
});

$('.list').on('change', '.complete-status', function() {
  var isCompleted = $(this).prop('checked');
  var actionType = 'INCOMPLETE_TODO';

  if(isCompleted) {
    actionType = 'COMPLETE_TODO'
  }

  todosStore.dispatch({
    type: actionType,
    id: $(this).parents('.item').data('id'),
    completed: isCompleted
  });
});

$('.filter-complete').click(() => {
  todosStore.dispatch({
    type: SHOW_COMPLETED
  });
});

$('.filter-all').click(() => {
  todosStore.dispatch({
    type: SHOW_ALL
  });
});

//監聽，當dispatch action執行造成state改變時就去取目前state內容，用來更新UI
todosStore.subscribe(() => {
  var state = todosStore.getState();
  var ResultHTML = '';

  for(var i = 0; i < state.todos.length; i++) {
    let HTML = '';
    let item = state.todos[i];
    let status = item.completed ? 'checked' : '';
    let hide = (state.filter === SHOW_COMPLETED && !item.completed) ? 'hide' : '';

    HTML += [
      '
',
      '  <input type="checkbox" class="complete-status"' + status +'>',
      '  ' + item.name + '',
      '  ',
      '    <input class="input-edit" />',
      '    <button class="submit">submit</button>',
      '  ',
      '  <button class="edit">edit</button>',
      '  <button class="delete">delete</button>',
      '
'
    ].join('');
    ResultHTML += HTML;
  }

  $('#todoList .list').html(ResultHTML);
});<|endoftext|>


<commit_before>const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const cssExtract = new ExtractTextPlugin('styles.css');
const scssExtract = new ExtractTextPlugin('main.css');

const APP_PATH = path.join(__dirname, 'app');
const APP_BUILD_PATH = path.join(__dirname, 'build', 'app');

module.exports = {
  entry: {
    vendors: ['react', 'react-dom'],
    app: path.join(APP_PATH, 'index.jsx')
  },
  output: {
    path: APP_BUILD_PATH,
    publicPath: '/public/',
    filename: '[name].js'
  },
  module: {
    // preLoaders: [
    //   {
    //     test: /\.jsx?$/,
    //     loaders: ['eslint'],
    //     exclude: /node_modules/
    //   }
    // ],
    loaders: [
      {
        test: /\.jsx?$/,
        loaders: ['babel'],
        include: APP_PATH,
        query: {
          presets: ['es2015', 'react']
        }
      },
      {
        test: /\.scss$/,
        loader: scssExtract.extract(['css?sourceMap', 'sass?sourceMap'])
        // loaders: [
        //   // 'isomorphic-style-loader',
        //   'style',
        //   'css?sourceMap',
        //   'sass?sourceMap'
        // ]
      },
      {
        test: /\.css$/,
        loader: cssExtract.extract(['css'])
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      VERSION: JSON.stringify('1.0.0'),
      PROD_MODE: false
    }),
    new webpack.optimize.OccurenceOrderPlugin(), // recommanded by webpack
    new webpack.HotModuleReplacementPlugin(),
    new webpack.EnvironmentPlugin([
      'NODE_ENV'
    ]),
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendors'],
      minChunks: Infinity
    }),
    cssExtract,
    scssExtract,
    new HtmlWebpackPlugin({
      title: 'my title',
      template: './app/views/index.html',
      filename: 'index.html',
      inject: 'body'
    })
    // ,
    // new ExtractTextPlugin("styles.css")
  ],
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  // devServer: {
  //   historyApiFallback: true,
  //   hot: true,
  //   inline: true,
  //   progress: true
  //   // ,
  //   // proxy: {
  //   //   '/api/*': {
  //   //     target: 'http://localhost:5000',
  //   //     secure: false
  //   //   }
  //   // }
  // },
  devtool: 'eval-source-map'
};<commit_msg>fix loader/query config<commit_after>const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const cssExtract = new ExtractTextPlugin('styles.css');
const scssExtract = new ExtractTextPlugin('main.css');

const APP_PATH = path.join(__dirname, 'app');
const APP_BUILD_PATH = path.join(__dirname, 'build', 'app');

module.exports = {
  entry: {
    vendors: ['react', 'react-dom'],
    app: path.join(APP_PATH, 'index.jsx')
  },
  output: {
    path: APP_BUILD_PATH,
    publicPath: '/public/',
    filename: '[name].js'
  },
  module: {
    // preLoaders: [
    //   {
    //     test: /\.jsx?$/,
    //     loaders: ['eslint'],
    //     exclude: /node_modules/
    //   }
    // ],
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel',
        include: APP_PATH,
        query: {
          presets: ['es2015', 'react']
        }
      },
      {
        test: /\.scss$/,
        loader: scssExtract.extract(['css?sourceMap', 'sass?sourceMap'])
        // loaders: [
        //   // 'isomorphic-style-loader',
        //   'style',
        //   'css?sourceMap',
        //   'sass?sourceMap'
        // ]
      },
      {
        test: /\.css$/,
        loader: cssExtract.extract(['css'])
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      VERSION: JSON.stringify('1.0.0'),
      PROD_MODE: false
    }),
    new webpack.optimize.OccurenceOrderPlugin(), // recommanded by webpack
    new webpack.HotModuleReplacementPlugin(),
    new webpack.EnvironmentPlugin([
      'NODE_ENV'
    ]),
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendors'],
      minChunks: Infinity
    }),
    cssExtract,
    scssExtract,
    new HtmlWebpackPlugin({
      title: 'my title',
      template: './app/views/index.html',
      filename: 'index.html',
      inject: 'body'
    })
    // ,
    // new ExtractTextPlugin("styles.css")
  ],
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  // devServer: {
  //   historyApiFallback: true,
  //   hot: true,
  //   inline: true,
  //   progress: true
  //   // ,
  //   // proxy: {
  //   //   '/api/*': {
  //   //     target: 'http://localhost:5000',
  //   //     secure: false
  //   //   }
  //   // }
  // },
  devtool: 'eval-source-map'
};<|endoftext|>


<commit_before>/*
 * grunt-appc-cli
 * https://github.com/paulryanwork/grunt-appc-cli
 *
 * Copyright (c) 2015 Paul Ryan
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    var _ = require("lodash");
    var tiObject = {};

    var appcSettings = grunt.config.get("appc-cli");

    grunt.registerTask('ti', 'titanium commands', function(command, job) {
        // Merge task-specific and/or target-specific options with these defaults.

        var options = this.options({}),
            spawn = require('child_process').spawn,
            task,
            done = this.async(),
            cwd = process.cwd(),
            params = ['ti', command],
            settings = appcSettings[job];

        var buildArgs = [];
        _.each(settings.options, function(obj, val) {
            params.push("--"+val + "=" + obj);
        });
        _.extend(buildArgs, params);
        if (settings.args) {
            settings.args.forEach(function(item){
                buildArgs.push(item);
            });
        }

        task = spawn('appc', buildArgs, {
            'cwd' : cwd
        });

        task.stdout.on('data', function(data) {
            if(data.indexOf("Project built successfully") !== -1) {
                done(true);
            }
            grunt.log.ok(data);
        });

        task.stderr.on('error', function(data) {
            grunt.log.error("ti.js " + data);
            done(false);
        });

        task.stdout.on('close', function(code) {
            done(true);
        });

    });
};
<commit_msg>Handling appc ti build buffer output in a better way<commit_after>/*
 * grunt-appc-cli
 * https://github.com/paulryanwork/grunt-appc-cli
 *
 * Copyright (c) 2015 Paul Ryan
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    var _ = require("lodash");
    var tiObject = {};

    var appcSettings = grunt.config.get("appc-cli");

    grunt.registerTask('ti', 'titanium commands', function(command, job) {
        // Merge task-specific and/or target-specific options with these defaults.

        var options = this.options({}),
            spawn = require('child_process').spawn,
            task,
            done = this.async(),
            cwd = process.cwd(),
            params = ['ti', command],
            settings = appcSettings[job];

        var buildArgs = [];
        _.each(settings.options, function(obj, val) {
            params.push("--"+val + "=" + obj);
        });
        _.extend(buildArgs, params);
        if (settings.args) {
            settings.args.forEach(function(item){
                buildArgs.push(item);
            });
        }

        task = spawn('appc', buildArgs, {
            'cwd' : cwd
        });

        task.stdout.on('data', function(data) {
            if(data.indexOf("Project built successfully") !== -1) {
                done(true);
            }
            grunt.log.ok(data);
        });

        task.stderr.on('data', function(data) {
            var status = data.toString().substr(0, data.toString().indexOf(" "));
            switch (status) {
                case "[DEBUG]":
                    grunt.log.debug(data);
                    break;
                case "[INFO]":
                    grunt.log.ok(data);
                    break;
                case "[WARN]":
                    grunt.log.error(data);
                    break;
                case "[ERROR]":
                    grunt.log.error(data);
                    done(false);
                    break;
                default:
                    grunt.log.ok(data);
            }
        });

        task.stderr.on('error', function(data) {
            grunt.log.error(data);
            done(false);
        });

        task.stdout.on('close', function(code) {
            done(true);
        });

    });
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Development-only webpack settings.
 */
const webpack = require('webpack');
const config = require('./webpack.config');
const Visualizer = require('webpack-visualizer-plugin');

config.devtool = 'cheap-module-eval-source-map';
config.entry.unshift('webpack-hot-middleware/client');
config.plugins = [
  new Visualizer(),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin(),
  new webpack.DefinePlugin({
    'process.env': {
      NODE_ENV: JSON.stringify('development')
    }
  })
];

module.exports = config;
<commit_msg>gt - Update dev config for Webpack 2.2<commit_after>'use strict';

/**
 * Development-only webpack settings.
 */
const webpack = require('webpack');
const config = require('./webpack.config');
const Visualizer = require('webpack-visualizer-plugin');

config.devtool = 'cheap-module-eval-source-map';
config.entry.unshift('webpack-hot-middleware/client');
config.plugins = [
  new Visualizer(),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoEmitOnErrorsPlugin(),
  new webpack.DefinePlugin({
    'process.env': {
      NODE_ENV: JSON.stringify('development')
    }
  })
];

module.exports = config;
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 Guyon Roche
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
'use strict';

var _ = require('underscore');

var TextXform = require('./text-xform');
var RichTextXform = require('./rich-text-xform');

var utils = require('../../utils/utils');
var BaseXform = require('./base-xform');

// <si>
//   <r></r><r></r>...
// </si>
// <si>
//   <t></t>
// </si>

var SharedStringXform = module.exports = function(model) {
  this.model = model;

  this.map = {
    r: new RichTextXform(),
    t: new TextXform()
  };
};

utils.inherits(SharedStringXform, BaseXform, {

  write: function(xmlStream, model) {
    model = model || this.model;

    xmlStream.openNode('si');
    if (model.richText) {
      var r = this.map.r;
      _.each(model.richText, function(text) {
        r.write(xmlStream, text);
      });
    } else if (model) {
      this.map.t.write(xmlStream, model);
    }
    xmlStream.closeNode();
  },

  parseOpen: function(node) {
    var name = node.name;
    if (this.parser) {
      this.parser.parseOpen(node);
      return true;
    } else {
      switch(name) {
        case 'si':
          this.model = {};
          return true;
        case 'r':
          this.model.richText = this.model.richText || [];
          this.parser  = this.map.r;
          this.parser.parseOpen(node);
          return true;
        case 't':
          this.parser = this.map.t;
          this.parser.parseOpen(node);
          return true;
        default:
          return false;
      }
    }
  },
  parseText: function(text) {
    if (this.parser) {
      this.parser.parseText(text);
    }
  },
  parseClose: function(name) {
    if (this.parser) {
      if (!this.parser.parseClose(name)) {
        switch(name) {
          case 'r':
            this.model.richText.push(this.parser.model);
            break;
          case 't':
            this.model = this.parser.model;
            break;
        }
        this.parser = undefined;
      }
      return true;
    } else {
      switch(name) {
        case 'si':
          return false;
        default:
          return true;
      }
    }
  }
});
<commit_msg>remove extra spaces<commit_after>/**
 * Copyright (c) 2015 Guyon Roche
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
'use strict';

var _ = require('underscore');

var TextXform = require('./text-xform');
var RichTextXform = require('./rich-text-xform');

var utils = require('../../utils/utils');
var BaseXform = require('./base-xform');

// <si>
//   <r></r><r></r>...
// </si>
// <si>
//   <t></t>
// </si>

var SharedStringXform = module.exports = function(model) {
  this.model = model;

  this.map = {
    r: new RichTextXform(),
    t: new TextXform()
  };
};

utils.inherits(SharedStringXform, BaseXform, {

  write: function(xmlStream, model) {
    model = model || this.model;

    xmlStream.openNode('si');
    if (model.richText) {
      var r = this.map.r;
      _.each(model.richText, function(text) {
        r.write(xmlStream, text);
      });
    } else if (model) {
      this.map.t.write(xmlStream, model);
    }
    xmlStream.closeNode();
  },

  parseOpen: function(node) {
    var name = node.name;
    if (this.parser) {
      this.parser.parseOpen(node);
      return true;
    } else {
      switch(name) {
        case 'si':
          this.model = {};
          return true;
        case 'r':
          this.model.richText = this.model.richText || [];
          this.parser  = this.map.r;
          this.parser.parseOpen(node);
          return true;
        case 't':
          this.parser = this.map.t;
          this.parser.parseOpen(node);
          return true;
        default:
          return false;
      }
    }
  },
  parseText: function(text) {
    if (this.parser) {
      this.parser.parseText(text);
    }
  },
  parseClose: function(name) {
    if (this.parser) {
      if (!this.parser.parseClose(name)) {
        switch(name) {
          case 'r':
            this.model.richText.push(this.parser.model);
            break;
          case 't':
            this.model = this.parser.model;
            break;
        }
        this.parser = undefined;
      }
      return true;
    } else {
      switch(name) {
        case 'si':
          return false;
        default:
          return true;
      }
    }
  }
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

// released `uiw`

// 1. Copy `README.md` to the `/packages/core/` directory.
// 2. Creacte document static resource.
// 3. Entry the `/packages/core/` and run the `npm run build` command.
// 4. Copy static resource to the `/packages/core/docs` directory.

const fs = require('fs-extra');
const { join } = require('path');
const { spawn } = require('child_process')

const libPath = join(process.cwd(), 'packages', 'core');
const libReadmePath = join(libPath, 'README.md');
const readmePath = join(process.cwd(), 'README.md');

const libDocsPath = join(libPath, 'docs');
const docsPath = join(process.cwd(), 'dist');

const uiwPkg = join(libPath, 'package.json');
const docVersion = join(process.cwd(), 'src', 'version.json');

(async () => {
  try {
    const readmeContent = await fs.readFile(readmePath);
    await fs.outputFile(libReadmePath, readmeContent);

    console.log(`> Publish ${uiwPkgContent.version} v${uiwPkgContent.version}`);
    // Modify document version data.
    const uiwPkgContent = await fs.readJson(uiwPkg);
    const versionList = await fs.readJson(docVersion);
    if (!versionList.includes(uiwPkgContent.version)) {
      versionList.unshift(uiwPkgContent.version);
      await fs.outputJson(docVersion, versionList);
    }
    /**
     * Run babel over the ./packages/core/src directory and output
     * compiled common js files to ./packages/core/lib/cjs.
     */
    await execute(`cd ${libPath} && npm run build-cjs`);
    /**
     * Run babel over the ./packages/core/src directory and output
     * compiled es modules (but otherwise es5) to ./packages/core/lib/esm
     */
    await execute(`cd ${libPath} && npm run build-esm`);
    /**
     * Bundles a minified and unminified version of [uiw] including
     * all it's immediate dependencies (excluding React, ReactDOM, etc)
     */
    await execute(`cd ${libPath} && npm run bundle`);
    await execute(`cd ${libPath} && npm run bundle:min`);
    /**
     * Run KKT over the ./src directory and output compiled documents files to ./dist
     */
    await execute('npm run build');
    await fs.copy(docsPath, libDocsPath);
    // Publish the documentation website.
    await execute('npm run deploy');
  } catch (error) {
    console.log('error:', error);
  }
})();

function execute(command) {
  return new Promise((resolve, reject) => {
    const subProcess = spawn('bash');
    function onData(data) {
      process.stdout.write(data);
    }
    subProcess.on('error', (error) => {
      reject(new Error(`command failed: ${command}; ${error.message ? error.message : ''}`));
    });
    subProcess.stdout.on('data', onData);
    subProcess.stderr.on('data', onData);
    subProcess.on('close', (code) => {
      resolve(code);
    });
    subProcess.stdin.write(`${command} \n`);
    subProcess.stdin.end();
  });
}
<commit_msg>chore: Update released script.<commit_after>#!/usr/bin/env node

// released `uiw`

// 1. Copy `README.md` to the `/packages/core/` directory.
// 2. Creacte document static resource.
// 3. Entry the `/packages/core/` and run the `npm run build` command.
// 4. Copy static resource to the `/packages/core/docs` directory.

const fs = require('fs-extra');
const { join } = require('path');
const { spawn } = require('child_process')

const libPath = join(process.cwd(), 'packages', 'core');
const libReadmePath = join(libPath, 'README.md');
const readmePath = join(process.cwd(), 'README.md');

const libDocsPath = join(libPath, 'docs');
const docsPath = join(process.cwd(), 'dist');

const uiwPkg = join(libPath, 'package.json');
const docVersion = join(process.cwd(), 'src', 'version.json');

(async () => {
  try {
    const readmeContent = await fs.readFile(readmePath);
    await fs.outputFile(libReadmePath, readmeContent);

    // Modify document version data.
    const uiwPkgContent = await fs.readJson(uiwPkg);
    console.log(`> Publish ${uiwPkgContent.version} v${uiwPkgContent.version}`);
    const versionList = await fs.readJson(docVersion);
    if (!versionList.includes(uiwPkgContent.version)) {
      versionList.unshift(uiwPkgContent.version);
      await fs.outputJson(docVersion, versionList);
    }
    /**
     * Run babel over the ./packages/core/src directory and output
     * compiled common js files to ./packages/core/lib/cjs.
     */
    await execute(`cd ${libPath} && npm run build-cjs`);
    /**
     * Run babel over the ./packages/core/src directory and output
     * compiled es modules (but otherwise es5) to ./packages/core/lib/esm
     */
    await execute(`cd ${libPath} && npm run build-esm`);
    /**
     * Bundles a minified and unminified version of [uiw] including
     * all it's immediate dependencies (excluding React, ReactDOM, etc)
     */
    await execute(`cd ${libPath} && npm run bundle`);
    await execute(`cd ${libPath} && npm run bundle:min`);
    /**
     * Run KKT over the ./src directory and output compiled documents files to ./dist
     */
    await execute('npm run build');
    await fs.copy(docsPath, libDocsPath);
    // Publish the documentation website.
    await execute('npm run deploy');
    await execute(`git tag -a v${uiwPkgContent.version} -m "released v${uiwPkgContent.version}"`);
    await execute('git push --tags');
    await execute(`cd ${libPath} && npm publish`);
  } catch (error) {
    console.log('error:', error);
  }
})();

function execute(command) {
  return new Promise((resolve, reject) => {
    const subProcess = spawn('bash');
    function onData(data) {
      process.stdout.write(data);
    }
    subProcess.on('error', (error) => {
      reject(new Error(`command failed: ${command}; ${error.message ? error.message : ''}`));
    });
    subProcess.stdout.on('data', onData);
    subProcess.stderr.on('data', onData);
    subProcess.on('close', (code) => {
      resolve(code);
    });
    subProcess.stdin.write(`${command} \n`);
    subProcess.stdin.end();
  });
}
<|endoftext|>


<commit_before>/*
var blocks = {
  "regular":[
    {"start":"7:45","end":"9:06","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":9,"endMinute":6},
    {"start":"9:06","end":"9:16","name":"Break","bold":true,"startHour":9,"startMinute":6,"endHour":9,"endMinute":16},
    {"start":"9:21","end":"10:53","name":"Block 2","bold":false,"startHour":9,"startMinute":21,"endHour":10,"endMinute":53},
    {"start":"10:58","end":"12:19","name":"Block 3","bold":false,"startHour":10,"startMinute":58,"endHour":12,"endMinute":19},
    {"start":"12:19","end":"12:44","name":"Intervention","bold":false,"startHour":12,"startMinute":19,"endHour":12,"endMinute":44},
    {"start":"12:44","end":"1:14","name":"Lunch","bold":true,"startHour":12,"startMinute":44,"endHour":13,"endMinute":14},
    {"start":"1:19","end":"2:40","name":"Block 4","bold":false,"startHour":13,"startMinute":19,"endHour":14,"endMinute":40}
  ],

  "articulation":[
    {"start":"7:45","end":"8:53","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":8,"endMinute":53},
    {"start":"8:58","end":"10:14","name":"Block 2","bold":false,"startHour":8,"startMinute":58,"endHour":10,"endMinute":14},
    {"start":"10:14","end":"10:34","name":"Break/Lunch","bold":true,"startHour":10,"startMinute":14,"endHour":10,"endMinute":34},
    {"start":"10:39","end":"11:47","name":"Block 3","bold":false,"startHour":10,"startMinute":39,"endHour":11,"endMinute":47},
    {"start":"11:52","end":"1:00","name":"Block 4","bold":false,"startHour":11,"startMinute":52,"endHour":13,"endMinute":0}
  ]
};
*/

// Maintenance Note: Change all `var data = blocks` to `var data = JSON.parse(blocks);` when editing code

function getTimeAdv (date) {
  return [ date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() ];
}

function timeUpdate () {
  $('#time').html('The time is currently ' + new Date().toLocaleTimeString() + '.');
  $('#next').html(getNext());
}

function getNext () {
  var i;
  var cycle = true;
  var data = blocks;
  var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
  var date = new Date();
  var render;
  var currentEvent;
  var time = getTimeAdv(date);

  if (date.getDay() !== 0 || date.getDay() !== 6) {
    if (date.getDay() === 1) {
      render = data.articulation;
    } else {
      render = data.regular;
    }

    var currentTime = 0;
    var nextTime = 0;
    var hoursLeft = 0;
    var minutesLeft = 0;
    for (i = 0; i < render.length; i++) {
      currentTime = (time[0] * 60) + time[1];
      nextTime = (render[i].endHour * 60) + render[i].endMinute;
      if (currentTime < nextTime) {
        hoursLeft = Math.floor((nextTime - currentTime) / 60);
        minutesLeft = Math.floor((nextTime - (hoursLeft * 60)) - currentTime);
        if (hoursLeft === 0) {
          return minutesLeft + ' minutes until the end of ' + render[i].name;
        } else if (hoursLeft !== 0) {
          return hoursLeft + ' hours and ' + minutesLeft + ' minutes until the end of ' + render[i].name;
        }
      }
    }
    return 'School is over.';
  }
}

$(document).ready(function () {
  var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
  var data = blocks;
  var i;
  var date = new Date();
  var render;
  if (date.getDay() === 1) {
    render = data.articulation;
    for (i = 0; i < render.length; i++) {
      if (!render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      } else if (render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      }
    }
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
  } else if (date.getDay() === 2 || date.getDay() === 3 || date.getDay() === 4 || date.getDay() === 5) {
    render = data.regular;
    for (i = 0; i < render.length; i++) {
      if (!render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      } else if (render[i].bold) {
        $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
      }
    }
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
  } else if (date.getDay() === 0 || date.getDay() === 6) {
    document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
    $('#text').show();
    $('#text').text("No school today, it's " + days[date.getDay()] + "!");
  }

  timeUpdate();

  var clock = setInterval(function () {
    timeUpdate();
  }, 500);
});
<commit_msg>Update schedule.js<commit_after>+/*
  var blocks = {
    "regular":[
      {"start":"7:45","end":"9:06","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":9,"endMinute":6},
     {"start":"9:06","end":"9:16","name":"Break","bold":true,"startHour":9,"startMinute":6,"endHour":9,"endMinute":16},
     {"start":"9:21","end":"10:53","name":"Block 2","bold":false,"startHour":9,"startMinute":21,"endHour":10,"endMinute":53},
     {"start":"10:58","end":"12:19","name":"Block 3","bold":false,"startHour":10,"startMinute":58,"endHour":12,"endMinute":19},
     {"start":"12:19","end":"12:44","name":"Intervention","bold":false,"startHour":12,"startMinute":19,"endHour":12,"endMinute":44},
     {"start":"12:44","end":"1:14","name":"Lunch","bold":true,"startHour":12,"startMinute":44,"endHour":13,"endMinute":14},
     {"start":"1:19","end":"2:40","name":"Block 4","bold":false,"startHour":13,"startMinute":19,"endHour":14,"endMinute":40}
   ],

   "articulation":[
     {"start":"7:45","end":"8:53","name":"Block 1","bold":false,"startHour":7,"startMinute":45,"endHour":8,"endMinute":53},
     {"start":"8:58","end":"10:14","name":"Block 2","bold":false,"startHour":8,"startMinute":58,"endHour":10,"endMinute":14},
     {"start":"10:14","end":"10:34","name":"Break/Lunch","bold":true,"startHour":10,"startMinute":14,"endHour":10,"endMinute":34},
     {"start":"10:39","end":"11:47","name":"Block 3","bold":false,"startHour":10,"startMinute":39,"endHour":11,"endMinute":47},
      {"start":"11:52","end":"1:00","name":"Block 4","bold":false,"startHour":11,"startMinute":52,"endHour":13,"endMinute":0}
    ]
  };
 +*/

  // Maintenance Note: Change all `var data = blocks` to `var data = JSON.parse(blocks);` when editing code

 function getTimeAdv (date) {
   return [ date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds() ];
 }

 function getNext () {
   var i;
   var cycle = true;
   var data = blocks;
   var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
   var date = new Date();
   var render;
   var currentEvent;
   var time = getTimeAdv(date);

   if (date.getDay() !== 0 || date.getDay() !== 6) {
     if (date.getDay() === 1) {
       render = data.articulation;
     } else {
       render = data.regular;
     }

     var currentTime = 0;
     var nextTime = 0;
     var hoursLeft = 0;
     var minutesLeft = 0;
     for (i = 0; i < render.length; i++) {
       currentTime = (time[0] * 60) + time[1];
       nextTime = (render[i].endHour * 60) + render[i].endMinute;
       if (currentTime < nextTime) {
         hoursLeft = Math.floor((nextTime - currentTime) / 60);
         minutesLeft = Math.floor((nextTime - (hoursLeft * 60)) - currentTime);
         if (hoursLeft === 0) {
           return minutesLeft + ' minutes until the end of ' + render[i].name;
         } else if (hoursLeft !== 0) {
           return hoursLeft + ' hours and ' + minutesLeft + ' minutes until the end of ' + render[i].name;
         }
       }
     }
     return 'School is over.';
   }
 }

 $(document).ready(function () {
   var days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
   var data = blocks;
   var i;
   var date = new Date();
   var render;
   if (date.getDay() === 1) {
     render = data.articulation;
     for (i = 0; i < render.length; i++) {
       if (!render[i].bold) {
         $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
       } else if (render[i].bold) {
         $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
       }
     }
     document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
   } else if (date.getDay() === 2 || date.getDay() === 3 || date.getDay() === 4 || date.getDay() === 5) {
     render = data.regular;
     for (i = 0; i < render.length; i++) {
       if (!render[i].bold) {
         $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
       } else if (render[i].bold) {
         $('#display').append('
' + render[i].name + ':	' + render[i].start + '-' + render[i].end + '
');
       }
     }
     document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
   } else if (date.getDay() === 0 || date.getDay() === 6) {
     document.getElementsByTagName('title')[0].innerHTML += ': ' + days[new Date().getDay()];
     $('#text').show();
     $('#text').text("No school today, it's " + days[date.getDay()] + "!");
   }
 });

 var timeUpdate = setInterval(function () {
   $('#time').html('The time is currently ' + new Date().toLocaleTimeString() + '.');
   $('#next').html(getNext());
 }, 500);
<|endoftext|>


<commit_before>Frontend.App = Class.extend({
	appData: {},
	_controllers: {},
	_pubSubBroker: null,
	PageController: null,
	_errorHandler: null,
	/**
	 * Holds an instance of the router class
	 *
	 * @var Frontend.Router
	 */
	Router: null,
	/**
	 * Class constructor
	 *
	 * @param {ob} appData Application JSON vars from the backend
	 * @return void
	 */
	init: function(appData) {
		this.appData = appData;
		this._pubSubBroker = new Frontend.PublishSubscribeBroker();
		this.Router = new Frontend.Router(appData);
		this.UIBlocker = new Frontend.UIBlocker();
	},

	/**
	 * Called on document ready.
	 *
	 * @return void
	 */
	startup: function() {
		// initialize the main controller, if available
		this.PageController = this._loadController(this.appData);
	},

	/**
	 * Initialize a controller based on the frontendData
	 *
	 * @returns void
	 */
	_loadController: function(frontendData, parentController, instanceId) {
		var actionControllerName = camelCase(frontendData.request.controller) + camelCase(frontendData.request.action) + 'Controller';
		var controller = null;

		if (frontendData.request.plugin && window['App']['Controllers'][ frontendData.request.plugin ] && window['App']['Controllers'][ frontendData.request.plugin ][ actionControllerName ]) {
			if (this._controllers[actionControllerName] == undefined) {
				this._controllers[actionControllerName] = [];
			}
			this._controllers[actionControllerName][this._controllers[actionControllerName].length] = new window['App']['Controllers'][ frontendData.request.plugin ][ actionControllerName ](frontendData, parentController, instanceId);
			controller = this._controllers[actionControllerName];
		}
		else if (window['App']['Controllers'][ actionControllerName ]) {
			if (this._controllers[actionControllerName] == undefined) {
				this._controllers[actionControllerName] = [];
			}
			this._controllers[actionControllerName][this._controllers[actionControllerName].length] = new window['App']['Controllers'][ actionControllerName ](frontendData, parentController, instanceId);
			controller = this._controllers[actionControllerName];
		}
		else {
			this._controllers[ 'AppController' ] = new Frontend.AppController(frontendData, parentController);
			controller = this._controllers[ 'AppController' ];
		}
		return controller;
	},
	/**
	 * Makes an AJAX request and triggers the _onWidgetLoaded() event
	 *
	 * @param mixed url			Either a string url or a Router compatible url object
	 * @param obj	options		options object, all keys are optional
	 *							- target:		A DOM element where the resulting
	 *											HTML will be inserted.
	 *							- onComplete	This function will be called if the json action
	 *											request was successful. Will receive
	 *											the json action controller as an argument, if available.
	 *							- data			POST data
	 *							- onError		This function will be called if an error
	 *											occured, it will receive the ajax response
	 *											as an argument.
	 * @return void
	 */
	loadJsonAction: function(url, options) {
		if (!options) {
			var options = {};
		}
		var options = jQuery.extend({}, {
			target: null,
			onComplete: null,
			data: null,
			onError: null,
			parentController: null,
			initController: true,
			replaceTarget: false,
			dialog: null
		}, options);
		if (typeof url == 'object') {
			//url.prefix = 'json_action/';
			if (typeof url.query !== 'object') {
				url.query = {};
			}
			url.query.json_action = 1;
		}
		this.request(url, options.data, function(response) {
			switch(response.code) {
				case 'success':
					this._onJsonActionLoaded(response, options);
					break;
				default:
					if (typeof options.onError == 'function') {
						options.onError(response);
					}
					else if (this._errorHandler != null) {
						this._errorHandler.handleError(response);
					}
					console.log('loadJsonAction error: ', response);
			}
		}.bind(this));
	},
	/**
	 * Triggered from loadJsonAction()
	 *
	 * @param obj response	The AJAX response
	 * @param obj options	The loadJsonAction() options
	 * @return void
	 */
	_onJsonActionLoaded: function(response, options) {
		if (options.replaceTarget === true && options.target !== null) {
			options.target.replaceWith(response.data.html);
		}
		else if (options.target !== null) {
			options.target.html(response.data.html);
		}
		var controller = null;
		if (typeof response.data.frontendData == 'object' && options.initController) {
            var instanceId = $(options.target).find('.controller').data('instance-id');
			setTimeout(function() {
				controller = this._loadController(response.data.frontendData, options.parentController, instanceId);
			}.bind(this), 10);
		}
		if (typeof options.onComplete == 'function') {
			options.onComplete(controller, response);
		}
	},

	/**
	 * Makes an AJAX request to the server and returns the results.
	 *
	 * @param mixed		url		Either a string url or a Router-compatible url object
	 * @param Object	data	(optional)	POST data
	 * @param Function	responseCallback	The function which will receive the response
	 * @return void
	 */
	request: function(url, data, responseCallback) {
		if (typeof url == 'object') {
			var url = this.Router.url(url);
		}
		var requestType = (data !== null) ? 'POST' : 'GET';

		var requestData = {
			type: requestType,
			url: url,
			postData: data
		};

		var ajaxData = {
			type: requestType,
			data: data,
			url: url,
			dataType: 'json',
			cache: false,
			context: this,
			success: function(response, textStatus, jqXHR) {
				if (response == null) {
					var response = {
						code: 'error'
					};
				}
				response.requestData = requestData;
				if (typeof responseCallback == 'function') {
					responseCallback(response);
				}
			},
			error: function(jqXHR, textStatus, errorThrown) {
				var responseText = jqXHR.responseText;
				var response = null;
				try {
					response = $.parseJSON(responseText);
				} catch (exception) {
					response = {
						code: 'error',
						exception: exception,
						requestData: requestData,
						responseText: responseText
					};
				}
				if (typeof response != 'object') {
					response = {
						code: 'error',
						requestData: requestData,
						responseText: responseText
					};
				}
				if (typeof responseCallback == 'function') {
					responseCallback(response);
				}
			}
		};

		if ((window.FormData !== undefined) && (data instanceof FormData)) {
			$.extend(ajaxData, {processData: false, contentType: false});
		}

		$.ajax(ajaxData);
	},
	/**
	 * Redirects the user to another page
	 *
	 * @param string|object url		Either the URL as a string or a router-compatible url.
	 * @return void
	 */
	redirect: function(url) {
		if (typeof url == 'object') {
			url = this.Router.url(url);
		}
		window.location.replace(url);
	},
	/**
	 * Proxy for PublishSubscribeBroker::subscribe()
	 *
	 * @return SubscriptionHandle	Containing topic and subscription id (used for unsubscribing)
	 */
	subscribeEvent: function(topic, handler, scope) {
		this._pubSubBroker.subscribe(topic, handler, scope);
	},

	/**
	 * Proxy for PublishSubscribeBroker::publish()
	 *
	 * @return void
	 */
	publishEvent: function(topic, data) {
		this._pubSubBroker.publish(topic, data);
	},
	/**
	 * Inject an app-specific error handler, which will be used to delegate
	 * the error handling to.
	 *
	 * @param Object	errorHandler	Must implement handleError(response)
	 * @return void
	 */
	registerErrorHandler: function(errorHandler) {
		this._errorHandler = errorHandler;
	}
});
<commit_msg>fix multiple instances support<commit_after>Frontend.App = Class.extend({
	appData: {},
	_controllers: {},
	_pubSubBroker: null,
	PageController: null,
	_errorHandler: null,
	/**
	 * Holds an instance of the router class
	 *
	 * @var Frontend.Router
	 */
	Router: null,
	/**
	 * Class constructor
	 *
	 * @param {ob} appData Application JSON vars from the backend
	 * @return void
	 */
	init: function(appData) {
		this.appData = appData;
		this._pubSubBroker = new Frontend.PublishSubscribeBroker();
		this.Router = new Frontend.Router(appData);
		this.UIBlocker = new Frontend.UIBlocker();
	},

	/**
	 * Called on document ready.
	 *
	 * @return void
	 */
	startup: function() {
		// initialize the main controller, if available
		this.PageController = this._loadController(this.appData);
	},

	/**
	 * Initialize a controller based on the frontendData
	 *
	 * @returns void
	 */
	_loadController: function(frontendData, parentController, instanceId) {
		var actionControllerName = camelCase(frontendData.request.controller) + camelCase(frontendData.request.action) + 'Controller';
		var controller = null;

		if (frontendData.request.plugin && window['App']['Controllers'][ frontendData.request.plugin ] && window['App']['Controllers'][ frontendData.request.plugin ][ actionControllerName ]) {
			if (this._controllers[actionControllerName] == undefined) {
				this._controllers[actionControllerName] = [];
			}
			this._controllers[actionControllerName][this._controllers[actionControllerName].length] = new window['App']['Controllers'][ frontendData.request.plugin ][ actionControllerName ](frontendData, parentController, instanceId);
			controller = this._controllers[actionControllerName];
		}
		else if (window['App']['Controllers'][ actionControllerName ]) {
			if (this._controllers[actionControllerName] == undefined) {
				this._controllers[actionControllerName] = [];
			}
			this._controllers[actionControllerName][this._controllers[actionControllerName].length] = new window['App']['Controllers'][ actionControllerName ](frontendData, parentController, instanceId);
			controller = this._controllers[actionControllerName];
		}
		else {
			this._controllers[ 'AppController' ] = new Frontend.AppController(frontendData, parentController);
			controller = this._controllers[ 'AppController' ];
		}
		return controller;
	},
	/**
	 * Makes an AJAX request and triggers the _onWidgetLoaded() event
	 *
	 * @param mixed url			Either a string url or a Router compatible url object
	 * @param obj	options		options object, all keys are optional
	 *							- target:		A DOM element where the resulting
	 *											HTML will be inserted.
	 *							- onComplete	This function will be called if the json action
	 *											request was successful. Will receive
	 *											the json action controller as an argument, if available.
	 *							- data			POST data
	 *							- onError		This function will be called if an error
	 *											occured, it will receive the ajax response
	 *											as an argument.
	 * @return void
	 */
	loadJsonAction: function(url, options) {
		if (!options) {
			var options = {};
		}
		var options = jQuery.extend({}, {
			target: null,
			onComplete: null,
			data: null,
			onError: null,
			parentController: null,
			initController: true,
			replaceTarget: false,
			dialog: null
		}, options);
		if (typeof url == 'object') {
			//url.prefix = 'json_action/';
			if (typeof url.query !== 'object') {
				url.query = {};
			}
			url.query.json_action = 1;
		}
		this.request(url, options.data, function(response) {
			switch(response.code) {
				case 'success':
					this._onJsonActionLoaded(response, options);
					break;
				default:
					if (typeof options.onError == 'function') {
						options.onError(response);
					}
					else if (this._errorHandler != null) {
						this._errorHandler.handleError(response);
					}
					console.log('loadJsonAction error: ', response);
			}
		}.bind(this));
	},
	/**
	 * Triggered from loadJsonAction()
	 *
	 * @param obj response	The AJAX response
	 * @param obj options	The loadJsonAction() options
	 * @return void
	 */
	_onJsonActionLoaded: function(response, options) {
		if (options.replaceTarget === true && options.target !== null) {
			options.target.replaceWith(response.data.html);
		}
		else if (options.target !== null) {
			options.target.html(response.data.html);
		}
		var controller = null;
		if (typeof response.data.frontendData == 'object' && options.initController) {
			var instanceId = $(response.data.html).data('instance-id');
			setTimeout(function() {
				controller = this._loadController(response.data.frontendData, options.parentController, instanceId);
			}.bind(this), 10);
		}
		if (typeof options.onComplete == 'function') {
			options.onComplete(controller, response);
		}
	},

	/**
	 * Makes an AJAX request to the server and returns the results.
	 *
	 * @param mixed		url		Either a string url or a Router-compatible url object
	 * @param Object	data	(optional)	POST data
	 * @param Function	responseCallback	The function which will receive the response
	 * @return void
	 */
	request: function(url, data, responseCallback) {
		if (typeof url == 'object') {
			var url = this.Router.url(url);
		}
		var requestType = (data !== null) ? 'POST' : 'GET';

		var requestData = {
			type: requestType,
			url: url,
			postData: data
		};

		var ajaxData = {
			type: requestType,
			data: data,
			url: url,
			dataType: 'json',
			cache: false,
			context: this,
			success: function(response, textStatus, jqXHR) {
				if (response == null) {
					var response = {
						code: 'error'
					};
				}
				response.requestData = requestData;
				if (typeof responseCallback == 'function') {
					responseCallback(response);
				}
			},
			error: function(jqXHR, textStatus, errorThrown) {
				var responseText = jqXHR.responseText;
				var response = null;
				try {
					response = $.parseJSON(responseText);
				} catch (exception) {
					response = {
						code: 'error',
						exception: exception,
						requestData: requestData,
						responseText: responseText
					};
				}
				if (typeof response != 'object') {
					response = {
						code: 'error',
						requestData: requestData,
						responseText: responseText
					};
				}
				if (typeof responseCallback == 'function') {
					responseCallback(response);
				}
			}
		};

		if ((window.FormData !== undefined) && (data instanceof FormData)) {
			$.extend(ajaxData, {processData: false, contentType: false});
		}

		$.ajax(ajaxData);
	},
	/**
	 * Redirects the user to another page
	 *
	 * @param string|object url		Either the URL as a string or a router-compatible url.
	 * @return void
	 */
	redirect: function(url) {
		if (typeof url == 'object') {
			url = this.Router.url(url);
		}
		window.location.replace(url);
	},
	/**
	 * Proxy for PublishSubscribeBroker::subscribe()
	 *
	 * @return SubscriptionHandle	Containing topic and subscription id (used for unsubscribing)
	 */
	subscribeEvent: function(topic, handler, scope) {
		this._pubSubBroker.subscribe(topic, handler, scope);
	},

	/**
	 * Proxy for PublishSubscribeBroker::publish()
	 *
	 * @return void
	 */
	publishEvent: function(topic, data) {
		this._pubSubBroker.publish(topic, data);
	},
	/**
	 * Inject an app-specific error handler, which will be used to delegate
	 * the error handling to.
	 *
	 * @param Object	errorHandler	Must implement handleError(response)
	 * @return void
	 */
	registerErrorHandler: function(errorHandler) {
		this._errorHandler = errorHandler;
	}
});
<|endoftext|>


<commit_before>var height = $(window).height();
var width = $(window).width();
d3.select(".can")
		.attr("width",width)
		.attr("height",height);
d3.select("svg .canvas")
		.attr("width",width)
		.attr("height",height);
var rectangles = [];
//I know you can do it using a color scale but I think this way you get more control
var colorH = d3.scale.linear().domain([0,height]).range([0,255]);
var colorW = d3.scale.linear().domain([0,width]).range([0,255]);
var colorB = d3.scale.linear().domain([0,(width+height)]).range([0,255]);
function toRGB (color){
	color = color.replace("rgb(","");
	color = color.replace(")","");
	color = color.split(",");
	return color.map(function (x) {
    		return parseInt(x);
		});
}
function colorChanger(x,y,sign,amount){
	var currentColor  = rectangles[x][y].attr("fill");
	var colors = toRGB(currentColor);
	var k = colors[0];
	var l = colors[1];
	if(sign == '+'){
		k = colors[0]+amount;
		l = colors[1]+amount;
	}else{
		k = colors[0]-amount;
		l = colors[1]-amount;
	}

	var newColor = "rgb("+k+","+l+","+Math.floor((l+k)/2)+")";	return newColor;;
}
function currentSquare(x,y,width,height,sign){
	for (var i = x-width; i <= x+width; ++i) {
		rectangles[y-height-1][i].attr("fill",colorChanger(y-height-1,i,sign,10));
		rectangles[y+height][i].attr("fill",colorChanger(y+height,i,sign,10));
	};
	for (var i = y-height; i < y+height; ++i) {
		rectangles[i][x-width].attr("fill",colorChanger(i,x-width,sign,10));
		rectangles[i][x+width].attr("fill",colorChanger(i,x+width,sign,10));
	};
}
function rippleEffect(x,y){
	/*for(var k = 0; k < 10; ++k){
		currentSquare(x,y,k,k,'+');
		currentSquare(x,y,k-2,k-2,'-');
	}*/
//	for(var i = 0; i < 15; i++){
		currentCircle(x,y,3,'+',2);
//	}
}
function calculateDistance(x,y,cx,cy,radius,Limit){
	var distance = Math.sqrt(Math.pow(y-cy,2) + Math.pow(x-cx,2)); //Distance formula
	if(Limit > 100){return -1};
	if(distance > radius){
		return calculateDistance(x,y,cx,--cy,radius,++Limit);
	}
	return cy;
}

function currentCircle(x0,y0,radius,sign,amount){
	//MidPoint_Circle_Algarithm
	var x = radius;
	var y = 0;
	var decisionOver2 = 1-x;
	while(x >= y){
		rectangles[x+x0][y+y0].attr("fill",colorChanger(x+x0,x+y0,sign,10));
		rectangles[y+x0][x+y0].attr("fill",colorChanger(y+x0,x+x0,sign,10));
		rectangles[-x+x0][y+y0].attr("fill",colorChanger(-x+x0,x+y0,sign,10));
		rectangles[-y+x0][x+y0].attr("fill",colorChanger(-y+x0,x+x0,sign,10));
		rectangles[-x+x0][y+y0].attr("fill",colorChanger(-x+x0,-x+y0,sign,10));
		rectangles[-y+x0][x+y0].attr("fill",colorChanger(-y+x0,-x+x0,sign,10));
		rectangles[x+x0][y+y0].attr("fill",colorChanger(x+x0,-x+y0,sign,10));
		rectangles[y+x0][x+y0].attr("fill",colorChanger(y+x0,-x+x0,sign,10));
	y++;
	if(decisionOver2 <0){
		decisionOver2 += 2 * y + 1;
	}else{
		x--;
		decisionOver2 += 2 * (y - x) +1;
	}
	}
}

var squarerectangles = {width: 10, height: 10};
var x = 0;
var y = 0;
for (var i = 0; i < width; i = i + squarerectangles.width){
	var row = [];
	for (var k = 0; k < height; k = k + squarerectangles.height){
		row.push(d3.select(".canvas").append("circle")
			.attr("fill",function(){
				return "rgb("+Math.floor(colorW(i))+","+Math.floor(colorH(k))+","+Math.floor(colorB((i+k)))+")";
			})
			.attr("cx",i)
			.attr("cy",k)
			.attr("r",squarerectangles.width)
			.attr("id",x+++","+y)
			.on("click",function(d){
				var position = this.id.split(",");
				rippleEffect(parseInt(position[0]),parseInt(position[1]))
			})
			)
		}
	y++;
	rectangles.push(row);
	row = [];
	x = 0;
}<commit_msg>made it awesome<commit_after>var height = $(window).height();
var width = $(window).width();
d3.select(".can")
		.attr("width",width)
		.attr("height",height);
d3.select("svg .canvas")
		.attr("width",width)
		.attr("height",height);
var rectangles = [];
//I know you can do it using a color scale but I think this way you get more control
var colorH = d3.scale.linear().domain([0,height]).range([0,255]);
var colorW = d3.scale.linear().domain([0,width]).range([0,255]);
var colorB = d3.scale.linear().domain([0,(width+height)]).range([0,255]);
function toRGB (color){
	color = color.replace("rgb(","");
	color = color.replace(")","");
	color = color.split(",");
	return color.map(function (x) {
    		return parseInt(x);
		});
}
function colorChanger(x,y,sign,amount){
	var currentColor  = rectangles[x][y].attr("fill");
	var colors = toRGB(currentColor);
	var k = colors[0];
	var l = colors[1];
	if(sign == '+'){
		k = colors[0]+amount;
		l = colors[1]+amount;
	}else{
		k = colors[0]-amount;
		l = colors[1]-amount;
	}

	var newColor = "rgb("+k+","+l+","+Math.floor((l+k)/2)+")";	return newColor;;
}
function currentSquare(x,y,width,height,sign){
	for (var i = x-width; i <= x+width; ++i) {
		rectangles[y-height-1][i].attr("fill",colorChanger(y-height-1,i,sign,10));
		rectangles[y+height][i].attr("fill",colorChanger(y+height,i,sign,10));
	};
	for (var i = y-height; i < y+height; ++i) {
		rectangles[i][x-width].attr("fill",colorChanger(i,x-width,sign,10));
		rectangles[i][x+width].attr("fill",colorChanger(i,x+width,sign,10));
	};
}
function rippleEffect(x,y){
	/*for(var k = 0; k < 10; ++k){
		currentSquare(x,y,k,k,'+');
		currentSquare(x,y,k-2,k-2,'-');
	}*/
	var max = 30;
	var newcounter = 0;
	var counter = 0;
	for(var i = 0; i < max; i++){
		setTimeout(function(){
				if(newcounter < (max)){
					currentCircle(x,y,newcounter,'+',10);
				}
				if(newcounter >=5){
					currentCircle(x,y,(newcounter-5),'-',10);
				}
				newcounter++;
			}, counter++*60);
	}

	newcounter = 0;
	counter = 0;
}
function makeripple(x,y){

}
function calculateDistance(x,y,cx,cy,radius,Limit){
	var distance = Math.sqrt(Math.pow(y-cy,2) + Math.pow(x-cx,2)); //Distance formula
	if(Limit > 100){return -1};
	if(distance > radius){
		return calculateDistance(x,y,cx,--cy,radius,++Limit);
	}
	return cy;
}

function currentCircle(x0,y0,radius,sign,amount){
	//MidPoint_Circle_Algarithm
	var x = radius;
	var y = 0;
	var decisionOver2 = 1-x;
	while(x >= y){
		rectangles[y0+y][x0+x].attr("fill",colorChanger(y0+y,x0+x,sign,amount));
		rectangles[y0-y][x0+x].attr("fill",colorChanger(y0-y,x0+x,sign,amount));
		rectangles[y0-y][x0-x].attr("fill",colorChanger(y0-y,x0-x,sign,amount));
		rectangles[y0+y][x0-x].attr("fill",colorChanger(y0+y,x0-x,sign,amount));

		rectangles[y0+x][x0-y].attr("fill",colorChanger(y0+x,x0-y,sign,amount));
		rectangles[y0+x][x0+y].attr("fill",colorChanger(y0+x,x0+y,sign,amount));
		rectangles[y0-x][x0+y].attr("fill",colorChanger(y0-x,x0+y,sign,amount));
		rectangles[y0-x][x0-y].attr("fill",colorChanger(y0-x,x0-y,sign,amount));
	y++;
	if(decisionOver2 <0){
		decisionOver2 += 2 * y + 1;
	}else{
		x--;
		decisionOver2 += 2 * (y - x) +1;
	}
	}
}

var squarerectangles = {width: 10, height: 10};
var x = 0;
var y = 0;
for (var i = 0; i < width; i = i + squarerectangles.width){
	var row = [];
	for (var k = 0; k < height; k = k + squarerectangles.height){
		row.push(d3.select(".canvas").append("circle")
			.attr("fill",function(){
				return "rgb("+Math.floor(colorW(i))+","+Math.floor(colorH(k))+","+Math.floor(colorB((i+k)))+")";
			})
			.attr("cx",i)
			.attr("cy",k)
			.attr("r",squarerectangles.width)
			.attr("id",x+++","+y)
			.on("click",function(d){
				var position = this.id.split(",");
				rippleEffect(parseInt(position[0]),parseInt(position[1]))
			})
			)
		}
	y++;
	rectangles.push(row);
	row = [];
	x = 0;
}<|endoftext|>


<commit_before>/*global md5 */

(function() {

  const DATA_PREFIX = "data-poll-";
  const DEFAULT_POLL_NAME = "poll";

  const WHITELISTED_ATTRIBUTES = ["type", "name", "min", "max", "step", "order", "color", "background", "status"];
  const WHITELISTED_STYLES = ["color", "background"];

  const ATTRIBUTES_REGEX = new RegExp("(" + WHITELISTED_ATTRIBUTES.join("|") + ")=[^\\s\\]]+", "g");

  Discourse.Dialect.replaceBlock({
    start: /\[poll([^\]]*)\]([\s\S]*)/igm,
    stop: /\[\/poll\]/igm,

    emitter: function(blockContents, matches) {
      var o, contents = [];

      // post-process inside block contents
      if (blockContents.length) {
        var self = this, b;

        var postProcess = function(bc) {
          if (typeof bc === "string" || bc instanceof String) {
            var processed = self.processInline(String(bc));
            if (processed.length) {
              contents.push(["p"].concat(processed));
            }
          } else {
            contents.push(bc);
          }
        };

        while ((b = blockContents.shift()) !== undefined) {
          this.processBlock(b, blockContents).forEach(postProcess);
        }
      }

      // default poll attributes
      var attributes = { "class": "poll" };
      attributes[DATA_PREFIX + "status"] = "open";
      attributes[DATA_PREFIX + "name"] = DEFAULT_POLL_NAME;

      // extract poll attributes
      (matches[1].match(ATTRIBUTES_REGEX) || []).forEach(function(m) {
        var attr = m.split("=");
        attributes[DATA_PREFIX + attr[0]] = attr[1];
      });

      // we might need these values later...
      var min = parseInt(attributes[DATA_PREFIX + "min"], 10),
          max = parseInt(attributes[DATA_PREFIX + "max"], 10),
          step = parseInt(attributes[DATA_PREFIX + "step"], 10);

      // generate the options when the type is "number"
      if (attributes[DATA_PREFIX + "type"] === "number") {
        // default values
        if (isNaN(min)) { min = 1; }
        if (isNaN(max)) { max = 10; }
        if (isNaN(step)) { step = 1; }
        // dynamically generate options
        contents.push(["bulletlist"]);
        for (o = min; o <= max; o += step) {
          contents[0].push(["listitem", String(o)]);
        }
      }

      // make sure the first child is a list with at least 1 option
      if (contents.length === 0 || contents[0].length <= 1 || (contents[0][0] !== "numberlist" && contents[0][0] !== "bulletlist")) {
        return ["div"].concat(contents);
      }

      // TODO: remove non whitelisted content

      // generate <li> styles (if any)
      var styles = [];
      WHITELISTED_STYLES.forEach(function(style) {
        if (attributes[DATA_PREFIX + style]) {
          styles.push(style + ":" + attributes[DATA_PREFIX + style]);
        }
      });

      var style = styles.join(";");

      // add option id (hash) + style
      for (o = 1; o < contents[0].length; o++) {
        // break as soon as the list is done
        if (contents[0][o][0] !== "listitem") { break; }

        var attr = {};
        // apply styles if any
        if (style.length > 0) { attr["style"] = style; }
        // compute md5 hash of the content of the option
        attr[DATA_PREFIX + "option-id"] = md5(JSON.stringify(contents[0][o].slice(1)));
        // store options attributes
        contents[0][o].splice(1, 0, attr);
      }

      // // add some information when type is "multiple"
      // if (attributes[DATA_PREFIX + "type"] === "multiple") {

      // }

      var result = ["div", attributes],
          poll = ["div"];

      // 1 - POLL INFO
      var info = ["div", { "class": "poll-info" }];

      // # of voters
      info.push(["p",
                  ["span", { "class": "info-number" }, "0"],
                  ["span", { "class": "info-text"}, I18n.t("poll.voters", { count: 0 })]
                ]);

      // multiple help text
      if (attributes[DATA_PREFIX + "type"] === "multiple") {
        var optionCount = contents[0].length - 1;

        // default values
        if (isNaN(min) || min < 1) { min = 1; }
        if (isNaN(max) || max > optionCount) { max = optionCount; }

        // add some help text
        var help;

        if (max > 0) {
          if (min === max) {
            if (min > 1) {
              help = I18n.t("poll.multiple.help.x_options", { count: min });
            }
          } else if (min > 1) {
            if (max < optionCount) {
              help = I18n.t("poll.multiple.help.between_min_and_max_options", { min: min, max: max });
            } else {
              help = I18n.t("poll.multiple.help.at_least_min_options", { count: min });
            }
          } else if (max <= optionCount) {
            help = I18n.t("poll.multiple.help.up_to_max_options", { count: max });
          }
        }

        if (help) { info.push(["p", help]); }
      }

      poll.push(info);

      // 2 - POLL CONTAINER
      var container = ["div", { "class": "poll-container" }].concat(contents);
      poll.push(container);

      // 3 - BUTTONS
      var buttons = ["div", { "class": "poll-buttons" }];

      // add "cast-votes" button
      if (attributes[DATA_PREFIX + "type"] === "multiple") {
        buttons.push(["a", { "class": "button cast-votes", "title": I18n.t("poll.cast-votes.title") }, I18n.t("poll.cast-votes.label")]);
      }

      // add "toggle-results" button
      buttons.push(["a", { "class": "button toggle-results", "title": I18n.t("poll.show-results.title") }, I18n.t("poll.show-results.label")]);

      // 4 - MIX IT ALL UP
      result.push(poll);
      result.push(buttons)

      return result;
    }
  });

  Discourse.Markdown.whiteListTag("div", "class", "poll");
  Discourse.Markdown.whiteListTag("div", "class", /^poll-(info|container|buttons)/);
  Discourse.Markdown.whiteListTag("div", "data-*");

  Discourse.Markdown.whiteListTag("span", "class", /^info-(number|text)/);

  Discourse.Markdown.whiteListTag("a", "class", /^button (cast-votes|toggle-results)/);

  Discourse.Markdown.whiteListTag("li", "data-*");
  Discourse.Markdown.whiteListTag("li", "style");

})();
<commit_msg>make jshint happy<commit_after>/*global md5 */

(function() {

  const DATA_PREFIX = "data-poll-";
  const DEFAULT_POLL_NAME = "poll";

  const WHITELISTED_ATTRIBUTES = ["type", "name", "min", "max", "step", "order", "color", "background", "status"];
  const WHITELISTED_STYLES = ["color", "background"];

  const ATTRIBUTES_REGEX = new RegExp("(" + WHITELISTED_ATTRIBUTES.join("|") + ")=[^\\s\\]]+", "g");

  Discourse.Dialect.replaceBlock({
    start: /\[poll([^\]]*)\]([\s\S]*)/igm,
    stop: /\[\/poll\]/igm,

    emitter: function(blockContents, matches) {
      var o, contents = [];

      // post-process inside block contents
      if (blockContents.length) {
        var self = this, b;

        var postProcess = function(bc) {
          if (typeof bc === "string" || bc instanceof String) {
            var processed = self.processInline(String(bc));
            if (processed.length) {
              contents.push(["p"].concat(processed));
            }
          } else {
            contents.push(bc);
          }
        };

        while ((b = blockContents.shift()) !== undefined) {
          this.processBlock(b, blockContents).forEach(postProcess);
        }
      }

      // default poll attributes
      var attributes = { "class": "poll" };
      attributes[DATA_PREFIX + "status"] = "open";
      attributes[DATA_PREFIX + "name"] = DEFAULT_POLL_NAME;

      // extract poll attributes
      (matches[1].match(ATTRIBUTES_REGEX) || []).forEach(function(m) {
        var attr = m.split("=");
        attributes[DATA_PREFIX + attr[0]] = attr[1];
      });

      // we might need these values later...
      var min = parseInt(attributes[DATA_PREFIX + "min"], 10),
          max = parseInt(attributes[DATA_PREFIX + "max"], 10),
          step = parseInt(attributes[DATA_PREFIX + "step"], 10);

      // generate the options when the type is "number"
      if (attributes[DATA_PREFIX + "type"] === "number") {
        // default values
        if (isNaN(min)) { min = 1; }
        if (isNaN(max)) { max = 10; }
        if (isNaN(step)) { step = 1; }
        // dynamically generate options
        contents.push(["bulletlist"]);
        for (o = min; o <= max; o += step) {
          contents[0].push(["listitem", String(o)]);
        }
      }

      // make sure the first child is a list with at least 1 option
      if (contents.length === 0 || contents[0].length <= 1 || (contents[0][0] !== "numberlist" && contents[0][0] !== "bulletlist")) {
        return ["div"].concat(contents);
      }

      // TODO: remove non whitelisted content

      // generate <li> styles (if any)
      var styles = [];
      WHITELISTED_STYLES.forEach(function(style) {
        if (attributes[DATA_PREFIX + style]) {
          styles.push(style + ":" + attributes[DATA_PREFIX + style]);
        }
      });

      var style = styles.join(";");

      // add option id (hash) + style
      for (o = 1; o < contents[0].length; o++) {
        // break as soon as the list is done
        if (contents[0][o][0] !== "listitem") { break; }

        var attr = {};
        // apply styles if any
        if (style.length > 0) { attr["style"] = style; }
        // compute md5 hash of the content of the option
        attr[DATA_PREFIX + "option-id"] = md5(JSON.stringify(contents[0][o].slice(1)));
        // store options attributes
        contents[0][o].splice(1, 0, attr);
      }

      // // add some information when type is "multiple"
      // if (attributes[DATA_PREFIX + "type"] === "multiple") {

      // }

      var result = ["div", attributes],
          poll = ["div"];

      // 1 - POLL INFO
      var info = ["div", { "class": "poll-info" }];

      // # of voters
      info.push(["p",
                  ["span", { "class": "info-number" }, "0"],
                  ["span", { "class": "info-text"}, I18n.t("poll.voters", { count: 0 })]
                ]);

      // multiple help text
      if (attributes[DATA_PREFIX + "type"] === "multiple") {
        var optionCount = contents[0].length - 1;

        // default values
        if (isNaN(min) || min < 1) { min = 1; }
        if (isNaN(max) || max > optionCount) { max = optionCount; }

        // add some help text
        var help;

        if (max > 0) {
          if (min === max) {
            if (min > 1) {
              help = I18n.t("poll.multiple.help.x_options", { count: min });
            }
          } else if (min > 1) {
            if (max < optionCount) {
              help = I18n.t("poll.multiple.help.between_min_and_max_options", { min: min, max: max });
            } else {
              help = I18n.t("poll.multiple.help.at_least_min_options", { count: min });
            }
          } else if (max <= optionCount) {
            help = I18n.t("poll.multiple.help.up_to_max_options", { count: max });
          }
        }

        if (help) { info.push(["p", help]); }
      }

      poll.push(info);

      // 2 - POLL CONTAINER
      var container = ["div", { "class": "poll-container" }].concat(contents);
      poll.push(container);

      // 3 - BUTTONS
      var buttons = ["div", { "class": "poll-buttons" }];

      // add "cast-votes" button
      if (attributes[DATA_PREFIX + "type"] === "multiple") {
        buttons.push(["a", { "class": "button cast-votes", "title": I18n.t("poll.cast-votes.title") }, I18n.t("poll.cast-votes.label")]);
      }

      // add "toggle-results" button
      buttons.push(["a", { "class": "button toggle-results", "title": I18n.t("poll.show-results.title") }, I18n.t("poll.show-results.label")]);

      // 4 - MIX IT ALL UP
      result.push(poll);
      result.push(buttons);

      return result;
    }
  });

  Discourse.Markdown.whiteListTag("div", "class", "poll");
  Discourse.Markdown.whiteListTag("div", "class", /^poll-(info|container|buttons)/);
  Discourse.Markdown.whiteListTag("div", "data-*");

  Discourse.Markdown.whiteListTag("span", "class", /^info-(number|text)/);

  Discourse.Markdown.whiteListTag("a", "class", /^button (cast-votes|toggle-results)/);

  Discourse.Markdown.whiteListTag("li", "data-*");
  Discourse.Markdown.whiteListTag("li", "style");

})();
<|endoftext|>