<commit_before>import Ember from 'ember'; // eslint-disable-line
import { L } from 'ember-leaflet'; // eslint-disable-line
import bbox from 'npm:@turf/bbox'; // eslint-disable-line

import carto from '../utils/carto';

function buildBorocd(boro, cd) {
  let borocode;
  switch (boro) {
    case 'manhattan':
      borocode = 100;
      break;
    case 'bronx':
      borocode = 200;
      break;
    case 'brooklyn':
      borocode = 300;
      break;
    case 'queens':
      borocode = 400;
      break;
    case 'staten-island':
      borocode = 500;
      break;
    default:
  }
  return borocode + parseInt(cd, 10);
}

export default Ember.Route.extend({
  mapState: Ember.inject.service(),
  model(params) {
    const { boro, cd } = params;
    const borocd = buildBorocd(boro, cd);
    const sql = `SELECT * FROM community_district_profiles WHERE borocd=${borocd}`;

    const selectedDistrict = this.modelFor('application')
      .features.find(district => district.properties.borocd === borocd);

    return carto.SQL(sql, 'json')
      .then((json) => {
        Ember.set(selectedDistrict, 'properties.dataprofile', json[0]);
        return selectedDistrict;
      });
  },
  afterModel(feature) {
    const mapState = this.get('mapState');
    mapState.set('bounds', bbox(feature.geometry));
    mapState.set('feature', feature);

    carto.getTileTemplate()
      .then((landUseTemplate) => {
        mapState.set('landUseTemplate', landUseTemplate);
      });
  },
});
<commit_msg>Transition to 404 in error state<commit_after>import Ember from 'ember'; // eslint-disable-line
import { L } from 'ember-leaflet'; // eslint-disable-line
import bbox from 'npm:@turf/bbox'; // eslint-disable-line

import carto from '../utils/carto';

function buildBorocd(boro, cd) {
  let borocode;
  switch (boro) {
    case 'manhattan':
      borocode = 100;
      break;
    case 'bronx':
      borocode = 200;
      break;
    case 'brooklyn':
      borocode = 300;
      break;
    case 'queens':
      borocode = 400;
      break;
    case 'staten-island':
      borocode = 500;
      break;
    default:
  }
  return borocode + parseInt(cd, 10);
}

export default Ember.Route.extend({
  mapState: Ember.inject.service(),
  model(params) {
    const { boro, cd } = params;
    const borocd = buildBorocd(boro, cd);
    const sql = `SELECT * FROM community_district_profiles WHERE borocd=${borocd}`;

    const selectedDistrict = this.modelFor('application')
      .features.find(district => district.properties.borocd === borocd);

    return carto.SQL(sql, 'json')
      .then((json) => {
        Ember.set(selectedDistrict, 'properties.dataprofile', json[0]);
        return selectedDistrict;
      });
  },
  afterModel(feature) {
    const mapState = this.get('mapState');
    mapState.set('bounds', bbox(feature.geometry));
    mapState.set('feature', feature);

    carto.getTileTemplate()
      .then((landUseTemplate) => {
        mapState.set('landUseTemplate', landUseTemplate);
      });
  },
  actions: {
    error() {
      this.transitionTo('404');
    }
  }
});
<|endoftext|>


<commit_before>var win = Ti.UI.currentWindow;

var ServerHandler = require('/includes/ServerHandler');
Ti.include('/includes/lib/json.i18n.js');

var isMcStyle = Ti.App.Properties.getBool('mcStyledUI', true);

var tableView = require('/includes/PullToRefresh')({
	style: Ti.UI.iPhone.TableViewStyle.PLAIN,
	scrollIndicatorStyle: Ti.UI.iPhone.ScrollIndicatorStyle.WHITE,
	editable: true
});

if(isMcStyle) {
	tableView.setSeparatorColor('#4b4b4b');
	tableView.setBackgroundImage('/img/full-bg.png');
}

win.add(tableView);

function updateList() {
	//opening the database containing the servers that we will display
	var db = Ti.Database.open('servers');
	var servers = db.execute('SELECT * FROM servers');
	//erase the existing tableview entries
	tableView.setData([]);
	//this index corresponds to the tableviewrow id
	var i = 0;

	//loop through the servers
	while(servers.isValidRow()) {
		//getting all the data corresponding to the row, it will be useful later
		var data = {
			name: servers.fieldByName('name'),
			host: servers.fieldByName('host'),
			port: servers.fieldByName('port'),
			sqlid: servers.fieldByName('id'),
			id: i
		};

		//create temporary row, that will say "polling server..."
		ServerHandler.getRow(data, i, function(e) {
			tableView.appendRow(e.row);
		}, ServerHandler.state.POLLING);

		//get real info
		ServerHandler.getServerInfo(data, i, function(e) {
			e.row.data = e.data;
			//update the existing temporary row and update it in consequence
			tableView.updateRow(e.index, e.row);
		});

		//next server, next row
		servers.next();
		i++;
	}

	//we're done with the database
	servers.close();
}

Ti.App.addEventListener('reload', updateList);

tableView.addEventListener('delete', function(e) {
	var db = Ti.Database.open('servers');
	db.execute('DELETE FROM servers WHERE id=?', e.rowData.data.sqlid);
	db.close();
});

var b_add = Ti.UI.createButton({
	image: '/img/add.png',
	backgroundImage: '/img/menubar-button.png'
});

b_add.addEventListener('click', function(e) {
	var win_add = Ti.UI.createWindow({
		url: 'add.js',
		title: I('addServer.title'),
		barImage: '/img/menubar.png',
		backgroundImage: '/img/full-bg.png'
	});

	win_add.addEventListener('close', function(e) {
		updateList();
	});

	win_add.open({
		modal: true
	});
});

var b_edit = Ti.UI.createButton({
	image: '/img/edit.png',
	backgroundImage: '/img/menubar-button.png'
});

b_edit.addEventListener('click', function(e) {
	if(!tableView.getEditing()) {
		tableView.setEditing(true);
	} else {
		tableView.setEditing(false);
	}
});

win.setRightNavButton(b_add);
win.setLeftNavButton(b_edit);

var view_ad = Ti.UI.iOS.createAdView({
	adSize: Ti.UI.iOS.AD_SIZE_PORTRAIT,
	bottom: 0
});

win.add(view_ad);

var b_info_win = Ti.UI.createButton({
	style: (isMcStyle) ? Ti.UI.iPhone.SystemButton.INFO_LIGHT : Ti.UI.iPhone.SystemButton.INFO_DARK,
	bottom: 10,
	right: 10
});

b_info_win.addEventListener('click', function(e) {
	var win_info = Ti.UI.createWindow({
		url: 'credits.js',
		title: I('credits.title'),
		barImage: '/img/menubar.png',
		backgroundImage: '/img/full-bg.png'
	});

	win_info.open({
		modal: true
	});
});

win.add(b_info_win);
updateList();
<commit_msg>Added a button to indicate the state of editing<commit_after>var win = Ti.UI.currentWindow;

var ServerHandler = require('/includes/ServerHandler');
Ti.include('/includes/lib/json.i18n.js');

var isMcStyle = Ti.App.Properties.getBool('mcStyledUI', true);

var tableView = require('/includes/PullToRefresh')({
	style: Ti.UI.iPhone.TableViewStyle.PLAIN,
	scrollIndicatorStyle: Ti.UI.iPhone.ScrollIndicatorStyle.WHITE,
	editable: true
});

if(isMcStyle) {
	tableView.setSeparatorColor('#4b4b4b');
	tableView.setBackgroundImage('/img/full-bg.png');
}

win.add(tableView);

function updateList() {
	//opening the database containing the servers that we will display
	var db = Ti.Database.open('servers');
	var servers = db.execute('SELECT * FROM servers');
	//erase the existing tableview entries
	tableView.setData([]);
	//this index corresponds to the tableviewrow id
	var i = 0;

	//loop through the servers
	while(servers.isValidRow()) {
		//getting all the data corresponding to the row, it will be useful later
		var data = {
			name: servers.fieldByName('name'),
			host: servers.fieldByName('host'),
			port: servers.fieldByName('port'),
			sqlid: servers.fieldByName('id'),
			id: i
		};

		//create temporary row, that will say "polling server..."
		ServerHandler.getRow(data, i, function(e) {
			tableView.appendRow(e.row);
		}, ServerHandler.state.POLLING);

		//get real info
		ServerHandler.getServerInfo(data, i, function(e) {
			e.row.data = e.data;
			//update the existing temporary row and update it in consequence
			tableView.updateRow(e.index, e.row);
		});

		//next server, next row
		servers.next();
		i++;
	}

	//we're done with the database
	servers.close();
}

Ti.App.addEventListener('reload', updateList);

tableView.addEventListener('delete', function(e) {
	var db = Ti.Database.open('servers');
	db.execute('DELETE FROM servers WHERE id=?', e.rowData.data.sqlid);
	db.close();
});

var b_add = Ti.UI.createButton({
	image: '/img/add.png',
	backgroundImage: '/img/menubar-button.png'
});

b_add.addEventListener('click', function(e) {
	var win_add = Ti.UI.createWindow({
		url: 'add.js',
		title: I('addServer.title'),
		barImage: '/img/menubar.png',
		backgroundImage: '/img/full-bg.png'
	});

	win_add.addEventListener('close', function(e) {
		updateList();
	});

	win_add.open({
		modal: true
	});
});

var b_edit = Ti.UI.createButton({
	image: '/img/edit.png',
	backgroundImage: '/img/menubar-button.png'
});

var b_done = Ti.UI.createButton({
	image: '/img/check.png',
	backgroundImage: '/img/menubar-button.png'
});

b_edit.addEventListener('click', function(e) {
	tableView.setEditing(true);
	win.setLeftNavButton(b_done, {
		animated: true
	});
});

b_done.addEventListener('click', function(e) {
	tableView.setEditing(false);
	win.setLeftNavButton(b_edit, {
		animated: true
	});
});

win.setRightNavButton(b_add);
win.setLeftNavButton(b_edit);

var view_ad = Ti.UI.iOS.createAdView({
	adSize: Ti.UI.iOS.AD_SIZE_PORTRAIT,
	bottom: 0
});

win.add(view_ad);

var b_info_win = Ti.UI.createButton({
	style: (isMcStyle) ? Ti.UI.iPhone.SystemButton.INFO_LIGHT : Ti.UI.iPhone.SystemButton.INFO_DARK,
	bottom: 12,
	right: 10
});

b_info_win.addEventListener('click', function(e) {
	var win_info = Ti.UI.createWindow({
		url: 'credits.js',
		title: I('credits.title'),
		barImage: '/img/menubar.png',
		backgroundImage: '/img/full-bg.png'
	});

	win_info.open({
		modal: true
	});
});

