<commit_before>const { LayerController } = require('../components/layerController');

var globalMap = {};
var imageUrl = '';
global.L = { DomEvent: {disableClickPropagation: jest.fn(), disableScrollPropagation: jest.fn()},
            imageOverlay: (raster, coordinates, settings) => ({setUrl: (url, coords, options) => {globalMap[url] = coords; imageUrl = url;},
                                                               addTo: (map) => {globalMap[raster] = coordinates},
                                                               remove: (map) => {delete globalMap[raster]},
                                                               bringToFront: () => {},
                                                               bringToBack: () => {},
                                                               _image: {}}),
            icon: (options) => {}};

const controller = require('../components/Controller.js');
jest.mock('../components/Controller.js', () => ({
    controllers: ({
        currentDomain: ({
            getValue: () => 1,
            subscribe: () => {}
        }),
        syncImageLoad: ({
            subscribe: (fun) => {},
            increment: () => {}
        }),
        currentTimestamp: ({
            getValue: () => '2020',
            subscribe: (fun) => {}
        }),
    }),

}));

const util = require('../util.js');
jest.mock('../util.js', () => ({
    simVars: ({
        currentSimulation: 'test',
        rasters: ({
            1: {
                "2020": {"raster": {raster: "raster test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, "colorbar": "test colorbar raster"},
                    "overlay": {raster: "overlay test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, "colorbar": "test colorbar overlay" }},
                "2021": {"raster": {raster: "raster test current timestamp", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                    "overlay": {raster: "overlay test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            },
            2: {
                "2020": {"raster": {raster: "raster test 2", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                    "overlay": {raster: "overlay test 2", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            }
        }),
        rasterBase: 'testBase/',
        sortedTimestamps: ['2020'],
        overlayOrder: [],
        displayedColorbar: null,
        organization: 'SJSU',
        overlayList: ['overlay'],
        baseLayerDict: {},
    }),
    map: {
        addTo: jest.fn(),
        fitBounds: jest.fn(),
        on: jest.fn()
    },
    dragElement: jest.fn(),
    debounce: jest.fn()
}));

HTMLCanvasElement.prototype.getContext = () => {
    return {drawImage: jest.fn()}
};

describe('Tests for adding layers to menu and selecting layers', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should populate its raster and overlay layers correctly', () => {
        const rasterDict = layerController.rasterDict;
        const overlayDict = layerController.overlayDict;
        expect(Object.entries(rasterDict).length).toEqual(1);
        expect('raster' in rasterDict).toEqual(true);
        expect(Object.entries(overlayDict).length).toEqual(1);
        expect('overlay' in overlayDict).toEqual(true);
    });

    test('Layers should be correctly added to the map when selected', () => {
        layerController.handleOverlayadd('raster');
        expect('testBase/raster test' in globalMap).toEqual(true);
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
    });

    test('Layers should be correctly removed from the map when selected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect('testBase/raster test' in globalMap).toEqual(false);
    });

    test('Layer Controller should preserve previous selected layers when domain is switched on the same simulation', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
        expect('testBase/raster test 2' in globalMap).toEqual(true);
        expect('testBase/raster test' in globalMap).toEqual(false);
    });

    test('Layer Controller should clear selected layers when domain is switched to new simulation', () => {
        layerController.handleOverlayadd('raster');
        util.simVars.currentSimulation = 'new simulation';
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.length).toEqual(0);
        expect(globalMap).toEqual({});
    });

    test('Layer Controller should show the current_timestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect('testBase/raster test current timestamp' in globalMap).toEqual(true);
    });

    test('updateSlider should set img according to currentTimestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect(imageUrl).toEqual('testBase/raster test current timestamp');
    });
});

describe('Tests for adding layers with colorbars', () => {
    var layerController;

    beforeEach(async () => {
        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () => '2020';

        util.simVars.overlayOrder = [];
        util.simVars.displayedColorbar = '';

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should add any colorbars', () => {
        layerController.handleOverlayadd('raster');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbars when layer deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect(util.simVars.displayedColorbar).toEqual(null);
    });

    test('Layer Controller should put most recent selected colorbar on top', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        expect(util.simVars.displayedColorbar).toEqual('overlay');
    });

    test('Layer Controller should put last selected colorbar on top when another is deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        layerController.handleOverlayRemove('overlay');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbar when switching to a domain without one', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.displayedColorbar).toEqual(null);
    });
});<commit_msg>Sets up tests for preloading in layerController<commit_after>const { LayerController } = require('../components/layerController');

var globalMap = {};
var imageUrl = '';
global.L = { DomEvent: {disableClickPropagation: jest.fn(), disableScrollPropagation: jest.fn()},
            imageOverlay: (raster, coordinates, settings) => ({setUrl: (url, coords, options) => {globalMap[url] = coords; imageUrl = url;},
                                                               addTo: (map) => {globalMap[raster] = coordinates},
                                                               remove: (map) => {delete globalMap[raster]},
                                                               bringToFront: () => {},
                                                               bringToBack: () => {},
                                                               _image: {}}),
            icon: (options) => {}};

const controller = require('../components/Controller.js');
jest.mock('../components/Controller.js', () => ({
    controllers: ({
        currentDomain: ({
            getValue: () => 1,
            subscribe: () => {}
        }),
        syncImageLoad: ({
            subscribe: (fun) => {},
            increment: () => {}
        }),
        currentTimestamp: ({
            getValue: () => '2020',
            subscribe: (fun) => {}
        }),
    }),

}));

const util = require('../util.js');
jest.mock('../util.js', () => ({
    simVars: ({
        currentSimulation: 'test',
        rasters: ({
            1: {
                '2020': {'raster': {raster: 'raster test', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'test colorbar raster'},
                    'overlay': {raster: 'overlay test', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'test colorbar overlay' }},
                '2021': {'raster': {raster: 'raster test current timestamp', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                    'overlay': {raster: 'overlay test', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            },
            2: {
                '2020': {'raster': {raster: 'raster test 2', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                    'overlay': {raster: 'overlay test 2', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            }
        }),
        rasterBase: 'testBase/',
        sortedTimestamps: ['2020'],
        overlayOrder: [],
        displayedColorbar: null,
        organization: 'SJSU',
        overlayList: ['overlay'],
        baseLayerDict: {},
    }),
    map: {
        addTo: jest.fn(),
        fitBounds: jest.fn(),
        on: jest.fn()
    },
    dragElement: jest.fn(),
    debounce: jest.fn()
}));

HTMLCanvasElement.prototype.getContext = () => {
    return {drawImage: jest.fn()}
};

describe('Tests for adding layers to menu and selecting layers', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should populate its raster and overlay layers correctly', () => {
        const rasterDict = layerController.rasterDict;
        const overlayDict = layerController.overlayDict;
        expect(Object.entries(rasterDict).length).toEqual(1);
        expect('raster' in rasterDict).toEqual(true);
        expect(Object.entries(overlayDict).length).toEqual(1);
        expect('overlay' in overlayDict).toEqual(true);
    });

    test('Layers should be correctly added to the map when selected', () => {
        layerController.handleOverlayadd('raster');
        expect('testBase/raster test' in globalMap).toEqual(true);
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
    });

    test('Layers should be correctly removed from the map when selected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect('testBase/raster test' in globalMap).toEqual(false);
    });

    test('Layer Controller should preserve previous selected layers when domain is switched on the same simulation', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.includes('raster')).toEqual(true);
        expect('testBase/raster test 2' in globalMap).toEqual(true);
        expect('testBase/raster test' in globalMap).toEqual(false);
    });

    test('Layer Controller should clear selected layers when domain is switched to new simulation', () => {
        layerController.handleOverlayadd('raster');
        util.simVars.currentSimulation = 'new simulation';
        layerController.domainSwitch();
        expect(util.simVars.overlayOrder.length).toEqual(0);
        expect(globalMap).toEqual({});
    });

    test('Layer Controller should show the current_timestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect('testBase/raster test current timestamp' in globalMap).toEqual(true);
    });

    test('updateSlider should set img according to currentTimestamp', () => {
        controller.controllers.currentTimestamp.getValue = () => '2021';
        layerController.handleOverlayadd('raster');
        expect(imageUrl).toEqual('testBase/raster test current timestamp');
    });
});

describe('Tests for adding layers with colorbars', () => {
    var layerController;

    beforeEach(async () => {
        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () => '2020';

        util.simVars.overlayOrder = [];
        util.simVars.displayedColorbar = '';

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn();
    });

    test('Layer Controller should add any colorbars', () => {
        layerController.handleOverlayadd('raster');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbars when layer deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayRemove('raster');
        expect(util.simVars.displayedColorbar).toEqual(null);
    });

    test('Layer Controller should put most recent selected colorbar on top', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        expect(util.simVars.displayedColorbar).toEqual('overlay');
    });

    test('Layer Controller should put last selected colorbar on top when another is deselected', () => {
        layerController.handleOverlayadd('raster');
        layerController.handleOverlayadd('overlay');
        layerController.handleOverlayRemove('overlay');
        expect(util.simVars.displayedColorbar).toEqual('raster');
    });

    test('Layer Controller should remove colorbar when switching to a domain without one', () => {
        layerController.handleOverlayadd('raster');
        controller.controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect(util.simVars.displayedColorbar).toEqual(null);
    });
});