win.add(b_info_win);
updateList();
<|endoftext|>


<commit_before>Date.weekdays = $w('Sunday Monday Tuesday Wednesday Thursday Friday Saturday');
Date.months   = $w('January February March April May June July August September October November December');

var Timeframes = [];

var Timeframe = Class.create({
 /**
  * Syntax:
  *
  * new Timeframe('el_id', {
  *   calendars: 2,
  *   weekoffset: 0
  * });
  */
  Version: '0.1 Calamari',

  initialize: function(element, options) {
    Timeframes.push(this);

    this.container = $(element);
    this.disableSelection(this.container);

    this.options = $H({
      calendars:   2,
      format:      '%b %d, %Y',
      weekoffset:  0
    }).merge(options || {});

    this.calendars = this.options.get('calendars');

    // Look for custom buttons:
    this.buttons = $H({
      previous: $(this.options.get('previousbutton')),
      today:    $(this.options.get('todaybutton')),
      next:     $(this.options.get('nextbutton')),
      reset:    $(this.options.get('resetbutton'))
    });

    // Look for custom fields:
    this.fields = $H({
      start:    $(this.options.get('startfield')),
      end:      $(this.options.get('endfield'))
    });

    this.format       = this.options.get('format');
    this.weekoffset   = this.options.get('weekoffset');
    this.weekdayNames = Date.weekdays; // this.weekdayNames = Date.internationalizations.get(this.options.get('locale'));
    this.monthNames   = Date.months;   // this.monthNames   = Date.internationalizations.get(this.options.get('locale'));
    this.date         = new Date();
    this.defaultDate  = new Date(this.date)

    this.buildButtons();
    this.calendars.times(function(calendar) { this.buildCalendar(calendar) }.bind(this));
    this.buildFields();
    this.populate();
    this.activate();
  },

  // Make sure dragging doesn't select any calendar text
  disableSelection: function(element) {
    element.onselectstart       = function() { return false; };
    element.unselectable        = 'on';
    element.style.MozUserSelect = 'none';
    element.style.cursor        = 'default';
  },

  buildButtons: function() {
    var list = new Element('ul', { id: 'timeframe_menu' });
    this.buttons.each(function(pair) {
      if(pair.value)
        pair.value.addClassName('timeframe_button').addClassName(pair.key);
      else {
        var item = new Element('li');
        this.buttons.set(pair.key, new Element('a', { className: 'timeframe_button ' + pair.key, href: '#', onclick: 'return false;' }).update(pair.key));
        Element.insert(item, { bottom: this.buttons.get(pair.key) });
        Element.insert(list, { bottom: item });
      }
    }.bind(this))
    if(list.childNodes.length > 0) Element.insert(this.container, { bottom: list });

    this.clearButton = new Element('span', { className: 'clear' }).update(new Element('span').update('X'));
  },

  buildCalendar: function(calendarNumber) {
    var calendar = new Element('table', { id: 'calendar_' + calendarNumber, border: 0, cellspacing: 0, cellpadding: 5 });
    Element.insert(calendar, { top: new Element('caption') });
    Element.insert(calendar, { bottom: this.buildHead() });
    Element.insert(calendar, { bottom: this.buildBody() });
    Element.insert(this.container, { bottom: calendar });
  },

  buildHead: function() {
    var head = new Element('thead');
    var row  = new Element('tr');
    this.weekdayNames.length.times(function(column) {
      var weekday = this.weekdayNames[(column + this.weekoffset) % 7];
      var cell = new Element('th', { scope: 'col', abbr: weekday }).update(weekday.substring(0,1));
      Element.insert(row, { bottom: cell });
    }.bind(this));
    Element.insert(head, { bottom: row });
    return head;
  },

  buildBody: function() {
    var body = new Element('tbody');
    (6).times(function(rowNumber) {
      var row = new Element('tr');
      this.weekdayNames.length.times(function(column) {
        var cell = new Element('td');
        Element.insert(row, { bottom: cell });
      });
      Element.insert(body, { bottom: row });
    }.bind(this));
    return body;
  },

  buildFields: function() {
    var fieldset = new Element('div', { id: 'timeframe_fields' });
    this.fields.each(function(pair) {
      if(pair.value)
        pair.value.addClassName('timeframe_field').addClassName(pair.key);
      else {
        var container = new Element('div', { id: pair.key + 'field_container' });
        this.fields.set(pair.key, new Element('input', { id: pair.key + 'field', name: pair.key + 'field', type: 'text', value: '' }));
        Element.insert(container, { bottom: new Element('label', { 'for': pair.key + 'field' }).update(pair.key) });
        Element.insert(container, { bottom: this.fields.get(pair.key) });
        Element.insert(fieldset, { bottom: container });
      }
    }.bind(this));
    if(fieldset.childNodes.length > 0) Element.insert(this.container, { bottom: fieldset });
    this.startfield = this.fields.get('start');
    this.endfield = this.fields.get('end');
  },

  populate: function() {
    var month = this.date.neutral();
    month.setDate(1);
    this.calendars.times(function(n) {
      var calendar = $('calendar_' + n);
      var caption = calendar.select('caption').first();
      caption.update(this.monthNames[month.getMonth()] + ' ' + month.getFullYear());

      var iterator = new Date(month);
      var offset = (iterator.getDay() - this.weekoffset) % 7;
      var inactive = offset > 0 ? 'pre' : false;
      iterator.setDate(iterator.getDate() - offset);
      if(iterator.getDate() > 1 && !inactive) {
        iterator.setDate(iterator.getDate() - 7);
        if(iterator.getDate() > 1) inactive = 'pre';
      }

      calendar.select('td').each(function(day) {
        day.date = new Date(iterator); // Is this expensive (we unload these later)? We could store the epoch time instead.
        day.update(day.date.getDate()).writeAttribute('class', inactive || 'active');
        if(iterator.toString() === new Date().neutral().toString()) day.addClassName('today');
        iterator.setDate(iterator.getDate() + 1);
        if(iterator.getDate() == 1) inactive = inactive ? false : 'post';
      });

      month.setMonth(month.getMonth() + 1);
    }.bind(this));
    this.refreshRange();
  },

  activate: function() {
    document.observe('click', this.handleClick.bindAsEventListener(this));
    document.observe('mousedown', this.handleMousedown.bindAsEventListener(this));
    document.observe('mouseover', this.handleMouseover.bindAsEventListener(this));
    document.observe('mouseup', this.setPoint.bindAsEventListener(this));
    document.observe('unload', this.deactivate.bindAsEventListener(this));
    this.aimFieldObservers();
  },

  aimFieldObservers: function(field, assignment) {
    [this.startfield, this.endfield].invoke('observe', 'focus', this.declareFocus.bindAsEventListener(this));
    [this.startfield, this.endfield].invoke('observe', 'blur', this.declareBlur.bindAsEventListener(this));
    new Form.Element.Observer(this.startfield, 0.2, function(element, value) {
      if(element.hasFocus) {
        var date = new Date(Date.parse(value)).neutral();
        this.startdate = date == 'Invalid Date' ? null : date;
        this.refreshRange();
      }
    }.bind(this));
    new Form.Element.Observer(this.endfield, 0.2, function(element, value) {
      if(element.hasFocus) {
        var date = new Date(Date.parse(value)).neutral();
        this.enddate = date == 'Invalid Date' ? null : date;
        this.refreshRange();
      }
    }.bind(this));
  },

  declareFocus: function(event) {
    event.element().hasFocus = true;
    if(this.startdate && event.element() == this.startfield) {
      this.date = new Date(this.startdate)
      this.populate();
    }
    else if(this.enddate && event.element() == this.endfield) {
      this.date = new Date(this.enddate)
      this.populate();
    }
  },

  declareBlur: function(event) {
    event.element().hasFocus = false;
    this.refreshFields();
  },

  deactivate: function() {
    this.container.select('td').each(function(day) { day.date = null; });
  },

  handleClick: function(event) {
    if(!event.element().ancestors) return;
    var el;
    if(el = event.findElement('a.timeframe_button'))
      this.handleButtonClick(event, el);
  },

  handleMousedown: function(event) {
    if(!event.element().ancestors) return;
    var el, em;
    if(el = event.findElement('span.clear')) {
      el.addClassName('active');
      if(em = event.findElement('td'))
        this.handleDateClick(em, true);
    }
    else if(el = event.findElement('td'))
      this.handleDateClick(el);
    else return;
  },

  handleButtonClick: function(event, element) {
    var el;
    var movement = this.calendars > 1 ? this.calendars - 1 : 1;
    if(element.hasClassName('next'))
      this.date.setMonth(this.date.getMonth() + movement);
    else if(element.hasClassName('previous'))
      this.date.setMonth(this.date.getMonth() - movement);
    else if(element.hasClassName('today'))
      this.date = new Date();
    else if(element.hasClassName('reset')) {
      this.resetFields();
    }
    this.populate();
  },

  resetFields: function() {
    this.startfield.value = this.startfield.defaultValue || '';
    this.endfield.value = this.endfield.defaultValue || '';
    this.date = new Date(this.defaultDate);
    var startdate = new Date(Date.parse(this.startfield.value)).neutral();
    this.startdate = startdate == 'Invalid Date' ? null : startdate;
    var enddate = new Date(Date.parse(this.endfield)).neutral();
    this.enddate = enddate == 'Invalid Date' ? null : enddate;
  },

  handleDateClick: function(element, couldClear) {
    this.mousedown = this.dragging = true;
    if(this.stuck)
      this.stuck = false;
    else if(couldClear) {
      if(!element.hasClassName('startrange')) return;
    }
    else {
      this.stuck = true;
      setTimeout(function() { if(this.mousedown) this.stuck = false; }.bind(this), 200);
    }
    this.getPoint(element.date);
  },

  getPoint: function(date) {
    if(this.startdate && this.startdate.toString() == date && this.enddate)
      this.startdrag = this.enddate;
    else {
      this.clearButton.hide();
      if(this.enddate && this.enddate.toString() == date)
        this.startdrag = this.startdate;
      else
        this.startdrag = this.startdate = this.enddate = date;
    }
    this.refreshRange();
  },

  handleMouseover: function(event) {
    var el;
    if(!this.dragging)
      this.toggleClearButton(event);
    else if(event.findElement('span.clear.active'));
    else if(el = event.findElement('td'))
      this.extendRange(el.date);
  },

  toggleClearButton: function(event) {
    var el;
    if(event.element().ancestors && event.findElement('td.selected')) {
      if(el = this.container.select('#calendar_0 .pre.selected').first());
      else if(el = this.container.select('.active.selected').first());
      if(el) Element.insert(el, { top: this.clearButton });
      this.clearButton.removeClassName('active').show();
    }
    else {
      this.clearButton.hide();
    }
  },

  extendRange: function(date) {
    this.clearButton.hide();
    if(date > this.startdrag) {
      this.startdate = this.startdrag;
      this.enddate = date;
    }
    else if(date < this.startdrag) {
      this.startdate = date;
      this.enddate = this.startdrag;
    }
    else {
      this.startdate = this.enddate = date;
    }
    this.refreshRange();
  },

  setPoint: function(event) {
    if(!this.dragging) return;
    if(!this.stuck) {
      var el;
      this.dragging = false;
      if(el = event.findElement('span.clear.active')) {
        el.hide().removeClassName('active');
        this.startdate = this.enddate = null;
        this.refreshRange();
        this.refreshFields();
      }
    }
    this.mousedown = false;
    this.refreshRange();
  },

  refreshRange: function() {
    this.container.select('td').each(function(day) {
      if(this.startdate <= day.date && day.date <= this.enddate) {
        day.addClassName('selected');
        this.stuck || this.mousedown ? day.addClassName('stuck') : day.removeClassName('stuck');
        this.startdate.toString() == day.date ? day.addClassName('startrange') : day.removeClassName('startrange');
        this.enddate.toString() == day.date ? day.addClassName('endrange') : day.removeClassName('endrange');
      }
      else day.removeClassName('selected').removeClassName('startrange').removeClassName('endrange').removeClassName('stuck');
    }.bind(this));
    if(this.dragging) this.refreshFields();
  },

  refreshFields: function() {
    this.startfield.value = this.startdate ? this.startdate.strftime(this.format) : '';
    this.endfield.value = this.enddate ? this.enddate.strftime(this.format) : '';
  }
});

Object.extend(Date.prototype, {
  // modified from http://alternateidea.com/blog/articles/2008/2/8/a-strftime-for-prototype
  strftime: function(format) {
    var day = this.getDay(), month = this.getMonth();
    var hours = this.getHours(), minutes = this.getMinutes();
    function pad(num) { return num.toPaddedString(2); };

    return format.gsub(/\%([aAbBcdHImMpSwyY])/, function(part) {
      switch(part[1]) {
        case 'a': return Date.weekdays.invoke('substring', 0, 3)[day]; break;
        case 'A': return Date.weekdays[day]; break;
        case 'b': return Date.months.invoke('substring', 0, 3)[month]; break;
        case 'B': return Date.months[month]; break;
        case 'c': return this.toString(); break;
        case 'd': return pad(this.getDate()); break;
        case 'H': return pad(hours); break;
        case 'I': return (hours % 12 == 0) ? 12 : pad(hours % 12); break;
        case 'm': return pad(month + 1); break;
        case 'M': return pad(minutes); break;
        case 'p': return hours >= 12 ? 'PM' : 'AM'; break;
        case 'S': return pad(this.getSeconds()); break;
        case 'w': return day; break;
        case 'y': return pad(this.getFullYear() % 100); break;
        case 'Y': return this.getFullYear().toString(); break;
      }
    }.bind(this));
  },

  neutral: function() {
    var neutered = new Date(this);
    neutered.setHours(12);
    neutered.setMinutes(0);
    neutered.setSeconds(0);
    neutered.setMilliseconds(0);
    return neutered;
  }
});<commit_msg>IE7 bugfix: Check for 'NaN' in addition to 'Invalid Date'<commit_after>Date.weekdays = $w('Sunday Monday Tuesday Wednesday Thursday Friday Saturday');
Date.months   = $w('January February March April May June July August September October November December');

var Timeframes = [];

var Timeframe = Class.create({
 /**
  * Syntax:
  *
  * new Timeframe('el_id', {
  *   calendars: 2,
  *   weekoffset: 0
  * });
  */
  Version: '0.1 Calamari',

  initialize: function(element, options) {
    Timeframes.push(this);

    this.container = $(element);
    this.disableSelection(this.container);

    this.options = $H({
      calendars:   2,
      format:      '%b %d, %Y',
      weekoffset:  0
    }).merge(options || {});

    this.calendars = this.options.get('calendars');

    // Look for custom buttons:
    this.buttons = $H({
      previous: $(this.options.get('previousbutton')),
      today:    $(this.options.get('todaybutton')),
      next:     $(this.options.get('nextbutton')),
      reset:    $(this.options.get('resetbutton'))
    });

    // Look for custom fields:
    this.fields = $H({
      start:    $(this.options.get('startfield')),
      end:      $(this.options.get('endfield'))
    });

    this.format       = this.options.get('format');
    this.weekoffset   = this.options.get('weekoffset');
    this.weekdayNames = Date.weekdays; // this.weekdayNames = Date.internationalizations.get(this.options.get('locale'));
    this.monthNames   = Date.months;   // this.monthNames   = Date.internationalizations.get(this.options.get('locale'));
    this.date         = new Date();
    this.defaultDate  = new Date(this.date)

    this.buildButtons();
    this.calendars.times(function(calendar) { this.buildCalendar(calendar) }.bind(this));
    this.buildFields();
    this.populate();
    this.activate();
  },

  // Make sure dragging doesn't select any calendar text
  disableSelection: function(element) {
    element.onselectstart       = function() { return false; };
    element.unselectable        = 'on';
    element.style.MozUserSelect = 'none';
    element.style.cursor        = 'default';
  },

  buildButtons: function() {
    var list = new Element('ul', { id: 'timeframe_menu' });
    this.buttons.each(function(pair) {
      if(pair.value)
        pair.value.addClassName('timeframe_button').addClassName(pair.key);
      else {
        var item = new Element('li');
        this.buttons.set(pair.key, new Element('a', { className: 'timeframe_button ' + pair.key, href: '#', onclick: 'return false;' }).update(pair.key));
        Element.insert(item, { bottom: this.buttons.get(pair.key) });
        Element.insert(list, { bottom: item });
      }
    }.bind(this))
    if(list.childNodes.length > 0) Element.insert(this.container, { bottom: list });

    this.clearButton = new Element('span', { className: 'clear' }).update(new Element('span').update('X'));
  },

  buildCalendar: function(calendarNumber) {
    var calendar = new Element('table', { id: 'calendar_' + calendarNumber, border: 0, cellspacing: 0, cellpadding: 5 });
    Element.insert(calendar, { top: new Element('caption') });
    Element.insert(calendar, { bottom: this.buildHead() });
    Element.insert(calendar, { bottom: this.buildBody() });
    Element.insert(this.container, { bottom: calendar });
  },

  buildHead: function() {
    var head = new Element('thead');
    var row  = new Element('tr');
    this.weekdayNames.length.times(function(column) {
      var weekday = this.weekdayNames[(column + this.weekoffset) % 7];
      var cell = new Element('th', { scope: 'col', abbr: weekday }).update(weekday.substring(0,1));
      Element.insert(row, { bottom: cell });
    }.bind(this));
    Element.insert(head, { bottom: row });
    return head;
  },

  buildBody: function() {
    var body = new Element('tbody');
    (6).times(function(rowNumber) {
      var row = new Element('tr');
      this.weekdayNames.length.times(function(column) {
        var cell = new Element('td');
        Element.insert(row, { bottom: cell });
      });
      Element.insert(body, { bottom: row });
    }.bind(this));
    return body;
  },

  buildFields: function() {
    var fieldset = new Element('div', { id: 'timeframe_fields' });
    this.fields.each(function(pair) {
      if(pair.value)
        pair.value.addClassName('timeframe_field').addClassName(pair.key);
      else {
        var container = new Element('div', { id: pair.key + 'field_container' });
        this.fields.set(pair.key, new Element('input', { id: pair.key + 'field', name: pair.key + 'field', type: 'text', value: '' }));
        Element.insert(container, { bottom: new Element('label', { 'for': pair.key + 'field' }).update(pair.key) });
        Element.insert(container, { bottom: this.fields.get(pair.key) });
        Element.insert(fieldset, { bottom: container });
      }
    }.bind(this));
    if(fieldset.childNodes.length > 0) Element.insert(this.container, { bottom: fieldset });
    this.startfield = this.fields.get('start');
    this.endfield = this.fields.get('end');
  },

  populate: function() {
    var month = this.date.neutral();
    month.setDate(1);
    this.calendars.times(function(n) {
      var calendar = $('calendar_' + n);
      var caption = calendar.select('caption').first();
      caption.update(this.monthNames[month.getMonth()] + ' ' + month.getFullYear());

      var iterator = new Date(month);
      var offset = (iterator.getDay() - this.weekoffset) % 7;
      var inactive = offset > 0 ? 'pre' : false;
      iterator.setDate(iterator.getDate() - offset);
      if(iterator.getDate() > 1 && !inactive) {
        iterator.setDate(iterator.getDate() - 7);
        if(iterator.getDate() > 1) inactive = 'pre';
      }

      calendar.select('td').each(function(day) {
        day.date = new Date(iterator); // Is this expensive (we unload these later)? We could store the epoch time instead.
        day.update(day.date.getDate()).writeAttribute('class', inactive || 'active');
        if(iterator.toString() === new Date().neutral().toString()) day.addClassName('today');
        iterator.setDate(iterator.getDate() + 1);
        if(iterator.getDate() == 1) inactive = inactive ? false : 'post';
      });

      month.setMonth(month.getMonth() + 1);
    }.bind(this));
    this.refreshRange();
  },

  activate: function() {
    document.observe('click', this.handleClick.bindAsEventListener(this));
    document.observe('mousedown', this.handleMousedown.bindAsEventListener(this));
    document.observe('mouseover', this.handleMouseover.bindAsEventListener(this));
    document.observe('mouseup', this.setPoint.bindAsEventListener(this));
    document.observe('unload', this.deactivate.bindAsEventListener(this));
    this.aimFieldObservers();
  },

  aimFieldObservers: function(field, assignment) {
    [this.startfield, this.endfield].invoke('observe', 'focus', this.declareFocus.bindAsEventListener(this));
    [this.startfield, this.endfield].invoke('observe', 'blur', this.declareBlur.bindAsEventListener(this));
    new Form.Element.Observer(this.startfield, 0.2, function(element, value) {
      if(element.hasFocus) {
        var date = new Date(Date.parse(value)).neutral();
        this.startdate = date == 'Invalid Date' ? null : date;
        this.refreshRange();
      }
    }.bind(this));
    new Form.Element.Observer(this.endfield, 0.2, function(element, value) {
      if(element.hasFocus) {
        var date = new Date(Date.parse(value)).neutral();
        this.enddate = date == 'Invalid Date' ? null : date;
        this.refreshRange();
      }
    }.bind(this));
  },

  declareFocus: function(event) {
    event.element().hasFocus = true;
    if(this.startdate && event.element() == this.startfield) {
      this.date = new Date(this.startdate)
      this.populate();
    }
    else if(this.enddate && event.element() == this.endfield) {
      this.date = new Date(this.enddate)
      this.populate();
    }
  },

  declareBlur: function(event) {
    event.element().hasFocus = false;
    this.refreshFields();
  },

  deactivate: function() {
    this.container.select('td').each(function(day) { day.date = null; });
  },

  handleClick: function(event) {
    if(!event.element().ancestors) return;
    var el;
    if(el = event.findElement('a.timeframe_button'))
      this.handleButtonClick(event, el);
  },

  handleMousedown: function(event) {
    if(!event.element().ancestors) return;
    var el, em;
    if(el = event.findElement('span.clear')) {
      el.addClassName('active');
      if(em = event.findElement('td'))
        this.handleDateClick(em, true);
    }
    else if(el = event.findElement('td'))
      this.handleDateClick(el);
    else return;
  },

  handleButtonClick: function(event, element) {
    var el;
    var movement = this.calendars > 1 ? this.calendars - 1 : 1;
    if(element.hasClassName('next'))
      this.date.setMonth(this.date.getMonth() + movement);
    else if(element.hasClassName('previous'))
      this.date.setMonth(this.date.getMonth() - movement);
    else if(element.hasClassName('today'))
      this.date = new Date();
    else if(element.hasClassName('reset')) {
      this.resetFields();
    }
    this.populate();
  },

  resetFields: function() {
    this.startfield.value = this.startfield.defaultValue || '';
    this.endfield.value = this.endfield.defaultValue || '';
    this.date = new Date(this.defaultDate);
    var startdate = new Date(Date.parse(this.startfield.value)).neutral();
    this.startdate = (startdate == 'Invalid Date' || startdate == 'NaN') ? null : startdate;
    var enddate = new Date(Date.parse(this.endfield)).neutral();
    this.enddate = (enddate == 'Invalid Date' || enddate == 'NaN') ? null : enddate;
  },

  handleDateClick: function(element, couldClear) {
    this.mousedown = this.dragging = true;
    if(this.stuck)
      this.stuck = false;
    else if(couldClear) {
      if(!element.hasClassName('startrange')) return;
    }
    else {
      this.stuck = true;
      setTimeout(function() { if(this.mousedown) this.stuck = false; }.bind(this), 200);
    }
    this.getPoint(element.date);
  },

  getPoint: function(date) {
    if(this.startdate && this.startdate.toString() == date && this.enddate)
      this.startdrag = this.enddate;
    else {
      this.clearButton.hide();
      if(this.enddate && this.enddate.toString() == date)
        this.startdrag = this.startdate;
      else
        this.startdrag = this.startdate = this.enddate = date;
    }
    this.refreshRange();
  },

  handleMouseover: function(event) {
    var el;
    if(!this.dragging)
      this.toggleClearButton(event);
    else if(event.findElement('span.clear.active'));
    else if(el = event.findElement('td'))
      this.extendRange(el.date);
  },

  toggleClearButton: function(event) {
    var el;
    if(event.element().ancestors && event.findElement('td.selected')) {
      if(el = this.container.select('#calendar_0 .pre.selected').first());
      else if(el = this.container.select('.active.selected').first());
      if(el) Element.insert(el, { top: this.clearButton });
      this.clearButton.removeClassName('active').show();
    }
    else {
      this.clearButton.hide();
    }
  },

  extendRange: function(date) {
    this.clearButton.hide();
    if(date > this.startdrag) {
      this.startdate = this.startdrag;
      this.enddate = date;
    }
    else if(date < this.startdrag) {
      this.startdate = date;
      this.enddate = this.startdrag;
    }
    else {
      this.startdate = this.enddate = date;
    }
    this.refreshRange();
  },

  setPoint: function(event) {
    if(!this.dragging) return;
    if(!this.stuck) {
      var el;
      this.dragging = false;
      if(el = event.findElement('span.clear.active')) {
        el.hide().removeClassName('active');
        this.startdate = this.enddate = null;
        this.refreshRange();
        this.refreshFields();
      }
    }
    this.mousedown = false;
    this.refreshRange();
  },

  refreshRange: function() {
    this.container.select('td').each(function(day) {
      if(this.startdate <= day.date && day.date <= this.enddate) {
        day.addClassName('selected');
        this.stuck || this.mousedown ? day.addClassName('stuck') : day.removeClassName('stuck');
        this.startdate.toString() == day.date ? day.addClassName('startrange') : day.removeClassName('startrange');
        this.enddate.toString() == day.date ? day.addClassName('endrange') : day.removeClassName('endrange');
      }
      else day.removeClassName('selected').removeClassName('startrange').removeClassName('endrange').removeClassName('stuck');
    }.bind(this));
    if(this.dragging) this.refreshFields();
  },

  refreshFields: function() {
    this.startfield.value = this.startdate ? this.startdate.strftime(this.format) : '';
    this.endfield.value = this.enddate ? this.enddate.strftime(this.format) : '';
  }
});