describe('Tests for preloading', () => {
    var layerController;

    beforeEach(async () => {
        globalMap = {};

        controller.controllers.currentDomain.getValue = () => 1;
        controller.controllers.currentTimestamp.getValue = () =>'2020';

        util.simVars.rasters = ({
            1: {
                '2020': {'layer': {raster: 'rasterTest1/2020', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar1/2020'}},
                '2021': {'layer': {raster: 'rasterTest1/2021', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar1/2021'}}
            },
            2: {
                '2020': {'layer': {raster: 'rasterTest2/2020', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2020'}},
                '2020.5': {'layer': {raster: 'rasterTest2/2020.5', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2020.5'}},
                '2021': {'layer': {raster: 'rasterTest2/2021', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2021'}},
                '2021.5': {'layer': {raster: 'rasterTest2/2021.5', coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}, 'colorbar': 'colorbar2/2021.5'}}
            }
        })
        util.simVars.overlayOrder = []

        const div = document.createElement('div');
        div.id = 'raster-colorbar';
        await document.body.appendChild(div);

        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
        layerController.loadWithPriority = jest.fn()
    });

    test('test test', () => {
        expect(true).toEqual(true);
    });
});<|endoftext|>


<commit_before>'use strict';

module.exports = function(messageObject) {
  if (messageObject && messageObject.sender && messageObject.sender.id && messageObject.message && messageObject.message.text) {
    return {
      sender: messageObject.sender.id,
      text: messageObject.message.text,
      originalRequest: messageObject,
      type: 'facebook'
    };
  }
  else if (messageObject && messageObject.sender && messageObject.sender.id && messageObject.postback && messageObject.postback.payload) {
    return {
      sender: messageObject.sender.id,
      text: messageObject.postback.payload,
      originalRequest: messageObject,
      postback: true,
      type: 'facebook'
    };
  }
  else if (messageObject && messageObject.sender && messageObject.sender.id &&
    (typeof messageObject.delivery !== 'object' && typeof messageObject.read !== 'object' && (!messageObject.message || !messageObject.message.is_echo))) { // Disable delivery and read reports and message echos
    return {
      sender: messageObject.sender.id,
      text: (messageObject.message && messageObject.message.text) ? messageObject.message.text : '',
      originalRequest: messageObject,
      type: 'facebook'
    };
  }
};
<commit_msg>Parse FB quick reply text as message.text<commit_after>'use strict';

module.exports = function(messageObject) {
  if (messageObject && messageObject.sender && messageObject.sender.id && messageObject.message && messageObject.message.text) {
    return {
      sender: messageObject.sender.id,
      text: messageObject.message.text,
      originalRequest: messageObject,
      type: 'facebook'
    };
  }
  else if (messageObject && messageObject.sender && messageObject.sender.id && messageObject.postback && messageObject.postback.payload) {
    return {
      sender: messageObject.sender.id,
      text: messageObject.postback.payload,
      originalRequest: messageObject,
      postback: true,
      type: 'facebook'
    };
  }
  else if (messageObject && messageObject.sender && messageObject.sender.id && messageObject.message && messageObject.message.quick_reply && messageObject.message.quick_reply.payload) {
    return {
      sender: messageObject.sender.id,
      text: messageObject.message.quick_reply.payload,
      originalRequest: messageObject,
      postback: true,
      type: 'facebook'
    };
  }
  else if (messageObject && messageObject.sender && messageObject.sender.id &&
    (typeof messageObject.delivery !== 'object' && typeof messageObject.read !== 'object' && (!messageObject.message || !messageObject.message.is_echo))) { // Disable delivery and read reports and message echos
    return {
      sender: messageObject.sender.id,
      text: (messageObject.message && messageObject.message.text) ? messageObject.message.text : '',
      originalRequest: messageObject,
      type: 'facebook'
    };
  }
};
<|endoftext|>


<commit_before>$(document).ready(function() {

 var hideElement = function(element){
  element.hide();
 }

 hideElement("PUT FORM HERE")
 $('PUT BUTTON HERE').on('submit', function(event) {
  event.preventDefault
  $('PUT FORM HERE').show();
 });

  // This is called after the document has loaded in its entirety

 // This guarantees that any elements we bind to will exist on the page
  // when we try to bind to them

  // See: http://docs.jquery.com/Tutorials:Introducing_$(document).ready()

});
<commit_msg>add some jquery stuff<commit_after>$(document).ready(function() {

 var hideElement = function(element){
  element.hide();
 }

 hideElement("PUT FORM HERE")
 $('PUT Response BUTTON HERE').on('click', function(event) {
  event.preventDefault
  $('PUT FORM HERE').show();
  hideElement("PUT respond button FORM HERE")
 });

  // Not finished yet.....

  //  $("#comment_form").on('submit', function(event){
  //   event.preventDefault();
  //   var formInputs = $(this).serializeArray()
  //   var comment = formInputs[0]['value'];
  //   var author = formInputs[1]['value'];
  //   debugger
  //   console.log(comment)

  //   if (comment != '' || author != ''){
  //     $('#comment_list').append('
' + comment + '' + author + '
');
  //   };

  // });

});
<|endoftext|>


<commit_before>var get = require("../blog/get");
var Entry = require("../../app/models/entry");
var build = require("../../app/build");

if (require.main === module) {
  get(process.argv[2], function(user, blog) {
    main(blog, process.argv[3], function(err) {
      if (err) throw err;
      process.exit();
    });
  });
}

function main(blog, path, callback) {
  console.log("Blog " + blog.id + ":", "Rebuilding", path);
  build(blog, path, {}, function(err, entry) {
    console.log("Back with", err, entry);

    if (err) return callback(err);

    console.log("Saving entry...");
    Entry.set(blog.id, path, entry, function(err) {
      if (err) return callback(err);

      console.log("Blog " + blog.id + ":", "Rebuilt", path);
      callback(null);
    });
  });
}
<commit_msg>Updated script to rebuild a single entry<commit_after>var get = require("../get/entry");
var sync = require("../../app/sync");

get(process.argv[2], function(err, user, blog, entry) {
  if (err) throw err;
  sync(blog.id, function(err, folder, done) {
    if (err) throw err;
    folder.update(entry.path, function(err) {
      if (err) throw err;
      done(null, function(err) {
        if (err) throw err;
      });
    });
  });
});
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { DropTarget } from 'react-dnd'
import Immutable from 'immutable'

import Item from './Item'

// You can drop to a list if it's empty
const target = {
  drop(targetProps, monitor) {
    const targetTeam = targetProps.team
    const sourceProps = monitor.getItem()
    const sourcePlayer = sourceProps.player

    const count = isImmutable(targetTeam)
      ? targetTeam.get('players').count()
      : targetTeam.players.length

    if (!count) {
      targetProps.moveToList(sourcePlayer, targetTeam)
    }
  }
}

@DropTarget('Item', target, (connect) => ({
  connectDropTarget: connect.dropTarget()
}))
export default class List extends Component {

  // abusing refs to keep the example simple and in one place

  _addPlayer = event => {
    const name = event.target.value
    if (name === '') return
    this.refs.addnew.value = ''
    this.refs.addnew.focus()
    this.props.addPlayer(name, this.props.team)
  }

  _editPlayer = (player, name) => {
    // it's important here that we don't mutate the player
    // object but create a new one
    const updatedPlayer = _set(player, 'name', name)

    this.props.update(player, updatedPlayer)

    // Calling `toggleProperty` here has no effect here on the UI,
    // because `updatedPlayer` is now displayed. This call
    // just removes the reference to `player` and allows it to be GC'd
    this.props.toggleProperty('selected', player)
  }

  _onAddNewKeyDown = event => {
    if (event.keyCode === 13) {
      this.refs.addnew.blur()
    }
  }

  render() {
    const {
      team,
      deleteItem,
      update,
      move,
      connectDropTarget,
      toggleProperty } = this.props

    return connectDropTarget(

        Team {_get(team, 'name')}

          {_get(team, 'players').map((player, index) =>
            _get(team, 'selected').has(player) ?

                <input
                  ref="editplayer"
                  defaultValue={_get(player, 'name')}
                  placeholder="Edit player"
                  onBlur={event => this._editPlayer(player, event.target.value)}
                  onKeyDown={event => event.keyCode === 13 && this.refs.editplayer.blur()}
                />

            : <Item
                key={index}
                player={player}
                onMove={move}
              >
                {_get(player, 'name')}
                {' '}
                <button onClick={deleteItem.bind(null, player)}>delete</button>
                {' '}
                <button onClick={toggleProperty.bind(null, 'selected', player)}>Edit</button>
              </Item>
          )}

            <input
              ref="addnew"
              placeholder="Add new"
              onBlur={this._addPlayer}
              onKeyDown={this._onAddNewKeyDown}
            />

    )
  }
}

List.propTypes = {
  team: PropTypes.object.isRequired,
  addPlayer: PropTypes.func.isRequired,
  deleteItem: PropTypes.func.isRequired,
  update: PropTypes.func.isRequired,
  moveToList: PropTypes.func.isRequired,
  toggleProperty: PropTypes.func.isRequired,
}

// helpers to make this component work with ImmutableJS and plain objects

const isImmutable = obj => Immutable.Map.isMap(obj)
const _get = (obj, property) => isImmutable(obj) ? obj.get(property) : obj[property]
const _set = (obj, property, value) => isImmutable(obj) ? obj.set(property, value) : { ...obj, [property]: value}
<commit_msg>add comment<commit_after>import React, { Component, PropTypes } from 'react'
import { DropTarget } from 'react-dnd'
import Immutable from 'immutable'

import Item from './Item'

// This file implements a list component that accepts either a plain JS
// or `Immutable.Map` as a prop. Still searching for best ways to handle
// immutable data in React components, some thoughts here:
// https://gist.github.com/jlongster/028c83ed09d99c09983a

// You can drop to a list if it's empty
const target = {
  drop(targetProps, monitor) {
    const targetTeam = targetProps.team
    const sourceProps = monitor.getItem()
    const sourcePlayer = sourceProps.player

    const count = isImmutable(targetTeam)
      ? targetTeam.get('players').count()
      : targetTeam.players.length

    if (!count) {
      targetProps.moveToList(sourcePlayer, targetTeam)
    }
  }
}

@DropTarget('Item', target, (connect) => ({
  connectDropTarget: connect.dropTarget()
}))
export default class List extends Component {

  // abusing refs to keep the example simple and in one place

  _addPlayer = event => {
    const name = event.target.value
    if (name === '') return
    this.refs.addnew.value = ''
    this.refs.addnew.focus()
    this.props.addPlayer(name, this.props.team)
  }

  _editPlayer = (player, name) => {
    // it's important here that we don't mutate the player
    // object but create a new one
    const updatedPlayer = _set(player, 'name', name)

    this.props.update(player, updatedPlayer)

    // Calling `toggleProperty` here has no effect here on the UI,
    // because `updatedPlayer` is now displayed. This call
    // just removes the reference to `player` and allows it to be GC'd
    this.props.toggleProperty('selected', player)
  }

  _onAddNewKeyDown = event => {
    if (event.keyCode === 13) {
      this.refs.addnew.blur()
    }
  }

  render() {
    const {
      team,
      deleteItem,
      update,
      move,
      connectDropTarget,
      toggleProperty } = this.props

    return connectDropTarget(

        Team {_get(team, 'name')}

          {_get(team, 'players').map((player, index) =>
            _get(team, 'selected').has(player) ?

                <input
                  ref="editplayer"
                  defaultValue={_get(player, 'name')}
                  placeholder="Edit player"
                  onBlur={event => this._editPlayer(player, event.target.value)}
                  onKeyDown={event => event.keyCode === 13 && this.refs.editplayer.blur()}
                />

            : <Item
                key={index}
                player={player}
                onMove={move}
              >
                {_get(player, 'name')}
                {' '}
                <button onClick={deleteItem.bind(null, player)}>delete</button>
                {' '}
                <button onClick={toggleProperty.bind(null, 'selected', player)}>Edit</button>
              </Item>
          )}

            <input
              ref="addnew"
              placeholder="Add new"
              onBlur={this._addPlayer}
              onKeyDown={this._onAddNewKeyDown}
            />

    )
  }
}

List.propTypes = {
  team: PropTypes.object.isRequired,
  addPlayer: PropTypes.func.isRequired,
  deleteItem: PropTypes.func.isRequired,
  update: PropTypes.func.isRequired,
  moveToList: PropTypes.func.isRequired,
  toggleProperty: PropTypes.func.isRequired,
}

// helpers to make this component work with ImmutableJS and plain objects

const isImmutable = obj => Immutable.Map.isMap(obj)
const _get = (obj, property) => isImmutable(obj) ? obj.get(property) : obj[property]
const _set = (obj, property, value) => isImmutable(obj) ? obj.set(property, value) : { ...obj, [property]: value}
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import {createStyleSheet} from 'stylishly';
import MarkdownElement from './MarkdownElement';

export const styleSheet = createStyleSheet('MarkdownDocs', (theme) => {
  return {
    content: {
      '@raw pre': {
        margin: '25px 0',
        padding: '12px 18px',
        backgroundColor: '#fff',
        boxShadow: theme.shadows[4],
        borderRadius: 3,
      },
      '@raw code': {
        fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace',
        padding: '3px 6px',
        color: '#333',
        backgroundColor: '#fff',
      },
      '@raw pre > code': {
        padding: 0,
        fontSize: 14,
      },
    },
  };
});

export default class MarkdownDocs extends Component {

  static propTypes = {
    route: PropTypes.object,
  };

  static contextTypes = {
    styleManager: PropTypes.object.isRequired,
  };

  render() {
    const classes = this.context.styleManager.render(styleSheet);
    return (

        <MarkdownElement text={this.props.route.content} />

    );
  }
}
<commit_msg>Fix code block padding<commit_after>import React, {Component, PropTypes} from 'react';
import {createStyleSheet} from 'stylishly';
import MarkdownElement from './MarkdownElement';

export const styleSheet = createStyleSheet('MarkdownDocs', (theme) => {
  return {
    content: {
      '@raw pre': {
        margin: '25px 0',
        padding: '12px 18px',
        backgroundColor: '#fff',
        boxShadow: theme.shadows[4],
        borderRadius: 3,
        '@raw code': {
          padding: 0,
          fontSize: 14,
        },
      },
      '@raw code': {
        fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace',
        padding: '3px 6px',
        color: '#333',
        backgroundColor: '#fff',
      },
    },
  };
});

export default class MarkdownDocs extends Component {

  static propTypes = {
    route: PropTypes.object,
  };

  static contextTypes = {
    styleManager: PropTypes.object.isRequired,
  };

  render() {
    const classes = this.context.styleManager.render(styleSheet);
    return (

        <MarkdownElement text={this.props.route.content} />

    );
  }
}
<|endoftext|>


<commit_before>/*
 * jquery.drag-n-crop
 * https://github.com/fiszer/drag-n-crop
 *
 * Copyright (c) 2012 Lukasz Fiszer
 * Licensed under the MIT license.
 */

;(function ( $, window, document, undefined ) {

    $.widget( "fotomaton.drag2crop" , {

        options: {
            containmentClass: 'containment',
            overlayClass: 'overlay',
            containerActiveClass: 'dragging',
            position: { top: 0, left: 0 },
            centered: false,
            overlay: false
        },

        move: function ( position ) {

          if( !position ){
            throw new Error('position object must be provided');
          }

          if (position.left === undefined && position.top === undefined ) {
            throw new Error('position object must contain "left" or "top" props');
          }

          if( $.isNumeric(position.left) && this.axis === 'x'){

            var left = - position.left * this.offsetX;
            this.element.css('left', left);

          } else if( $.isNumeric(position.top) && this.axis === 'y'){

            var top = - position.top * this.offsetY;
            this.element.css('top', top);

          }
        },

        getPosition: function( position ) {

          return {
            left : ( - position.left / this.offsetX) || 0,
            top : (- position.top / this.offsetY) || 0
          };

        },

        //Setup widget (eg. element creation, apply theming
        // , bind events etc.)
        _create: function () {

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

            var dfd = this.element.imagesLoaded();
            var self = this;

            dfd.done( function( ){
              self._getDimensions.call(self);
              self._makeDraggable.call(self);
            } );

        },

        _getDimensions: function() {

          this.offsetX = this.element.width() - this.container.width();
          this.offsetY = this.element.height() - this.container.height();
          this.axis = this.element.width() / this.element.height() > 1 ? 'x' : 'y';

        },

        _makeDraggable : function () {

          var containement = this._insertContainment();
          var overlay      = this._insertOverlay();
          var axis         = this.axis;
          var position     = this.options.position;

          var draggable = this.draggable = this.element.draggable({
            axis: axis,
            containment: containement
          });

          draggable.bind('dragstart', $.proxy( function () {
            this.container.addClass( this.options.containerActiveClass );
          }, this) );

          draggable.bind('dragstop', $.proxy( function( event, ui ){
            this._dragStop( event , ui );
            this.container.removeClass( this.options.containerActiveClass );
          }, this) );

          if(this.options.overlay){
            draggable.bind('drag', $.proxy( function ( event, ui ) {
              this._adaptOverlay( ui );
            }, this) );
          }

          if(this.options.centered){
            position = {left: 0.5, top: 0.5};
          }

          if( position && ( position.top !== 0 || position.left !== 0)) {
            this.move(position);
          }

        },

        _dragStop: function( event, ui ) {

          this._trigger('dragged', event, this.getPosition(ui.position) );

        },

        _adaptOverlay: function( ui ) {

          if ( this.axis === 'x' ) {

            this.overlay.css('left', ui.position.left)
                        .css('border-left-width', -ui.position.left)
                        .css('right', -ui.position.left - this.offsetX)
                        .css('border-right-width', ui.position.left + this.offsetX);

          } else if ( this.axis === 'y' ){

            this.overlay.css('top', ui.position.top)
                        .css('border-top-width', -ui.position.top)
                        .css('bottom', -ui.position.top - this.offsetY )
                        .css('border-bottom-width', ui.position.top + this.offsetY );

          }

        },

        _insertContainment: function() {

          var top    = - this.offsetY;
          var bottom = - this.offsetY;
          var left   = - this.offsetX;
          var right  = - this.offsetX;

          var containment = $('<div/>').addClass(this.options.containmentClass)
                            .css('top',top).css('bottom', bottom)
                            .css('left',left).css('right',right)
                            .css('position','absolute');

          return this.containment = containment.insertBefore(this.element);

        },

        _insertOverlay: function(){

          var overlay = $('<div>').addClass(this.options.overlayClass);
          this.overlay = overlay.insertBefore(this.element);
          return this.overlay;
        }

    });

})( jQuery, window, document );
<commit_msg>More custom classes, event binders, automatic proportion check etc...<commit_after>/*
 * jquery.drag-n-crop
 * https://github.com/fiszer/drag-n-crop
 *
 * Copyright (c) 2013 Lukasz Fiszer
 * Licensed under the MIT license.
 */

;(function ( $, window, document, undefined ) {

    $.widget( "lukaszfiszer.dragncrop" , {

        options: {

            // Classes
            containmentClass: 'dragncrop-containment',
            containerActiveClass: 'dragncrop-dragging',
            noOverflowClass: 'dragncrop-no-overflow',
            horizontalClass: 'dragncrop-horizontal',
            verticalClass: 'dragncrop-vertical',

            // Initial position
            position: { x: 0, y: 0 },
            centered: false,

            // Overflow:
            overflow: true,

            // Overlay
            overlay: false,
            overlayClass: 'dragndrop-overlay'
        },

        move: function ( position ) {

          if( !position ){
            throw new Error('position object must be provided');
          }

          if (position.x === undefined && position.y === undefined ) {
            throw new Error('position object must contain "left" or "top" props');
          }

          if( $.isNumeric(position.x) && this.axis === 'x'){

            var left = - position.x * this.offsetX;
            this.element.css('left', left);

          } else if( $.isNumeric(position.y) && this.axis === 'y'){

            var top = - position.y * this.offsetY;
            this.element.css('top', top);

          }
        },

        _getPosition: function( ui ) {

          return {
            position : {
              x : ( -ui.position.left / this.offsetX) || null,
              y : ( -ui.position.top / this.offsetY) || null
            },
            offset : {
              x : ( -ui.position.left / this.containerWidth) || null,
              y : ( -ui.position.top / this.containerHeight) || null
            }
          };

        },

        //Setup widget (eg. element creation, apply theming
        // , bind events etc.)
        _create: function () {

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

            if( !this.options.overflow){
              $(this.container).addClass(this.options.noOverflowClass);
            }

            var dfd = this.element.imagesLoaded();
            var self = this;

            dfd.done( function( ){
              if(self._checkProportions()){
                self._getDimensions.call(self);
                self._makeDraggable.call(self);
              }
            } );

        },

        _checkProportions: function() {

          this.width = this.element.width();
          this.height = this.element.height();
          this.containerWidth = this.container.width();
          this.containerHeight = this.container.height();

          if (this.width > this.height) {
            $(this.container).addClass(this.options.horizontalClass);
            return true;
          } else if (this.width < this.height) {
            $(this.container).addClass(this.options.verticalClass);
            return true;
          }else{
            return false;
          }

        },

        _getDimensions: function() {

          this.offsetX = this.element.width() - this.container.width();
          this.offsetY = this.element.height() - this.container.height();
          this.axis = this.element.width() / this.element.height() > 1 ? 'x' : 'y';

        },

        _makeDraggable : function () {

          var axis         = this.axis;
          var position     = this.options.position;
          var containement = this._insertContainment();

          var draggable = this.draggable = this.element.draggable({
            axis: axis,
            containment: containement
          });

          draggable.bind('dragstart', $.proxy( function (event, ui) {
            this._dragStart( event , ui );
            this.container.addClass( this.options.containerActiveClass );
          }, this) );

          draggable.bind('drag', $.proxy( function( event, ui ){
            this._dragging( event , ui );
          }, this) );

          draggable.bind('dragstop', $.proxy( function( event, ui ){
            this._dragStop( event , ui );
            this.container.removeClass( this.options.containerActiveClass );
          }, this) );

          if(this.options.overlay){
            var overlay      = this._insertOverlay();
            draggable.bind('drag', $.proxy( function ( event, ui ) {
              this._adaptOverlay( ui );
            }, this) );
          }

          if(this.options.centered){
            position = {x: 0.5, y: 0.5};
          }

          if( position && ( position.x !== 0 || position.y !== 0)) {
            this.move(position);
          }

        },

        _dragStart: function( event, ui ) {
          this._trigger('start', event, this._getPosition(ui) );
        },

        _dragging: function( event, ui ) {
          this._trigger('drag', event, this._getPosition(ui) );
        },

        _dragStop: function( event, ui ) {
          this._trigger('stop', event, this._getPosition(ui) );
        },

        _adaptOverlay: function( ui ) {

          if ( this.axis === 'x' ) {

            this.overlay.css('left', ui.position.left)
                        .css('border-left-width', -ui.position.left)
                        .css('right', -ui.position.left - this.offsetX)
                        .css('border-right-width', ui.position.left + this.offsetX);

          } else if ( this.axis === 'y' ){

            this.overlay.css('top', ui.position.top)
                        .css('border-top-width', -ui.position.top)
                        .css('bottom', -ui.position.top - this.offsetY )
                        .css('border-bottom-width', ui.position.top + this.offsetY );

          }

        },

        _insertContainment: function() {

          var top    = - this.offsetY;
          var bottom = - this.offsetY;
          var left   = - this.offsetX;
          var right  = - this.offsetX;

          var containment = $('<div/>').addClass(this.options.containmentClass)
                            .css('top',top).css('bottom', bottom)
                            .css('left',left).css('right',right)
                            .css('position','absolute');

          return this.containment = containment.insertBefore(this.element);

        },

        _insertOverlay: function(){

          var overlay = $('<div>').addClass(this.options.overlayClass);
          this.overlay = overlay.insertBefore(this.element);
          return this.overlay;
        }

    });

})( jQuery, window, document );
<|endoftext|>


<commit_before>var url =				require('url');
var extend =			require('extend');
var parseIsoDuration =	require('parse-iso-duration');
var bluebird =			require('bluebird');
var request =			bluebird.promisify(require('request'));

var util = {
	errors:				require('./util/errors'),
	products:			require('./util/products'),
	locations:			require('./util/locations'),
	transports:			require('./util/transports'),
	dateTime:			require('./util/date-time')
};

var Client = module.exports = {

	// util
	_errors:		util.errors,
	_products:		util.products,
	_locations:		util.locations,
	_transports:	util.transports,
	_dateTime:		util.dateTime,

	endpoint:		'http://demo.hafas.de/openapi/vbb-proxy/',
	accessId:		null,

	init: function (accessId, endpoint) {
		if (!accessId) throw new Error('Missing `accessId`.');
		this.accessId = accessId;

		if (endpoint) this.endpoint = endpoint;

		return this;
	},

	_locationsDefaults: {
		results:		5,
		stations:		true,
		addresses:		true,
		pois:			true,
		products: {
			suburban:	true,
			subway:		true,
			tram:		true,
			bus:		true,
			ferry:		true,
			express:	false,
			regional:	true
		}
	},

	locations: function (query, options) {
		if (!query) throw new Error('Missing `query` parameter.');

		options = extend(true, {}, this._locationsDefaults, options || {});

		params = {
			input:			query,
			maxNo:			options.results,
			type: this._locations.createApiString({
				station:	options.stations,
				address:	options.addresses,
				poi:		options.pois
			}),
			products:		this._products.createApiNumber(options.products)
		};

		this._request('location.name', params, [this._locationsOnSuccess]);
	},

	_locationsOnSuccess: function (data) {
		var results = [];
		var i, length, loc, result;

		if (!data.StopLocation && !data.CoordLocation) return results;   // abort

		if (data.StopLocation)
			for (i = 0, length = data.StopLocation.length; i < length; i++) {
				loc = data.StopLocation[i];
				result = this._locations.parseApiLocation(loc);
				result.products = this._products.parseApiNumber(loc.products);
				results.push(result);
			}

		if (data.CoordLocation)
			for (i = 0, length = data.CoordLocation.length; i < length; i++) {
				results.push(this._locations.parseApiLocation(data.CoordLocation[i]));
			}

		console.log(results);
		return results;
	},

	_routesDefaults: {
		from:				null,
		fromLatitude:		null,
		fromLongitude:		null,
		to:					null,
		toLatitude:			null,
		toLongitude:		null,
		via:				null,

		results:			4,
		when:				null,
		changes:			null,
		changeTimeFactor:	1,
		products: {
			suburban:		true,
			subway:			true,
			tram:			true,
			bus:			true,
			ferry:			true,
			express:		true,
			regional:		true
		}
	},

	routes: function (options) {
		options = extend(true, {}, this._routesDefaults, options || {});

		if (!options.when) options.when = new Date();   // now
		params = {
			changeTimePercent:	Math.round(options.changeTimeFactor * 100),
			date:				this._dateTime.createApiDate(options.when),
			time:				this._dateTime.createApiTime(options.when),
			numB:				0,
			numF:				options.results > 6 ? 6 : options.results,
			products:			this._products.createApiNumber(options.products)
		};
		if (typeof options.changes === 'number') params.maxChange = options.changes;
		if (options.via) params.via = options.via;

		if (options.from)
			params.originId = this._locations.createApiId(options.from);
		else if (options.fromLatitude && options.fromLongitude) {
			params.originCoordLat = options.fromLatitude;
			params.originCoordLong = options.fromLongitude;
		} else
			throw new Error('Neither `from` nor `fromLatitude` & `fromLongitude` passed.');

		if (options.to)
			params.destId = this._locations.createApiId(options.to);
		else if (options.toLatitude && options.toLongitude) {
			params.destCoordLat = options.toLatitude;
			params.destCoordLong = options.toLongitude;
		} else
			throw new Error('Neither `to` nor `toLatitude` & `toLongitude` passed.');

		return this._request('trip', params, [this._routesOnSuccess]);
	},

	_routesOnSuccess: function (data) {
		var results = [];
		var i, tripsLength, trip, result;
		var j, legsLength, leg, part;

		if (!data.Trip) return results;   // abort

		for (i = 0, tripsLength = data.Trip.length; i < tripsLength; i++) {
			trip = data.Trip[i];

			result = {
				duration:	parseIsoDuration(trip.duration.replace(/^[R]T/, 'PT')),
				parts:		[]
			};

			for (j = 0, legsLength = trip.LegList.Leg.length; j < legsLength; j++ ) {
				leg = trip.LegList.Leg[j];

				part = {
					from:		this._locations.parseApiLocation(leg.Origin),
					to:			this._locations.parseApiLocation(leg.Destination),
					transport:	(this._transports[leg.type] || this._transports.unknown).type,
				};
				if (part.transport === 'public') {
					part.type = (this._products[leg.Product.catIn] || this._products.unknown).type;
					part.line = leg.Product.line;
					part.direction = leg.direction;
				}
				part.from.when = this._dateTime.parseApiDateTime(leg.Origin.date, leg.Origin.time);
				part.to.when = this._dateTime.parseApiDateTime(leg.Destination.date, leg.Destination.time);
				if (leg.Notes) part.notes = this._locations.parseApiNotes(leg.Notes);

				result.parts.push(part);
			}

			// todo: tickets and their prices
			// todo: `leg.Messages`? are they actually being used?
			// todo: `leg.ServiceDays`?
			results.push(result);
		}

		console.log(results);
		return results;
	},

	_departuresDefaults: {
		results:		10,
		when:			null,
		direction:		null,
		products: {
			suburban:	true,
			subway:		true,
			tram:		true,
			bus:		true,
			ferry:		true,
			express:	true,
			regional:	true
		}
	},

	departures: function (station, options) {
		if (!station) throw new Error('Missing `station` parameter.');

		options = extend(true, {}, this._departuresDefaults, options || {});
		if (!options.when) options.when = new Date();   // now

		params = {
			id:				this._locations.createApiId(station),
			maxJourneys:	options.results,
			date:			this._dateTime.createApiDate(options.when),
			time:			this._dateTime.createApiTime(options.when),
			products:		this._products.createApiNumber(options.products)
		};
		if (options.direction) params.direction = this._locations.createApiId(options.direction);

		return this._request('departureBoard', params, [this._departuresOnSuccess]);
	},

	_departuresOnSuccess: function (data) {
		var results = [];
		var i, length, dep, result;

		if (!data.Departure) return results;   // abort

		for (i = 0, length = data.Departure.length; i < length; i++) {
			dep = data.Departure[i];
			result = {
				stop:		this._locations.parseApiId(dep.stopExtId),
				type:		(this._products[dep.Product.catIn] || this._products.unknown).type,
				line:		dep.Product.line,
				direction:	dep.direction,
				when:		this._dateTime.parseApiDateTime(dep.date, dep.time)
			};
			if (dep.rtDate && dep.rtTime)
				result.realtime = this._dateTime.parseApiDateTime(dep.rtDate, dep.rtTime);
			results.push(result);
		}

		console.log(results);
		return results;
	},

	_request: function (service, params, handlers) {
		var target = url.parse(this.endpoint, true);
		target.pathname = path.join(target.pathname, service);

		target.query.format = 'json';
		target.query.accessId = this.accessId;
		extend(target.query, params);
		for (var property in params) {
			target.query[property] = params[property];
		}

		// todo: make this shorter, using the bluebird api
		var promise, i;
		promise = request(url.format(target)).bind(this)
		.then(this._requestOnSuccess);
		for (i = 0; i < handlers.length; i++) {
			promise = promise.then(handlers[i]);
		}
		return promise;
	},

	_requestOnSuccess: function (res) {
		res = res[0];

		try {
			data = JSON.parse(res.body);
		} catch (e) {
			if (res.statusCode < 200 || res.statusCode >= 300)
				throw new this._errors.ConnectionError(res.statusCode, res.statusMessage, res.request.uri, res.request.method);
			else throw new Error('Could not parse response JSON');
		}
		if (data.errorCode) throw this._errors.apiServerError(res, data);

		return data;
	}

};
<commit_msg>small fixes<commit_after>var url =				require('url');
var path =				require('path');
var extend =			require('extend');
var parseIsoDuration =	require('parse-iso-duration');
var bluebird =			require('bluebird');
var request =			bluebird.promisify(require('request'));

var util = {
	errors:				require('./util/errors'),
	products:			require('./util/products'),
	locations:			require('./util/locations'),
	transports:			require('./util/transports'),
	dateTime:			require('./util/date-time')
};

var Client = module.exports = {

	// util
	_errors:		util.errors,
	_products:		util.products,
	_locations:		util.locations,
	_transports:	util.transports,
	_dateTime:		util.dateTime,

	endpoint:		'http://demo.hafas.de/openapi/vbb-proxy/',
	accessId:		null,

	init: function (accessId, endpoint) {
		if (!accessId) throw new Error('Missing `accessId`.');
		this.accessId = accessId;

		if (endpoint) this.endpoint = endpoint;

		return this;
	},

	_locationsDefaults: {
		results:		5,
		stations:		true,
		addresses:		true,
		pois:			true,
		products: {
			suburban:	true,
			subway:		true,
			tram:		true,
			bus:		true,
			ferry:		true,
			express:	false,
			regional:	true
		}
	},

	locations: function (query, options) {
		if (!query) throw new Error('Missing `query` parameter.');

		options = extend(true, {}, this._locationsDefaults, options || {});

		params = {
			input:			query,
			maxNo:			options.results,
			type: this._locations.createApiString({
				station:	options.stations,
				address:	options.addresses,
				poi:		options.pois
			}),
			products:		this._products.createApiNumber(options.products)
		};

		return this._request('location.name', params, [this._locationsOnSuccess]);
	},

	_locationsOnSuccess: function (data) {
		var results = [];
		var i, length, loc, result;

		if (!data.StopLocation && !data.CoordLocation) return results;   // abort

		if (data.StopLocation)
			for (i = 0, length = data.StopLocation.length; i < length; i++) {
				loc = data.StopLocation[i];
				result = this._locations.parseApiLocation(loc);
				result.products = this._products.parseApiNumber(loc.products);
				results.push(result);
			}

		if (data.CoordLocation)
			for (i = 0, length = data.CoordLocation.length; i < length; i++) {
				results.push(this._locations.parseApiLocation(data.CoordLocation[i]));
			}

		return results;
	},

	_routesDefaults: {
		from:				null,
		fromLatitude:		null,
		fromLongitude:		null,
		to:					null,
		toLatitude:			null,
		toLongitude:		null,
		via:				null,

		results:			4,
		when:				null,
		changes:			null,
		changeTimeFactor:	1,
		products: {
			suburban:		true,
			subway:			true,
			tram:			true,
			bus:			true,
			ferry:			true,
			express:		true,
			regional:		true
		}
	},

	routes: function (options) {
		options = extend(true, {}, this._routesDefaults, options || {});

		if (!options.when) options.when = new Date();   // now
		params = {
			changeTimePercent:	Math.round(options.changeTimeFactor * 100),
			date:				this._dateTime.createApiDate(options.when),
			time:				this._dateTime.createApiTime(options.when),
			numB:				0,
			numF:				options.results > 6 ? 6 : options.results,
			products:			this._products.createApiNumber(options.products)
		};
		if (typeof options.changes === 'number') params.maxChange = options.changes;
		if (options.via) params.via = options.via;

		if (options.from)
			params.originId = this._locations.createApiId(options.from);
		else if (options.fromLatitude && options.fromLongitude) {
			params.originCoordLat = options.fromLatitude;
			params.originCoordLong = options.fromLongitude;
		} else
			throw new Error('Neither `from` nor `fromLatitude` & `fromLongitude` passed.');

		if (options.to)
			params.destId = this._locations.createApiId(options.to);
		else if (options.toLatitude && options.toLongitude) {
			params.destCoordLat = options.toLatitude;
			params.destCoordLong = options.toLongitude;
		} else
			throw new Error('Neither `to` nor `toLatitude` & `toLongitude` passed.');

		return this._request('trip', params, [this._routesOnSuccess]);
	},

	_routesOnSuccess: function (data) {
		var results = [];
		var i, tripsLength, trip, result;
		var j, legsLength, leg, part;

		if (!data.Trip) return results;   // abort

		for (i = 0, tripsLength = data.Trip.length; i < tripsLength; i++) {
			trip = data.Trip[i];

			result = {
				duration:	parseIsoDuration(trip.duration.replace(/^[R]T/, 'PT')),
				parts:		[]
			};

			for (j = 0, legsLength = trip.LegList.Leg.length; j < legsLength; j++ ) {
				leg = trip.LegList.Leg[j];

				part = {
					from:		this._locations.parseApiLocation(leg.Origin),
					to:			this._locations.parseApiLocation(leg.Destination),
					transport:	(this._transports[leg.type] || this._transports.unknown).type,
				};
				if (part.transport === 'public') {
					part.type = (this._products[leg.Product.catIn] || this._products.unknown).type;
					part.line = leg.Product.line;
					part.direction = leg.direction;
				}
				part.from.when = this._dateTime.parseApiDateTime(leg.Origin.date, leg.Origin.time);
				part.to.when = this._dateTime.parseApiDateTime(leg.Destination.date, leg.Destination.time);
				if (leg.Notes) part.notes = this._locations.parseApiNotes(leg.Notes);

				result.parts.push(part);
			}

			// todo: tickets and their prices
			// todo: `leg.Messages`? are they actually being used?
			// todo: `leg.ServiceDays`?
			results.push(result);
		}

		return results;
	},

	_departuresDefaults: {
		results:		10,
		when:			null,
		direction:		null,
		products: {
			suburban:	true,
			subway:		true,
			tram:		true,
			bus:		true,
			ferry:		true,
			express:	true,
			regional:	true
		}
	},

	departures: function (station, options) {
		if (!station) throw new Error('Missing `station` parameter.');

		options = extend(true, {}, this._departuresDefaults, options || {});
		if (!options.when) options.when = new Date();   // now

		params = {
			id:				this._locations.createApiId(station),
			maxJourneys:	options.results,
			date:			this._dateTime.createApiDate(options.when),
			time:			this._dateTime.createApiTime(options.when),
			products:		this._products.createApiNumber(options.products)
		};
		if (options.direction) params.direction = this._locations.createApiId(options.direction);

		return this._request('departureBoard', params, [this._departuresOnSuccess]);
	},

	_departuresOnSuccess: function (data) {
		var results = [];
		var i, length, dep, result;

		if (!data.Departure) return results;   // abort

		for (i = 0, length = data.Departure.length; i < length; i++) {
			dep = data.Departure[i];
			result = {
				stop:		this._locations.parseApiId(dep.stopExtId),
				type:		(this._products[dep.Product.catIn] || this._products.unknown).type,
				line:		dep.Product.line,
				direction:	dep.direction,
				when:		this._dateTime.parseApiDateTime(dep.date, dep.time)
			};
			if (dep.rtDate && dep.rtTime)
				result.realtime = this._dateTime.parseApiDateTime(dep.rtDate, dep.rtTime);
			results.push(result);
		}

		return results;
	},

	_request: function (service, params, handlers) {
		var target = url.parse(this.endpoint, true);
		target.pathname = path.join(target.pathname, service);

		target.query.format = 'json';
		target.query.accessId = this.accessId;
		extend(target.query, params);
		for (var property in params) {
			target.query[property] = params[property];
		}

		// todo: make this shorter, using the bluebird api
		var promise, i;
		promise = request(url.format(target)).bind(this)
		.then(this._requestOnSuccess);
		for (i = 0; i < handlers.length; i++) {
			promise = promise.then(handlers[i]);
		}
		return promise;
	},

	_requestOnSuccess: function (res) {
		res = res[0];

		try {
			data = JSON.parse(res.body);
		} catch (e) {
			if (res.statusCode < 200 || res.statusCode >= 300)
				throw new this._errors.ConnectionError(res.statusCode, res.statusMessage, res.request.uri, res.request.method);
			else throw new Error('Could not parse response JSON');
		}
		if (data.errorCode) throw this._errors.apiServerError(res, data);

		return data;
	}

};
<|endoftext|>


<commit_before>/*jshint strict: false */
/*globals $, analytics, jsbin, documentTitle, $document, throttle, editors*/

var saving = {
  todo: {
    html: false,
    css: false,
    javascript: false
  },
  _inprogress: false,
  inprogress: function (inprogress) {
    if (typeof inprogress === 'undefined') {
      return saving._inprogress;
    }

    saving._inprogress = inprogress;
    if (inprogress === false) {
      var panels = ['html','css','javascript'];

      var save = function () {
        var todo = panels.pop();
        if (todo && saving.todo[todo]) {
          saving._inprogress = true;
          updateCode(todo, save);
          saving.todo[todo] = false;
        } else if (todo) {
          save();
        }
      };

      save();
    }
  }
};

// to allow for download button to be introduced via beta feature
$('a.save').click(function (event) {
  event.preventDefault();

  analytics.milestone();
  // if save is disabled, hitting save will trigger a reload
  var ajax = true;
  if (jsbin.saveDisabled === true) {
    ajax = false;
  }
  saveCode('save', ajax);

  return false;
});

var $shareLinks = $('#share .link');
var $panelCheckboxes = $('#sharemenu #sharepanels input');

// TODO remove split when live
var split = $('#sharemenu .share-split').length;

// TODO candidate for removal
function updateSavedState() {
  'use strict';
  if (split) {
    return;
  }

  var mapping = {
    live: 'output',
    javascript: 'js',
    css: 'css',
    html: 'html',
    console: 'console'
  };

  var withRevision = true;

  var query = $panelCheckboxes.filter(':checked').map(function () {
    return mapping[this.getAttribute('data-panel')];
  }).get().join(',');
  $shareLinks.each(function () {
    var path = this.getAttribute('data-path');
    var url = jsbin.getURL({ withRevision: withRevision }) + path + (query && this.id !== 'livepreview' ? '?' + query : ''),
        nodeName = this.nodeName;
    var hash = panels.getHighlightLines();

    if (hash) {
      hash = '#' + hash;
    }

    if (nodeName === 'A') {
      this.href = url;
    } else if (nodeName === 'INPUT') {
      this.value = url;
      if (path === '/edit') {
        this.value += hash;
      }
    } else if (nodeName === 'TEXTAREA') {
      this.value = ('' + documentTitle + '<' + 'script src="' + jsbin.static + '/js/embed.js"><' + '/script>').replace(/<>"&/g, function (m) {
          return {
            '<': '<',
            '>': '>',
            '"': '"',
            '&': '&'
          }[m];
        });
    }
  });
}

$('#sharemenu').bind('open', updateSavedState);
$('#sharebintype input[type=radio]').on('click', function () {
  if (this.value === 'snapshot') {
    jsbin.state.checksum = false;
    saveChecksum = false;
  }
  updateSavedState();
});

$document.on('saved', function () {
  updateSavedState();

  $('#sharebintype input[type=radio][value="realtime"]').prop('checked', true);

  $shareLinks.closest('.menu').removeClass('hidden');

  $('#jsbinurl').attr('href', jsbin.getURL()).removeClass('hidden');
  $('#clone').removeClass('hidden');
});

var saveChecksum = jsbin.state.checksum || store.sessionStorage.getItem('checksum') || false;

// store it back on state
jsbin.state.checksum = saveChecksum;

if (saveChecksum) {
  // remove the disabled class, but also remove the cancelling event handlers
  $('#share div.disabled').removeClass('disabled').unbind('click mousedown mouseup');
} else {
  $('#share div.disabled').one('click', function (event) {
    event.preventDefault();
    $('a.save').click();
  });
}

$document.one('saved', function () {
  $('#share div.disabled').removeClass('disabled').unbind('click mousedown mouseup');
});

function onSaveError(jqXHR, panelId) {
  if (jqXHR.status === 413) {
    // Hijack the tip label to show an error message.
    $('#tip p').html('Sorry this bin is too large for us to save');
    $(document.documentElement).addClass('showtip');
  } else if (jqXHR.status === 403) {
    $document.trigger('tip', {
      type: 'error',
      content: 'I think there\'s something wrong with your session and I\'m unable to save. Refresh to fix this, you will not lose your code.'
    });
  } else if (panelId) {
    if (panelId) { savingLabels[panelId].text('Saving...').animate({ opacity: 1 }, 100); }
    window._console.error({message: 'Warning: Something went wrong while saving. Your most recent work is not saved.'});
  }
}

// only start live saving it they're allowed to (whereas save is disabled if they're following)
if (!jsbin.saveDisabled) {
  $('.code.panel .label .name').append('Saved');

  var savingLabels = {
    html: $('.panel.html .name span'),
    javascript: $('.panel.javascript .name span'),
    css: $('.panel.css .name span')
  };

  $document.bind('jsbinReady', function () {
    jsbin.panels.allEditors(function (panel) {
      panel.on('processor', function () {
        // if the url doesn't match the root - i.e. they've actually saved something then save on processor change
        if (jsbin.root !== jsbin.getURL()) {
          $document.trigger('codeChange', [{ panelId: panel.id }]);
        }
      });
    });

    $document.bind('codeChange', function (event, data) {
      // savingLabels[data.panelId].text('Saving');
      if (savingLabels[data.panelId]) {
        savingLabels[data.panelId].css({ 'opacity': 0 }).stop(true, true);
      }
    });

    $document.bind('saveComplete', throttle(function (event, data) {
      // show saved, then revert out animation
      savingLabels[data.panelId]
        .text('Saved')
        .stop(true, true)
        .animate({ opacity: 1 }, 100)
        .delay(1200)
        .animate({ opacity: 0 }, 500);
    }, 500));

    $document.bind('codeChange', throttle(function (event, data) {
      if (!data.panelId) {
        return;
      }

      if (jsbin.state.deleted) {
        return;
      }

      var panelId = data.panelId;

      jsbin.panels.savecontent();

      if (saving.inprogress()) {
        // queue up the request and wait
        saving.todo[panelId] = true;
        return;
      }

      saving.inprogress(true);

      // We force a full save if there's no checksum OR if there's no bin code/url
      if (!saveChecksum || !jsbin.state.code) {
        // create the bin and when the response comes back update the url
        saveCode('save', true);
      } else {
        updateCode(panelId);
      }
    }, 250));
  });
} else {
  $document.one('jsbinReady', function () {
    'use strict';
    var shown = false;
    if (!jsbin.embed && !jsbin.sandbox) {
      $document.on('codeChange.live', function (event, data) {
        if (!data.onload && !shown && data.origin !== 'setValue') {
          shown = true;
          var ismac = navigator.userAgent.indexOf(' Mac ') !== -1;
          var cmd = ismac ? '⌘' : 'ctrl';
          var shift = ismac ? '⇧' : 'shift';
          var plus = ismac ? '' : '+';

          $document.trigger('tip', {
            type: 'notification',
            content: 'You\'re currently viewing someone else\'s live stream, but you can clone your own copy (' + cmd + plus + shift + plus + 'S) at any time to save your edits'
          });
        }
      });
    }
  });
}

function compressKeys(keys, obj) {
  obj.compressed = keys;
  keys.split(',').forEach(function (key) {
    obj[key] = LZString.compressToUTF16(obj[key]);
  });
}

function updateCode(panelId, callback) {
  var panelSettings = {};

  if (jsbin.state.processors) {
    panelSettings.processors = jsbin.state.processors;
  }

  var data = {
    code: jsbin.state.code,
    revision: jsbin.state.revision,
    method: 'update',
    panel: panelId,
    content: editors[panelId].getCode(),
    checksum: saveChecksum,
    settings: JSON.stringify(panelSettings),
  };

  if (jsbin.settings.useCompression) {
    compressKeys('content', data);
  }

  var update = function(){
    $.ajax({
      url: jsbin.getURL({ withRevision: true }) + '/save',
      data: data,
      type: 'post',
      dataType: 'json',
      headers: {'Accept': 'application/json'},
      success: function (data) {
        $document.trigger('saveComplete', { panelId: panelId });
        if (data.error) {
          saveCode('save', true, function () {
            // savedAlready = data.checksum;
          });
        } else {
          jsbin.state.latest = true;
        }
      },
      error: function (jqXHR) {
        onSaveError(jqXHR, panelId);
      },
      complete: function () {
        saving.inprogress(false);
        if (callback) { callback(); }
      }
    });
  };

  update();
}

$('a.clone').click(clone);
$('#tip').delegate('a.clone', 'click', clone);

function clone(event) {
  event.preventDefault();

  // save our panel layout - assumes our user is happy with this layout
  jsbin.panels.save();
  analytics.clone();

  var $form = setupform('save,new');
  $form.submit();

  return false;
}

function setupform(method) {
var $form = $('form#saveform').empty()
    .append('<input type="hidden" name="javascript" />')
    .append('<input type="hidden" name="html" />')
    .append('<input type="hidden" name="css" />')
    .append('<input type="hidden" name="method" />')
    .append('<input type="hidden" name="_csrf" value="' + jsbin.state.token + '" />')
    .append('<input type="hidden" name="settings" />')
    .append('<input type="hidden" name="checksum" />');

  var settings = {};

  if (jsbin.state.processors) {
    settings.processors = jsbin.state.processors;
  }

  // this prevents new revisions forking off the welcome bin
  // because it's looking silly!
  if (jsbin.state.code === 'welcome') {
    $form.attr('action', '/save');
  }

  $form.find('input[name=settings]').val(JSON.stringify(settings));
  $form.find('input[name=javascript]').val(editors.javascript.getCode());
  $form.find('input[name=css]').val(editors.css.getCode());
  $form.find('input[name=html]').val(editors.html.getCode());
  $form.find('input[name=method]').val(method);
  $form.find('input[name=checksum]').val(jsbin.state.checksum);

  return $form;
}

function pad(n){
  return n<10 ? '0'+n : n;
}

function ISODateString(d){
  return d.getFullYear()+'-'
    + pad(d.getMonth()+1)+'-'
    + pad(d.getDate())+'T'
    + pad(d.getHours())+':'
    + pad(d.getMinutes())+':'
    + pad(d.getSeconds())+'Z';
}

function saveCode(method, ajax, ajaxCallback) {
  // create form and post to it
  var $form = setupform(method);
  // save our panel layout - assumes our user is happy with this layout
  jsbin.panels.save();
  jsbin.panels.saveOnExit = true;

  var data = $form.serializeArray().reduce(function(obj, data) {
    obj[data.name] = data.value;
    return obj;
  }, {});

  data.url = $.cookie('new-bin-name');

  if (jsbin.settings.useCompression) {
    compressKeys('html,css,javascript', data);
  }

  var save = function(){
    if (ajax) {
      $.ajax({
        url: $form.attr('action'),
        data: data,
        dataType: 'json',
        type: 'post',
        headers: {'Accept': 'application/json'},
        success: function (data) {
          if (ajaxCallback) {
            ajaxCallback(data);
          }

          store.sessionStorage.setItem('checksum', data.checksum);
          saveChecksum = data.checksum;

          jsbin.state.checksum = saveChecksum;
          jsbin.state.code = data.code;
          jsbin.state.revision = data.revision;
          jsbin.state.latest = true; // this is never not true...end of conversation!
          jsbin.state.metadata = { name: jsbin.user.name };
          $form.attr('action', jsbin.getURL({ withRevision: true }) + '/save');

          if (window.history && window.history.pushState) {
            // updateURL(edit);
            var hash = panels.getHighlightLines();
            if (hash) {hash = '#' + hash;}
            // If split is truthy (> 0) then we are using the revisonless feature
            // this is temporary until we release the feature!
            window.history.pushState(null, '', jsbin.getURL({withRevision: !split}) + '/edit' + hash);
            store.sessionStorage.setItem('url', jsbin.getURL({withRevision: !split}));
          } else {
            window.location.hash = data.edit;
          }

          $document.trigger('saved');
        },
        error: function (jqXHR) {
          onSaveError(jqXHR, null);
        },
        complete: function () {
          saving.inprogress(false);
        }
      });
    } else {
      $form.submit();
    }
  };

  if($.cookie('new-bin-name') || jsbin.state.revision !== undefined){
    save();
    $.removeCookie('new-bin-name');
  }else{
    $document.trigger('tip', {
      type: 'notication',
      content: 'The name of bin is not set. <input type="button" id="set-name" value="Set name">
',
      callback: function(){

        console.log($('#set-name'));
        $('#set-name').click(function(event){
          vex.dialog.prompt({
            message: 'What is name of new bin?',
            placeholder: 'Name of bin',
            className: 'vex-theme-os',
            callback: function(value) {
              $.cookie('new-bin-name', value);
              $('a.dismiss').trigger('click');
            }
          });
        });

      }
    });
  }
};
<commit_msg>Update minor<commit_after>/*jshint strict: false */
/*globals $, analytics, jsbin, documentTitle, $document, throttle, editors*/

var saving = {
  todo: {
    html: false,
    css: false,
    javascript: false
  },
  _inprogress: false,
  inprogress: function (inprogress) {
    if (typeof inprogress === 'undefined') {
      return saving._inprogress;
    }

    saving._inprogress = inprogress;
    if (inprogress === false) {
      var panels = ['html','css','javascript'];

      var save = function () {
        var todo = panels.pop();
        if (todo && saving.todo[todo]) {
          saving._inprogress = true;
          updateCode(todo, save);
          saving.todo[todo] = false;
        } else if (todo) {
          save();
        }
      };

      save();
    }
  }
};

// to allow for download button to be introduced via beta feature
$('a.save').click(function (event) {
  event.preventDefault();

  analytics.milestone();
  // if save is disabled, hitting save will trigger a reload
  var ajax = true;
  if (jsbin.saveDisabled === true) {
    ajax = false;
  }
  saveCode('save', ajax);

  return false;
});

var $shareLinks = $('#share .link');
var $panelCheckboxes = $('#sharemenu #sharepanels input');

// TODO remove split when live
var split = $('#sharemenu .share-split').length;

// TODO candidate for removal
function updateSavedState() {
  'use strict';
  if (split) {
    return;
  }

  var mapping = {
    live: 'output',
    javascript: 'js',
    css: 'css',
    html: 'html',
    console: 'console'
  };

  var withRevision = true;

  var query = $panelCheckboxes.filter(':checked').map(function () {
    return mapping[this.getAttribute('data-panel')];
  }).get().join(',');
  $shareLinks.each(function () {
    var path = this.getAttribute('data-path');
    var url = jsbin.getURL({ withRevision: withRevision }) + path + (query && this.id !== 'livepreview' ? '?' + query : ''),
        nodeName = this.nodeName;
    var hash = panels.getHighlightLines();

    if (hash) {
      hash = '#' + hash;
    }

    if (nodeName === 'A') {
      this.href = url;
    } else if (nodeName === 'INPUT') {
      this.value = url;
      if (path === '/edit') {
        this.value += hash;
      }
    } else if (nodeName === 'TEXTAREA') {
      this.value = ('' + documentTitle + '<' + 'script src="' + jsbin.static + '/js/embed.js"><' + '/script>').replace(/<>"&/g, function (m) {
          return {
            '<': '<',
            '>': '>',
            '"': '"',
            '&': '&'
          }[m];
        });
    }
  });
}

$('#sharemenu').bind('open', updateSavedState);
$('#sharebintype input[type=radio]').on('click', function () {
  if (this.value === 'snapshot') {
    jsbin.state.checksum = false;
    saveChecksum = false;
  }
  updateSavedState();
});

$document.on('saved', function () {
  updateSavedState();

  $('#sharebintype input[type=radio][value="realtime"]').prop('checked', true);

  $shareLinks.closest('.menu').removeClass('hidden');

  $('#jsbinurl').attr('href', jsbin.getURL()).removeClass('hidden');
  $('#clone').removeClass('hidden');
});

var saveChecksum = jsbin.state.checksum || store.sessionStorage.getItem('checksum') || false;

// store it back on state
jsbin.state.checksum = saveChecksum;

if (saveChecksum) {
  // remove the disabled class, but also remove the cancelling event handlers
  $('#share div.disabled').removeClass('disabled').unbind('click mousedown mouseup');
} else {
  $('#share div.disabled').one('click', function (event) {
    event.preventDefault();
    $('a.save').click();
  });
}

$document.one('saved', function () {
  $('#share div.disabled').removeClass('disabled').unbind('click mousedown mouseup');
});

function onSaveError(jqXHR, panelId) {
  if (jqXHR.status === 413) {
    // Hijack the tip label to show an error message.
    $('#tip p').html('Sorry this bin is too large for us to save');
    $(document.documentElement).addClass('showtip');
  } else if (jqXHR.status === 403) {
    $document.trigger('tip', {
      type: 'error',
      content: 'I think there\'s something wrong with your session and I\'m unable to save. Refresh to fix this, you will not lose your code.'
    });
  } else if (panelId) {
    if (panelId) { savingLabels[panelId].text('Saving...').animate({ opacity: 1 }, 100); }
    window._console.error({message: 'Warning: Something went wrong while saving. Your most recent work is not saved.'});
  }
}

// only start live saving it they're allowed to (whereas save is disabled if they're following)
if (!jsbin.saveDisabled) {
  $('.code.panel .label .name').append('Saved');

  var savingLabels = {
    html: $('.panel.html .name span'),
    javascript: $('.panel.javascript .name span'),
    css: $('.panel.css .name span')
  };

  $document.bind('jsbinReady', function () {
    jsbin.panels.allEditors(function (panel) {
      panel.on('processor', function () {
        // if the url doesn't match the root - i.e. they've actually saved something then save on processor change
        if (jsbin.root !== jsbin.getURL()) {
          $document.trigger('codeChange', [{ panelId: panel.id }]);
        }
      });
    });

    $document.bind('codeChange', function (event, data) {
      // savingLabels[data.panelId].text('Saving');
      if (savingLabels[data.panelId]) {
        savingLabels[data.panelId].css({ 'opacity': 0 }).stop(true, true);
      }
    });

    $document.bind('saveComplete', throttle(function (event, data) {
      // show saved, then revert out animation
      savingLabels[data.panelId]
        .text('Saved')
        .stop(true, true)
        .animate({ opacity: 1 }, 100)
        .delay(1200)
        .animate({ opacity: 0 }, 500);
    }, 500));

    $document.bind('codeChange', throttle(function (event, data) {
      if (!data.panelId) {
        return;
      }

      if (jsbin.state.deleted) {
        return;
      }

      var panelId = data.panelId;

      jsbin.panels.savecontent();

      if (saving.inprogress()) {
        // queue up the request and wait
        saving.todo[panelId] = true;
        return;
      }

      saving.inprogress(true);

      // We force a full save if there's no checksum OR if there's no bin code/url
      if (!saveChecksum || !jsbin.state.code) {
        // create the bin and when the response comes back update the url
        saveCode('save', true);
      } else {
        updateCode(panelId);
      }
    }, 250));
  });
} else {
  $document.one('jsbinReady', function () {
    'use strict';
    var shown = false;
    if (!jsbin.embed && !jsbin.sandbox) {
      $document.on('codeChange.live', function (event, data) {
        if (!data.onload && !shown && data.origin !== 'setValue') {
          shown = true;
          var ismac = navigator.userAgent.indexOf(' Mac ') !== -1;
          var cmd = ismac ? '⌘' : 'ctrl';
          var shift = ismac ? '⇧' : 'shift';
          var plus = ismac ? '' : '+';

          $document.trigger('tip', {
            type: 'notification',
            content: 'You\'re currently viewing someone else\'s live stream, but you can clone your own copy (' + cmd + plus + shift + plus + 'S) at any time to save your edits'
          });
        }
      });
    }
  });
}

function compressKeys(keys, obj) {
  obj.compressed = keys;
  keys.split(',').forEach(function (key) {
    obj[key] = LZString.compressToUTF16(obj[key]);
  });
}

function updateCode(panelId, callback) {
  var panelSettings = {};

  if (jsbin.state.processors) {
    panelSettings.processors = jsbin.state.processors;
  }

  var data = {
    code: jsbin.state.code,
    revision: jsbin.state.revision,
    method: 'update',
    panel: panelId,
    content: editors[panelId].getCode(),
    checksum: saveChecksum,
    settings: JSON.stringify(panelSettings),
  };

  if (jsbin.settings.useCompression) {
    compressKeys('content', data);
  }

  var update = function(){
    $.ajax({
      url: jsbin.getURL({ withRevision: true }) + '/save',
      data: data,
      type: 'post',
      dataType: 'json',
      headers: {'Accept': 'application/json'},
      success: function (data) {
        $document.trigger('saveComplete', { panelId: panelId });
        if (data.error) {
          saveCode('save', true, function () {
            // savedAlready = data.checksum;
          });
        } else {
          jsbin.state.latest = true;
        }
      },
      error: function (jqXHR) {
        onSaveError(jqXHR, panelId);
      },
      complete: function () {
        saving.inprogress(false);
        if (callback) { callback(); }
      }
    });
  };

  update();
}

$('a.clone').click(clone);
$('#tip').delegate('a.clone', 'click', clone);

function clone(event) {
  event.preventDefault();

  // save our panel layout - assumes our user is happy with this layout
  jsbin.panels.save();
  analytics.clone();

  var $form = setupform('save,new');
  $form.submit();

  return false;
}

function setupform(method) {
var $form = $('form#saveform').empty()
    .append('<input type="hidden" name="javascript" />')
    .append('<input type="hidden" name="html" />')
    .append('<input type="hidden" name="css" />')
    .append('<input type="hidden" name="method" />')
    .append('<input type="hidden" name="_csrf" value="' + jsbin.state.token + '" />')
    .append('<input type="hidden" name="settings" />')
    .append('<input type="hidden" name="checksum" />');

  var settings = {};

  if (jsbin.state.processors) {
    settings.processors = jsbin.state.processors;
  }

  // this prevents new revisions forking off the welcome bin
  // because it's looking silly!
  if (jsbin.state.code === 'welcome') {
    $form.attr('action', '/save');
  }

  $form.find('input[name=settings]').val(JSON.stringify(settings));
  $form.find('input[name=javascript]').val(editors.javascript.getCode());
  $form.find('input[name=css]').val(editors.css.getCode());
  $form.find('input[name=html]').val(editors.html.getCode());
  $form.find('input[name=method]').val(method);
  $form.find('input[name=checksum]').val(jsbin.state.checksum);

  return $form;
}

function pad(n){
  return n<10 ? '0'+n : n;
}

function ISODateString(d){
  return d.getFullYear()+'-'
    + pad(d.getMonth()+1)+'-'
    + pad(d.getDate())+'T'
    + pad(d.getHours())+':'
    + pad(d.getMinutes())+':'
    + pad(d.getSeconds())+'Z';
}

function saveCode(method, ajax, ajaxCallback) {
  // create form and post to it
  var $form = setupform(method);
  // save our panel layout - assumes our user is happy with this layout
  jsbin.panels.save();
  jsbin.panels.saveOnExit = true;

  var data = $form.serializeArray().reduce(function(obj, data) {
    obj[data.name] = data.value;
    return obj;
  }, {});

  data.url = $.cookie('new-bin-name');

  if (jsbin.settings.useCompression) {
    compressKeys('html,css,javascript', data);
  }

  var save = function(){
    if (ajax) {
      $.ajax({
        url: $form.attr('action'),
        data: data,
        dataType: 'json',
        type: 'post',
        headers: {'Accept': 'application/json'},
        success: function (data) {
          if (ajaxCallback) {
            ajaxCallback(data);
          }

          store.sessionStorage.setItem('checksum', data.checksum);
          saveChecksum = data.checksum;

          jsbin.state.checksum = saveChecksum;
          jsbin.state.code = data.code;
          jsbin.state.revision = data.revision;
          jsbin.state.latest = true; // this is never not true...end of conversation!
          jsbin.state.metadata = { name: jsbin.user.name };
          $form.attr('action', jsbin.getURL({ withRevision: true }) + '/save');

          if (window.history && window.history.pushState) {
            // updateURL(edit);
            var hash = panels.getHighlightLines();
            if (hash) {hash = '#' + hash;}
            // If split is truthy (> 0) then we are using the revisonless feature
            // this is temporary until we release the feature!
            window.history.pushState(null, '', jsbin.getURL({withRevision: !split}) + '/edit' + hash);
            store.sessionStorage.setItem('url', jsbin.getURL({withRevision: !split}));
          } else {
            window.location.hash = data.edit;
          }

          $document.trigger('saved');
        },
        error: function (jqXHR) {
          onSaveError(jqXHR, null);
        },
        complete: function () {
          saving.inprogress(false);
        }
      });
    } else {
      $form.submit();
    }
  };

  if($.cookie('new-bin-name') || jsbin.state.revision !== undefined){
    save();
    $.removeCookie('new-bin-name');
  }else{
    $document.trigger('tip', {
      type: 'notication',
      content: 'The name of bin is not set. <input type="button" id="set-name" value="Set name">
',
      callback: function(){
        console.log($('#set-name'));
        $('#set-name').click(function(event){
          vex.dialog.prompt({
            message: 'What is name of new bin?',
            placeholder: 'Name of bin',
            className: 'vex-theme-os',
            callback: function(value) {
              $.cookie('new-bin-name', value);
              $('a.dismiss').trigger('click');
            }
          });
        });

      }
    });
  }
};
<|endoftext|>