Object.extend(Date.prototype, {
  // modified from http://alternateidea.com/blog/articles/2008/2/8/a-strftime-for-prototype
  strftime: function(format) {
    var day = this.getDay(), month = this.getMonth();
    var hours = this.getHours(), minutes = this.getMinutes();
    function pad(num) { return num.toPaddedString(2); };

    return format.gsub(/\%([aAbBcdHImMpSwyY])/, function(part) {
      switch(part[1]) {
        case 'a': return Date.weekdays.invoke('substring', 0, 3)[day]; break;
        case 'A': return Date.weekdays[day]; break;
        case 'b': return Date.months.invoke('substring', 0, 3)[month]; break;
        case 'B': return Date.months[month]; break;
        case 'c': return this.toString(); break;
        case 'd': return pad(this.getDate()); break;
        case 'H': return pad(hours); break;
        case 'I': return (hours % 12 == 0) ? 12 : pad(hours % 12); break;
        case 'm': return pad(month + 1); break;
        case 'M': return pad(minutes); break;
        case 'p': return hours >= 12 ? 'PM' : 'AM'; break;
        case 'S': return pad(this.getSeconds()); break;
        case 'w': return day; break;
        case 'y': return pad(this.getFullYear() % 100); break;
        case 'Y': return this.getFullYear().toString(); break;
      }
    }.bind(this));
  },

  neutral: function() {
    var neutered = new Date(this);
    neutered.setHours(12);
    neutered.setMinutes(0);
    neutered.setSeconds(0);
    neutered.setMilliseconds(0);
    return neutered;
  }
});<|endoftext|>


<commit_before>define(['text!views/templates/app.tmp'], function (tmp) {
    'use strict';

    var module = {}, AppView;

    // The Application
    // ---------------

    // Our overall **AppView** is the top-level piece of UI.
    AppView = Backbone.View.extend({

        // Instead of generating a new element, bind to the existing skeleton of
        // the App already present in the HTML.
        el: $("#todoapp"),

        // Our template for the line of statistics at the bottom of the app.
        statsTemplate: _.template($('#stats-template').html()),

        // Delegated events for creating new items, and clearing completed ones.
        events: {
            "keypress #new-todo":  "createOnEnter",
            "keyup #new-todo":     "showTooltip",
            "click .todo-clear a": "clearCompleted"
        },

        // At initialization we bind to the relevant events on the `Todos`
        // collection, when items are added or changed. Kick things off by
        // loading any preexisting todos that might be saved in *localStorage*.
        initialize: function() {
            this.input    = this.$("#new-todo");
            _.bindAll(this, 'addOne');

            this.collection.bind('add',   this.addOne, this);
            this.collection.bind('reset', this.addAll, this);
            this.collection.bind('all',   this.render, this);

            console.log('collection');
            console.log(this.collection);

            this.collection.fetch();
        },

        // Re-rendering the App just means refreshing the statistics -- the rest
        // of the app doesn't change.
        render: function() {
            this.$('#todo-stats').html(this.statsTemplate({
            total:      this.collection.length,
            done:       this.collection.done().length,
            remaining:  this.collection.remaining().length
        }));
        },

        // Add a single todo item to the list by creating a view for it, and
        // appending its element to the `<ul>`.
        addOne: function(todo) {
            var that = this;

            require(['views/Todo'], function (todoView) {
                var view;

                todo.set({done : false, order : that.collection.nextOrder });
                view = todoView.create({ model : todo });
                that.$("#todo-list").append(view.render().el);
            });
        },

        // Add all items in the **Todos** collection at once.
        addAll: function() {
            this.collection.each(this.addOne);
        },

        // If you hit return in the main input field, and there is text to save,
        // create new **Todo** model persisting it to *localStorage*.
        createOnEnter: function(e) {
            var text = this.input.val();
            if (!text || e.keyCode != 13) return;
            this.collection.create({text: text});
            this.input.val('');
        },

        // Clear all done todo items, destroying their models.
        clearCompleted: function() {
            _.each(this.collection.done(), function(todo){ todo.destroy(); });
            return false;
        },

        // Lazily show the tooltip that tells you to press `enter` to save
        // a new todo item, after one second.
        showTooltip: function(e) {
            var tooltip = this.$(".ui-tooltip-top");
            var val = this.input.val();
            tooltip.fadeOut();
            if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
            if (val == '' || val == this.input.attr('placeholder')) return;
            var show = function(){ tooltip.show().fadeIn(); };
            this.tooltipTimeout = _.delay(show, 1000);
        }

    });

    module.create = function (properties) {
        return new AppView(properties);
    };

    return module;
});      <commit_msg>fixed toggle bug<commit_after>define(['text!views/templates/app.tmp'], function (tmp) {
    'use strict';

    var module = {}, AppView;

    // The Application
    // ---------------

    // Our overall **AppView** is the top-level piece of UI.
    AppView = Backbone.View.extend({

        // Instead of generating a new element, bind to the existing skeleton of
        // the App already present in the HTML.
        el: $("#todoapp"),

        // Our template for the line of statistics at the bottom of the app.
        statsTemplate: _.template($('#stats-template').html()),

        // Delegated events for creating new items, and clearing completed ones.
        events: {
            "keypress #new-todo":  "createOnEnter",
            "keyup #new-todo":     "showTooltip",
            "click .todo-clear a": "clearCompleted"
        },

        // At initialization we bind to the relevant events on the `Todos`
        // collection, when items are added or changed. Kick things off by
        // loading any preexisting todos that might be saved in *localStorage*.
        initialize: function() {
            this.input    = this.$("#new-todo");
            _.bindAll(this, 'addOne');

            this.collection.bind('add',   this.addOne, this);
            this.collection.bind('reset', this.addAll, this);
            this.collection.bind('all',   this.render, this);

            console.log('collection');
            console.log(this.collection);

            this.collection.fetch();
        },

        // Re-rendering the App just means refreshing the statistics -- the rest
        // of the app doesn't change.
        render: function() {
            this.$('#todo-stats').html(this.statsTemplate({
            total:      this.collection.length,
            done:       this.collection.done().length,
            remaining:  this.collection.remaining().length
        }));
        },

        // Add a single todo item to the list by creating a view for it, and
        // appending its element to the `<ul>`.
        addOne: function(todo) {
            var that = this;

            require(['views/Todo'], function (todoView) {
                var view;

                view = todoView.create({ model : todo });
                that.$("#todo-list").append(view.render().el);
            });
        },

        // Add all items in the **Todos** collection at once.
        addAll: function() {
            this.collection.each(this.addOne);
        },

        // If you hit return in the main input field, and there is text to save,
        // create new **Todo** model persisting it to *localStorage*.
        createOnEnter: function(e) {
            var text = this.input.val();
            if (!text || e.keyCode != 13) return;
            this.collection.create({text: text});
            this.input.val('');
        },

        // Clear all done todo items, destroying their models.
        clearCompleted: function() {
            _.each(this.collection.done(), function(todo){ todo.destroy(); });
            return false;
        },

        // Lazily show the tooltip that tells you to press `enter` to save
        // a new todo item, after one second.
        showTooltip: function(e) {
            var tooltip = this.$(".ui-tooltip-top");
            var val = this.input.val();
            tooltip.fadeOut();
            if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
            if (val == '' || val == this.input.attr('placeholder')) return;
            var show = function(){ tooltip.show().fadeIn(); };
            this.tooltipTimeout = _.delay(show, 1000);
        }

    });

    module.create = function (properties) {
        return new AppView(properties);
    };

    return module;
});      <|endoftext|>


<commit_before>{
	data: (function() {
		var ro = {};
		ro.partname = 'Boozembly 2015';
		ro.partlength = 1000 * 168;
		ro.cameras = {
			'writercam': new THREE.PerspectiveCamera(45, global_engine.getAspectRatio(), 0.1, 10000)
		};

		ro.scenes = {};
		ro.lights = {};
		ro.objects = {};

		ro.scenes['writer'] = (function(obj) {

			var scene = new THREE.Scene();

			var textarr = [
				[
					"°0it's °1time",
					"to °5announce"
				],
				[
					"°1boozembly °02014",
					"°2jubileum",
					"°3jul 31 - aug 3",
				],
				[
					"°4damones °7with",
					"°1boozembly",
					"disorganizing"
				],
				[
					"°3invites you to",
					"°1the scene event",
					"°3of the year",
					"°02014"
				],
				[
					"°3celebrating",
					"our °520th time",
					"°3lost in the hills"
				],
				[
					"°1boozembly °02014",
					"features",
				],
				[
					"°0nice °1people",
					"°2hot °3barbeque",
					"°4perfect °5weather",
					"°6great °7atmosphere"
				],
				[
					"°3location will",
					"be the same",
					"as last year"
				],
				[
					"°3if you don't know",
					"where to come,",
					"ask the nearest",
					"°5pullomummo"
				],
				[
					"°3if you have",
					"°6extra °3beer",
					"°3too °6many °3sausages",
					"°3stiff °6blunts"
				],
				[
					"°3feel free",
					"to",
					"°4share!"
				],
				[
					"°3add",
					"°6jul 31 - aug 3",
					"°3to your",
					"°3calendars",
					"°3now"
				],
				[
					"°3greetings fly to",
					"°0komplex °1pyrotech",
					"°2byterapers °4darklite",
					"°5accession °6kooma",
					"°7kewlers °0scoopex °1flo",
					"°2fairlight °4extend"
				],
				[
					"°1boozembly °02014",
					"°0.°1.°2.°3.°4.°5.°6.°7.°0.°1.°2.°3.°4.°5.°6.°7.",
					"°3bring your",
					"°3family"
				],
				[
					"credits for",
					"this",
					"invitation"
				],
				[
					"°7photos",
					"°6h7 & norppa",
					" ",
					"°7graphics",
					"°6h7"
				],
				[
					"°7music",
					"°6tempest",
					"    ",
					"°7code",
					"°6jawbreaker",
					"°6kakka"
				],
				[
					"°3released",
					"°3at",
					"°1graffathon",
					"°02014"
				],
				[
					"see you all",
					"in",
					"°1boozembly!"
				],
				[
					"dunkku",
					"koita",
					"keskittyä"
				]
			];

			var imagenamesarr = [];

			for (var i=1; i<58; i++) {
				var name = eval('image_pic_' + i + '.src');
				var width = eval('image_pic_' + i + '.width');
				var height = eval('image_pic_' + i + '.height');
				imagenamesarr.push({ name: name, width: width, height: height, added: false });
			}

			obj.objects['imagenamesarr'] = imagenamesarr;

			obj.objects['images'] = [];

			obj.objects['textarr'] = textarr;
			obj.objects['chargeoms'] = [];
			obj.objects['textcolors'] = {
				'0': 0xe0ab1d,
				'1': 0xe01db4,
				'2': 0x7d1de0,
				'3': 0x1d66e0,
				'4': 0x1de0b4,
				'5': 0x1de02f,
				'6': 0xe0271d,
				'7': 0xffffff,
			}

			for (var i=0; i<textarr.length; i++) {
				for (var j=0; j<textarr[i].length; j++) {
					for (var k=0; k<textarr[i][j].length; k++) {
						var c = textarr[i][j].charAt(k);

						if (c == '°') {
							k += 1;
							continue;
						}

						if (!obj.objects['chargeoms'][c]) {
							var geometry = null;
							if (c != ' ') {
									geometry = new THREE.TextGeometry(c, {
									size: 40,
									height: 20,
									curveSegments: 8,
									font: 'luckiest guy',
									weight: 'normal',
									style: 'normal',
									bevelThickness: 1.4,
									bevelSize: 0.5,
									bevelSegments: 6,
									bevelEnabled: false,
									bend: false
								});

								geometry.computeBoundingBox();
								geometry.width = geometry.boundingBox.min.x - geometry.boundingBox.max.x - 5;
							} else {
								geometry = new THREE.Geometry();
								geometry.width = -20;
							}

							obj.objects['chargeoms'][c] = geometry;
						}
					}
				}
			}

			function calculateLineLength(line) {
				var len = 0;

				for (var i=0; i<line.length; i++) {
					var c = line.charAt(i);
					if (c == '°') {
						i += 1;
						continue;
					}

					len += obj.objects['chargeoms'][c].width;
				}

				return len;
			}

			obj.objects['pagemesharr'] = [];

			for (var i=0; i<textarr.length; i++) {
				obj.objects['pagemesharr'][i] = [];

				for (var j=0; j<textarr[i].length; j++) {
					var xpos = -calculateLineLength(textarr[i][j]) / 2;
					var color = obj.objects['textcolors']['3'];

					for (var k=0; k<textarr[i][j].length; k++) {
						var c = textarr[i][j].charAt(k);

						if (c == '°') {
							color = obj.objects['textcolors'][textarr[i][j].charAt(k+1)];
							k += 2;
							c = textarr[i][j].charAt(k);
						}

						var material = new THREE.MeshLambertMaterial({ transparent: true, color: color });
						var mesh = new THREE.Mesh(obj.objects['chargeoms'][c], material);
						mesh.position.x = -xpos;
						mesh.position.y = (textarr[i].length / 2) * 50 - j * 50 - 50;
						xpos += obj.objects['chargeoms'][c].width;

						mesh.position.z = 500;
						scene.add(mesh);
						obj.objects['pagemesharr'][i].push(mesh);
					}
				}
			}

			var light = new THREE.SpotLight(0xFFFFFF);
			light.position.set(200, 200, 1500);
			scene.add(light);
			obj.lights['writerspot1'] = light;

			light = new THREE.SpotLight(0xFFFFFF);
			light.position.set(-200, -200, 1500);
			scene.add(light);
			obj.lights['writerspot2'] = light;

			light = new THREE.SpotLight(0xFFFFFF);
			light.intensity = 1.2;
			light.position.set(10, 10, 1500);
			scene.add(light);
			obj.lights['writerspot3'] = light;

			var directionallight = new THREE.DirectionalLight( 0xffffff, 0.5 );
			directionallight.position.set( 0, 1, 0 );
			scene.add( directionallight );
			obj.lights['writerdirectional'] = directionallight;

			scene.add(obj.cameras['writercam']);
			obj.cameras['writercam'].position.z = 1000;

			return scene;
		}(ro));

		ro.player = function(partdata, parttick, t) {

			var img_add_counter = Math.floor(parttick/1000);

			var img = this.objects['imagenamesarr'][img_add_counter];

			if (img && !img.added) {
				var geometry = new THREE.PlaneGeometry(img.width, img.height, 1, 1);
				var material = new THREE.MeshBasicMaterial( {map: THREE.ImageUtils.loadTexture(img.name), transparent: true} );
				var mesh = new THREE.Mesh(geometry, material);
				mesh.start_y =  Math.random() * 1000 - 500;
				mesh.start_z = -600 + img_add_counter;
				mesh.speed_x_multiplier = 5 + Math.random() * 5;
				mesh.start_x = Math.random() * 5000 - 2500;
				mesh.position.x = mesh.start_x;
				mesh.sin_z_start = Math.random();
				mesh.sin_z_multiplier = Math.random() * 5 + 3;
				mesh.position.y = mesh.start_y;
				mesh.position.z = mesh.start_z;

				this.scenes['writer'].add(mesh);
				this.objects['images'].push(mesh);
				this.objects['imagenamesarr'][img_add_counter].added = true;
			}

			for (var i=0; i<this.objects['images'].length; i++) {
				this.objects['images'][i].position.x = this.objects['images'][i].start_x + (parttick/this.objects['images'][i].speed_x_multiplier) ;

				if (this.objects['images'][i].position.x > 2000) {
					this.objects['images'][i].start_x -= 5000;
				}

				this.objects['images'][i].rotation.z = Math.sin(t/(100 * this.objects['images'][i].sin_z_multiplier)+ this.objects['images'][i].sin_z_start) / 10;

				if (img_add_counter == i) {
					this.objects['images'][i].material.opacity = (parttick - img_add_counter * 1000) / 1000;
				} else {
					this.objects['images'][i].material.opacity = 1;
				}

				if (parttick > 158000) {
					this.objects['images'][i].material.opacity = 1 - ((parttick - 158000) / 10000);
				}
			}

			var pagemaxtime = 8660;
			var page = Math.floor(parttick / pagemaxtime);
			var pagetime = parttick - page * pagemaxtime;

			for (var i=0; i<this.objects['pagemesharr'].length; i++) {
				for (var j=0; j<this.objects['pagemesharr'][i].length; j++) {
					if (i == page) {
						this.objects['pagemesharr'][i][j].position.z = Math.sin(t/200 + j/20) * 500;

						if (pagetime < 1000) {
							this.objects['pagemesharr'][i][j].material.opacity = pagetime/1000;
						} else if (pagetime > (pagemaxtime-1000)) {
							this.objects['pagemesharr'][i][j].material.opacity = (pagemaxtime - pagetime) / 1000;
						} else {
							this.objects['pagemesharr'][i][j].material.opacity = 1;
						}
					} else {
						this.objects['pagemesharr'][i][j].material.opacity = 0;
					}
				}
			}

			global_engine.renderers['main'].render(this.scenes['writer'], this.cameras['writercam']);
		}

		return ro;
	}())
}

<commit_msg>photos shuffled all over the screen<commit_after>{
	data: (function() {
		var ro = {};
		ro.partname = 'Boozembly 2015';
		ro.partlength = 1000 * 168;
		ro.cameras = {
			'photocam': new THREE.PerspectiveCamera(45, global_engine.getAspectRatio(), 0.1, 10000),
			'writercam': new THREE.PerspectiveCamera(45, global_engine.getAspectRatio(), 0.1, 10000)
		};

		ro.scenes = {};
		ro.lights = {};
		ro.objects = {};

		ro.scenes['photos'] = (function(obj) {
			obj.objects['photomaterials'] = [];

			for (var i=1; i<58; i++) {
				var name = eval('image_pic_' + i + '.src');
				var width = eval('image_pic_' + i + '.width');
				var height = eval('image_pic_' + i + '.height');

				var material = new THREE.MeshBasicMaterial( {map: THREE.ImageUtils.loadTexture(name), transparent: true} );
				material.pixelwidth = width;
				material.pixelheight = height;

				obj.objects['photomaterials'].push(material);
			}

			var scene = new THREE.Scene();

			obj.objects['photopositions'] = [];

			for (var i=0; i<5000; i++) {
				var material = obj.objects['photomaterials'][i  % obj.objects['photomaterials'].length];
				var geometry = new THREE.PlaneGeometry(material.pixelwidth,material.pixelheight, 2, 2);

				var mesh = new THREE.Mesh(geometry, material);
				var mesh_scale = Math.random() + 0.8
				mesh.scale.set(mesh_scale, mesh_scale, 1);
				mesh.renderOrder = i;
				var mesh_x_pos = Math.random() * 20000 - 10000;
				var mesh_y_pos = Math.random() * 20000 - 10000;
				var mesh_z_pos = 0;
				var mesh_rotation = Math.random() * Math.PI * 2;
				var photoposition = new THREE.Vector4(mesh_x_pos, mesh_y_pos, mesh_z_pos, mesh_rotation);

				mesh.position.set(mesh_x_pos, mesh_y_pos, mesh_z_pos);
				mesh.rotation.set(0, 0, mesh_rotation);
				scene.add(mesh);
			}

			var light = new THREE.SpotLight(0xFFFFFF);
			light.position.set(200, 200, 1500);
			scene.add(light);
			obj.lights['photospot1'] = light;

			light = new THREE.SpotLight(0xFFFFFF);
			light.position.set(-200, -200, 1500);
			scene.add(light);
			obj.lights['photospot2'] = light;

			light = new THREE.SpotLight(0xFFFFFF);
			light.intensity = 1.2;
			light.position.set(10, 10, 1500);
			scene.add(light);
			obj.lights['photospot3'] = light;

			var directionallight = new THREE.DirectionalLight( 0xffffff, 0.5 );
			directionallight.position.set( 0, 1, 0 );
			scene.add( directionallight );
			obj.lights['photodirectional'] = directionallight;

			scene.add(obj.cameras['photocam']);
			obj.cameras['photocam'].position.z = 1000;

			return scene;
		}(ro));
/*
		ro.scenes['writer'] = (function(obj) {

			var scene = new THREE.Scene();

			var textarr = [
				[
					"°0it's °1time",
					"to °5announce"
				],
				[
					"°1boozembly °02014",
					"°2jubileum",
					"°3jul 31 - aug 3",
				],
				[
					"°4damones °7with",
					"°1boozembly",
					"disorganizing"
				],
				[
					"°3invites you to",
					"°1the scene event",
					"°3of the year",
					"°02014"
				],
				[
					"°3celebrating",
					"our °520th time",
					"°3lost in the hills"
				],
				[
					"°1boozembly °02014",
					"features",
				],
				[
					"°0nice °1people",
					"°2hot °3barbeque",
					"°4perfect °5weather",
					"°6great °7atmosphere"
				],
				[
					"°3location will",
					"be the same",
					"as last year"
				],
				[
					"°3if you don't know",
					"where to come,",
					"ask the nearest",
					"°5pullomummo"
				],
				[
					"°3if you have",
					"°6extra °3beer",
					"°3too °6many °3sausages",
					"°3stiff °6blunts"
				],
				[
					"°3feel free",
					"to",
					"°4share!"
				],
				[
					"°3add",
					"°6jul 31 - aug 3",
					"°3to your",
					"°3calendars",
					"°3now"
				],
				[
					"°3greetings fly to",
					"°0komplex °1pyrotech",
					"°2byterapers °4darklite",
					"°5accession °6kooma",
					"°7kewlers °0scoopex °1flo",
					"°2fairlight °4extend"
				],
				[
					"°1boozembly °02014",
					"°0.°1.°2.°3.°4.°5.°6.°7.°0.°1.°2.°3.°4.°5.°6.°7.",
					"°3bring your",
					"°3family"
				],
				[
					"credits for",
					"this",
					"invitation"
				],
				[
					"°7photos",
					"°6h7 & norppa",
					" ",
					"°7graphics",
					"°6h7"
				],
				[
					"°7music",
					"°6tempest",
					"    ",
					"°7code",
					"°6jawbreaker",
					"°6kakka"
				],
				[
					"°3released",
					"°3at",
					"°1graffathon",
					"°02014"
				],
				[
					"see you all",
					"in",
					"°1boozembly!"
				],
				[
					"dunkku",
					"koita",
					"keskittyä"
				]
			];

			obj.objects['imagenamesarr'] = [];

			for (var i=1; i<58; i++) {
				var name = eval('image_pic_' + i + '.src');
				var width = eval('image_pic_' + i + '.width');
				var height = eval('image_pic_' + i + '.height');
				obj.objects['imagenamesarr'].push({ name: name, width: width, height: height, added: false });
			}

			obj.objects['textarr'] = textarr;
			obj.objects['chargeoms'] = [];
			obj.objects['textcolors'] = {
				'0': 0xe0ab1d,
				'1': 0xe01db4,
				'2': 0x7d1de0,
				'3': 0x1d66e0,
				'4': 0x1de0b4,
				'5': 0x1de02f,
				'6': 0xe0271d,
				'7': 0xffffff,
			}

			for (var i=0; i<textarr.length; i++) {
				for (var j=0; j<textarr[i].length; j++) {
					for (var k=0; k<textarr[i][j].length; k++) {
						var c = textarr[i][j].charAt(k);

						if (c == '°') {
							k += 1;
							continue;
						}

						if (!obj.objects['chargeoms'][c]) {
							var geometry = null;
							if (c != ' ') {
									geometry = new THREE.TextGeometry(c, {
									size: 40,
									height: 20,
									curveSegments: 8,
									font: 'luckiest guy',
									weight: 'normal',
									style: 'normal',
									bevelThickness: 1.4,
									bevelSize: 0.5,
									bevelSegments: 6,
									bevelEnabled: false,
									bend: false
								});

								geometry.computeBoundingBox();
								geometry.width = geometry.boundingBox.min.x - geometry.boundingBox.max.x - 5;
							} else {
								geometry = new THREE.Geometry();
								geometry.width = -20;
							}

							obj.objects['chargeoms'][c] = geometry;
						}
					}
				}
			}

			function calculateLineLength(line) {
				var len = 0;

				for (var i=0; i<line.length; i++) {
					var c = line.charAt(i);
					if (c == '°') {
						i += 1;
						continue;
					}

					len += obj.objects['chargeoms'][c].width;
				}

				return len;
			}

			obj.objects['pagemesharr'] = [];

			for (var i=0; i<textarr.length; i++) {
				obj.objects['pagemesharr'][i] = [];

				for (var j=0; j<textarr[i].length; j++) {
					var xpos = -calculateLineLength(textarr[i][j]) / 2;
					var color = obj.objects['textcolors']['3'];

					for (var k=0; k<textarr[i][j].length; k++) {
						var c = textarr[i][j].charAt(k);

						if (c == '°') {
							color = obj.objects['textcolors'][textarr[i][j].charAt(k+1)];
							k += 2;
							c = textarr[i][j].charAt(k);
						}

						var material = new THREE.MeshLambertMaterial({ transparent: true, color: color });
						var mesh = new THREE.Mesh(obj.objects['chargeoms'][c], material);
						mesh.position.x = -xpos;
						mesh.position.y = (textarr[i].length / 2) * 50 - j * 50 - 50;
						xpos += obj.objects['chargeoms'][c].width;

						mesh.position.z = 500;
						scene.add(mesh);
						obj.objects['pagemesharr'][i].push(mesh);
					}
				}
			}

			var light = new THREE.SpotLight(0xFFFFFF);
			light.position.set(200, 200, 1500);
			scene.add(light);
			obj.lights['writerspot1'] = light;

			light = new THREE.SpotLight(0xFFFFFF);
			light.position.set(-200, -200, 1500);
			scene.add(light);
			obj.lights['writerspot2'] = light;

			light = new THREE.SpotLight(0xFFFFFF);
			light.intensity = 1.2;
			light.position.set(10, 10, 1500);
			scene.add(light);
			obj.lights['writerspot3'] = light;

			var directionallight = new THREE.DirectionalLight( 0xffffff, 0.5 );
			directionallight.position.set( 0, 1, 0 );
			scene.add( directionallight );
			obj.lights['writerdirectional'] = directionallight;

			scene.add(obj.cameras['writercam']);
			obj.cameras['writercam'].position.z = 1000;

			return scene;
		}(ro));
*/
		ro.player = function(partdata, parttick, t) {
//			log("player: " + t);
/*
			var img_add_counter = Math.floor(parttick/1000);

			var img = this.objects['imagenamesarr'][img_add_counter];

			if (img && !img.added) {
				var geometry = new THREE.PlaneGeometry(img.width, img.height, 1, 1);
				var material = new THREE.MeshBasicMaterial( {map: THREE.ImageUtils.loadTexture(img.name), transparent: true} );
				var mesh = new THREE.Mesh(geometry, material);
				mesh.start_y =  Math.random() * 1000 - 500;
				mesh.start_z = -600 + img_add_counter;
				mesh.speed_x_multiplier = 5 + Math.random() * 5;
				mesh.start_x = Math.random() * 5000 - 2500;
				mesh.position.x = mesh.start_x;
				mesh.sin_z_start = Math.random();
				mesh.sin_z_multiplier = Math.random() * 5 + 3;
				mesh.position.y = mesh.start_y;
				mesh.position.z = mesh.start_z;

				this.scenes['writer'].add(mesh);
				this.objects['images'].push(mesh);
				this.objects['imagenamesarr'][img_add_counter].added = true;
			}

			for (var i=0; i<this.objects['images'].length; i++) {
				this.objects['images'][i].position.x = this.objects['images'][i].start_x + (parttick/this.objects['images'][i].speed_x_multiplier) ;

				if (this.objects['images'][i].position.x > 2000) {
					this.objects['images'][i].start_x -= 5000;
				}

				this.objects['images'][i].rotation.z = Math.sin(t/(100 * this.objects['images'][i].sin_z_multiplier)+ this.objects['images'][i].sin_z_start) / 10;

				if (img_add_counter == i) {
					this.objects['images'][i].material.opacity = (parttick - img_add_counter * 1000) / 1000;
				} else {
					this.objects['images'][i].material.opacity = 1;
				}

				if (parttick > 158000) {
					this.objects['images'][i].material.opacity = 1 - ((parttick - 158000) / 10000);
				}
			}

			var pagemaxtime = 8660;
			var page = Math.floor(parttick / pagemaxtime);
			var pagetime = parttick - page * pagemaxtime;

			for (var i=0; i<this.objects['pagemesharr'].length; i++) {
				for (var j=0; j<this.objects['pagemesharr'][i].length; j++) {
					if (i == page) {
						this.objects['pagemesharr'][i][j].position.z = Math.sin(t/200 + j/20) * 500;

						if (pagetime < 1000) {
							this.objects['pagemesharr'][i][j].material.opacity = pagetime/1000;
						} else if (pagetime > (pagemaxtime-1000)) {
							this.objects['pagemesharr'][i][j].material.opacity = (pagemaxtime - pagetime) / 1000;
						} else {
							this.objects['pagemesharr'][i][j].material.opacity = 1;
						}
					} else {
						this.objects['pagemesharr'][i][j].material.opacity = 0;
					}
				}
			}
*/

			this.cameras['photocam'].position.z = t;

			global_engine.renderers['main'].render(this.scenes['photos'], this.cameras['photocam']);
		}

		return ro;
	}())
}

<|endoftext|>


<commit_before>/*
* @Author: dmyang
* @Date:   2015-08-02 14:16:41
* @Last Modified by:   dmyang
* @Last Modified time: 2016-08-01 16:06:08
*/

'use strict';

const path = require('path')
const fs = require('fs')

const webpack = require('webpack')
const _ = require('lodash')
const glob = require('glob')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin
const DefinePlugin = webpack.DefinePlugin

const srcDir = path.resolve(process.cwd(), 'src')
const assets = path.resolve(process.cwd(), 'assets')
const nodeModPath = path.resolve(__dirname, './node_modules')
const pathMap = require('./src/pathmap.json')

let entries = (() => {
    let jsDir = path.resolve(srcDir, 'js')
    let entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
    let map = {}

    entryFiles.forEach((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
    })

    return map
})()
let chunks = Object.keys(entries)

module.exports = (options) => {
    options = options || {}

    let dev = options.dev !== undefined ? options.dev : true
    // 这里publicPath要使用绝对路径，不然scss/css最终生成的css图片引用路径是错误的，应该是scss-loader的bug
    let publicPath = '/'
    let extractCSS
    let cssLoader
    let sassLoader

    // generate entry html files
    // 自动生成入口文件，入口js名必须和入口文件名相同
    // 例如，a页的入口文件是a.html，那么在js目录下必须有一个a.js作为入口文件
    let plugins = () => {
        let entryHtml = glob.sync(srcDir + '/*.html')
        let r = []

        entryHtml.forEach((filePath) => {
            let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
            let conf = {
                template: 'html!' + filePath,
                filename: filename + '.html'
            }

            if(filename in entries) {
                conf.inject = 'body'
                conf.chunks = ['vender', 'common', filename]
            }

            if('b' === filename || 'c' === filename) conf.chunks.splice(2, 0, 'common-b-c')
            // dll打包过的库，只能通过script标签引入？？
            // if('react-demo' === filename) conf.chunks.splice(2, 0, 'reactStuff')

            r.push(new HtmlWebpackPlugin(conf))
        })

        return r
    }()

    // 没有真正引用也会加载到runtime，如果没安装这些模块会导致报错，有点坑
    /*plugins.push(
        new webpack.ProvidePlugin({
            React: 'react',
            ReactDOM: 'react-dom',
            _: 'lodash', 按需引用
            $: 'jquery'
        })
    )*/

    if(dev) {
        extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
        cssLoader = extractCSS.extract(['css'])
        sassLoader = extractCSS.extract(['css', 'sass'])
        plugins.push(extractCSS, new webpack.HotModuleReplacementPlugin())
    } else {
        extractCSS = new ExtractTextPlugin('css/[contenthash:8].[name].min.css', {
            // 当allChunks指定为false时，css loader必须指定怎么处理
            // additional chunk所依赖的css，即指定`ExtractTextPlugin.extract()`
            // 第一个参数`notExtractLoader`，一般是使用style-loader
            // @see https://github.com/webpack/extract-text-webpack-plugin
            allChunks: false
        })
        cssLoader = extractCSS.extract(['css?minimize'])
        sassLoader = extractCSS.extract(['css?minimize', 'sass'])

        plugins.push(
            extractCSS,
            new UglifyJsPlugin({
                compress: {
                    warnings: false
                },
                output: {
                    comments: false
                },
                mangle: {
                    except: ['$', 'exports', 'require']
                }
            }),
            // use `production` mode
            new DefinePlugin({'process.env': {'NODE_ENV': JSON.stringify('production')}}),
            // new AssetsPlugin({
            //     filename: path.resolve(assets, 'source-map.json')
            // }),
            new webpack.optimize.DedupePlugin(),
            new webpack.NoErrorsPlugin()
        )
    }

    let config = {
        entry: Object.assign(entries, {
            // 用到什么公共lib（例如React.js），就把它加进vender去，目的是将公用库单独提取打包
            'vender': ['zepto'],
            // 'reactStuff': 'assets/dll/js/reactStuff.js'
        }),

        output: {
            path: assets,
            filename: dev ? '[name].js' : 'js/[chunkhash:8].[name].min.js',
            chunkFilename: dev ? '[chunkhash:8].chunk.js' : 'js/[chunkhash:8].chunk.min.js',
            hotUpdateChunkFilename: dev ? '[id].js' : 'js/[id].[chunkhash:8].min.js',
            publicPath: publicPath
        },

        resolve: {
            root: [srcDir, nodeModPath],
            alias: pathMap,
            extensions: ['', '.js', '.css', '.scss', '.tpl', '.png', '.jpg']
        },

        module: {
            loaders: [
                {
                    test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
                    loaders: [
                        // url-loader更好用，小于10KB的图片会自动转成dataUrl，
                        // 否则则调用file-loader，参数直接传入
                        'url?limit=10000&name=img/[hash:8].[name].[ext]',
                        'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
                    ]
                },
                {
                    test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
                    loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
                },
                {test: /\.(tpl|ejs)$/, loader: 'ejs'},
                {test: /\.css$/, loader: cssLoader},
                {test: /\.scss$/, loader: sassLoader},
                {test: /\.jsx?$/, loader: 'babel?presets[]=react,presets[]=es2015'}
            ]
        },

        plugins: [
            new webpack.DllReferencePlugin({
                context: process.cwd(),
                manifest: require(path.join(assets, 'dll', 'js', 'reactStuff-manifest.json')),
                sourceType: 'var',
                // name: 'assets/dll/js/reactStuff.js'
            }),
            new CommonsChunkPlugin({
                name: 'common-b-c',
                chunks: ['b', 'c']
            }),
            new CommonsChunkPlugin({
                name: 'common',
                chunks: ['common-b-c', 'a']
            }),
            new CommonsChunkPlugin({
                name: 'vender',
                chunks: ['common']
            })
        ].concat(plugins),

        devServer: {
            hot: true,
            noInfo: false,
            inline: true,
            publicPath: publicPath,
            stats: {
                cached: false,
                colors: true
            }
        }
    }

    if (dev) {
        // 为实现webpack-hot-middleware做相关配置
        // @see https://github.com/glenjamin/webpack-hot-middleware
        ((entry) => {
            for (let key of Object.keys(entry)) {
                if (! Array.isArray(entry[key])) {
                    entry[key] = Array.of(entry[key])
                }
                entry[key].push('webpack-hot-middleware/client?reload=true')
            }
        })(config.entry)

        config.plugins.push( new webpack.HotModuleReplacementPlugin() )
        config.plugins.push( new webpack.NoErrorsPlugin() )
    }

    return config
}
<commit_msg>remove dll config<commit_after>/*
* @Author: dmyang
* @Date:   2015-08-02 14:16:41
* @Last Modified by:   dmyang
* @Last Modified time: 2016-08-01 16:07:10
*/

'use strict';

const path = require('path')
const fs = require('fs')

const webpack = require('webpack')
const _ = require('lodash')
const glob = require('glob')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin
const DefinePlugin = webpack.DefinePlugin

const srcDir = path.resolve(process.cwd(), 'src')
const assets = path.resolve(process.cwd(), 'assets')
const nodeModPath = path.resolve(__dirname, './node_modules')
const pathMap = require('./src/pathmap.json')

let entries = (() => {
    let jsDir = path.resolve(srcDir, 'js')
    let entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
    let map = {}

    entryFiles.forEach((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
    })

    return map
})()
let chunks = Object.keys(entries)

module.exports = (options) => {
    options = options || {}

    let dev = options.dev !== undefined ? options.dev : true
    // 这里publicPath要使用绝对路径，不然scss/css最终生成的css图片引用路径是错误的，应该是scss-loader的bug
    let publicPath = '/'
    let extractCSS
    let cssLoader
    let sassLoader

    // generate entry html files
    // 自动生成入口文件，入口js名必须和入口文件名相同
    // 例如，a页的入口文件是a.html，那么在js目录下必须有一个a.js作为入口文件
    let plugins = () => {
        let entryHtml = glob.sync(srcDir + '/*.html')
        let r = []

        entryHtml.forEach((filePath) => {
            let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
            let conf = {
                template: 'html!' + filePath,
                filename: filename + '.html'
            }

            if(filename in entries) {
                conf.inject = 'body'
                conf.chunks = ['vender', 'common', filename]
            }

            if('b' === filename || 'c' === filename) conf.chunks.splice(2, 0, 'common-b-c')
            // dll打包过的库，只能通过script标签引入？？
            // if('react-demo' === filename) conf.chunks.splice(2, 0, 'reactStuff')

            r.push(new HtmlWebpackPlugin(conf))
        })

        return r
    }()

    // 没有真正引用也会加载到runtime，如果没安装这些模块会导致报错，有点坑
    /*plugins.push(
        new webpack.ProvidePlugin({
            React: 'react',
            ReactDOM: 'react-dom',
            _: 'lodash', 按需引用
            $: 'jquery'
        })
    )*/

    if(dev) {
        extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
        cssLoader = extractCSS.extract(['css'])
        sassLoader = extractCSS.extract(['css', 'sass'])
        plugins.push(extractCSS, new webpack.HotModuleReplacementPlugin())
    } else {
        extractCSS = new ExtractTextPlugin('css/[contenthash:8].[name].min.css', {
            // 当allChunks指定为false时，css loader必须指定怎么处理
            // additional chunk所依赖的css，即指定`ExtractTextPlugin.extract()`
            // 第一个参数`notExtractLoader`，一般是使用style-loader
            // @see https://github.com/webpack/extract-text-webpack-plugin
            allChunks: false
        })
        cssLoader = extractCSS.extract(['css?minimize'])
        sassLoader = extractCSS.extract(['css?minimize', 'sass'])

        plugins.push(
            extractCSS,
            new UglifyJsPlugin({
                compress: {
                    warnings: false
                },
                output: {
                    comments: false
                },
                mangle: {
                    except: ['$', 'exports', 'require']
                }
            }),
            // use `production` mode
            new DefinePlugin({'process.env': {'NODE_ENV': JSON.stringify('production')}}),
            // new AssetsPlugin({
            //     filename: path.resolve(assets, 'source-map.json')
            // }),
            new webpack.optimize.DedupePlugin(),
            new webpack.NoErrorsPlugin()
        )
    }

    let config = {
        entry: Object.assign(entries, {
            // 用到什么公共lib（例如React.js），就把它加进vender去，目的是将公用库单独提取打包
            'vender': ['zepto'],
            // 'reactStuff': 'assets/dll/js/reactStuff.js'
        }),

        output: {
            path: assets,
            filename: dev ? '[name].js' : 'js/[chunkhash:8].[name].min.js',
            chunkFilename: dev ? '[chunkhash:8].chunk.js' : 'js/[chunkhash:8].chunk.min.js',
            hotUpdateChunkFilename: dev ? '[id].js' : 'js/[id].[chunkhash:8].min.js',
            publicPath: publicPath
        },

        resolve: {
            root: [srcDir, nodeModPath],
            alias: pathMap,
            extensions: ['', '.js', '.css', '.scss', '.tpl', '.png', '.jpg']
        },

        module: {
            loaders: [
                {
                    test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
                    loaders: [
                        // url-loader更好用，小于10KB的图片会自动转成dataUrl，
                        // 否则则调用file-loader，参数直接传入
                        'url?limit=10000&name=img/[hash:8].[name].[ext]',
                        'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
                    ]
                },
                {
                    test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
                    loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
                },
                {test: /\.(tpl|ejs)$/, loader: 'ejs'},
                {test: /\.css$/, loader: cssLoader},
                {test: /\.scss$/, loader: sassLoader},
                {test: /\.jsx?$/, loader: 'babel?presets[]=react,presets[]=es2015'}
            ]
        },

        plugins: [
            /*new webpack.DllReferencePlugin({
                context: process.cwd(),
                manifest: require(path.join(assets, 'dll', 'js', 'reactStuff-manifest.json')),
                sourceType: 'var',
                // name: 'assets/dll/js/reactStuff.js'
            }),*/
            new CommonsChunkPlugin({
                name: 'common-b-c',
                chunks: ['b', 'c']
            }),
            new CommonsChunkPlugin({
                name: 'common',
                chunks: ['common-b-c', 'a']
            }),
            new CommonsChunkPlugin({
                name: 'vender',
                chunks: ['common']
            })
        ].concat(plugins),

        devServer: {
            hot: true,
            noInfo: false,
            inline: true,
            publicPath: publicPath,
            stats: {
                cached: false,
                colors: true
            }
        }
    }

    if (dev) {
        // 为实现webpack-hot-middleware做相关配置
        // @see https://github.com/glenjamin/webpack-hot-middleware
        ((entry) => {
            for (let key of Object.keys(entry)) {
                if (! Array.isArray(entry[key])) {
                    entry[key] = Array.of(entry[key])
                }
                entry[key].push('webpack-hot-middleware/client?reload=true')
            }
        })(config.entry)

        config.plugins.push( new webpack.HotModuleReplacementPlugin() )
        config.plugins.push( new webpack.NoErrorsPlugin() )
    }

    return config
}
<|endoftext|>


<commit_before>(function() {

'use strict';

MacrosService.$inject = ['api', 'autosave', 'notify'];
function MacrosService(api, autosave, notify) {
    this.get = function() {
        return api.query('macros')
            .then(angular.bind(this, function(macros) {
                this.macros = macros._items;
                return this.macros;
            }));
    };

    this.getByDesk = function(desk) {
        return api.query('macros', {'desk': desk})
            .then(angular.bind(this, function(macros) {
                this.macros = macros._items;
                return this.macros;
            }));
    };

    this.setupShortcuts = function ($scope) {
        this.get().then(function(macros) {
            angular.forEach(macros, function(macro) {
                if (macro.shortcut) {
                    $scope.$on('key:ctrl:' + macro.shortcut, function() {
                        triggerMacro(macro, $scope.item);
                    });
                }
            });
        });
    };

    this.call = triggerMacro;

    function triggerMacro(macro, item, commit) {
        return api.save('macros', {
            macro: macro.name,
            item: _.omit(item), // get all the properties as shallow copy
            commit: !!commit
        }).then(function(res) {
            angular.extend(item, res.item);
            if (!commit) {
                autosave.save(item);
            }
            return item;
        }, function(err) {
            if (angular.isDefined(err.data._message)) {
                notify.error(gettext('Error: ' + err.data._message));
            }
        });
    }
}

MacrosController.$inject = ['$scope', 'macros', 'desks'];
function MacrosController($scope, macros, desks) {
    macros.get().then(function() {
        var currentDeskId = desks.getCurrentDeskId();
        if (currentDeskId !== null) {
            macros.getByDesk(desks.getCurrentDesk().name).then(function(_macros) {
                $scope.macros = _macros;
            });
        } else {
            $scope.macros = macros.macros;
        }
    });
    $scope.call = function(macro) {
        return macros.call(macro, $scope.item);
    };
}

angular.module('superdesk.authoring.macros', [])

    .service('macros', MacrosService)
    .controller('Macros', MacrosController)

    .config(['authoringWidgetsProvider', function(authoringWidgetsProvider) {
        authoringWidgetsProvider
            .widget('macros', {
                icon: 'macros',
                label: gettext('Macros'),
                template: 'scripts/superdesk-authoring/macros/views/macros-widget.html',
                order: 6,
                side: 'right',
                display: {authoring: true, packages: true, legalArchive: false}
            });
    }]);
})();
<commit_msg>[SD-3066] - Prevent macro execution on killed stories<commit_after>(function() {

'use strict';

MacrosService.$inject = ['api', 'autosave', 'notify'];
function MacrosService(api, autosave, notify) {
    this.get = function() {
        return api.query('macros')
            .then(angular.bind(this, function(macros) {
                this.macros = macros._items;
                return this.macros;
            }));
    };

    this.getByDesk = function(desk) {
        return api.query('macros', {'desk': desk})
            .then(angular.bind(this, function(macros) {
                this.macros = macros._items;
                return this.macros;
            }));
    };

    this.setupShortcuts = function ($scope) {
        this.get().then(function(macros) {
            angular.forEach(macros, function(macro) {
                if (macro.shortcut) {
                    $scope.$on('key:ctrl:' + macro.shortcut, function() {
                        triggerMacro(macro, $scope.item);
                    });
                }
            });
        });
    };

    this.call = triggerMacro;

    function triggerMacro(macro, item, commit) {
        return api.save('macros', {
            macro: macro.name,
            item: _.omit(item), // get all the properties as shallow copy
            commit: !!commit
        }).then(function(res) {
            angular.extend(item, res.item);
            if (!commit) {
                autosave.save(item);
            }
            return item;
        }, function(err) {
            if (angular.isDefined(err.data._message)) {
                notify.error(gettext('Error: ' + err.data._message));
            }
        });
    }
}

MacrosController.$inject = ['$scope', 'macros', 'desks'];
function MacrosController($scope, macros, desks) {
    macros.get().then(function() {
        var currentDeskId = desks.getCurrentDeskId();
        if (currentDeskId !== null) {
            macros.getByDesk(desks.getCurrentDesk().name).then(function(_macros) {
                $scope.macros = _macros;
            });
        } else {
            $scope.macros = macros.macros;
        }
    });
    $scope.call = function(macro) {
        return macros.call(macro, $scope.item);
    };
}

angular.module('superdesk.authoring.macros', [])

    .service('macros', MacrosService)
    .controller('Macros', MacrosController)

    .config(['authoringWidgetsProvider', function(authoringWidgetsProvider) {
        authoringWidgetsProvider
            .widget('macros', {
                icon: 'macros',
                label: gettext('Macros'),
                template: 'scripts/superdesk-authoring/macros/views/macros-widget.html',
                order: 6,
                needEditable: true,
                side: 'right',
                display: {authoring: true, packages: true, legalArchive: false}
            });
    }]);
})();
<|endoftext|>