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

import { connect } from 'react-redux';
import { saveThesis, updateThesis, deleteThesis } from './thesisActions';
import { createAttachment, deleteAttachment, downloadAttachments } from '../attachment/attachmentActions';
import { sendReminder } from '../email/emailActions';

import ThesisConfirmModal from '../../components/thesis/ThesisConfirmModal';
import ThesisInformation from '../../components/thesis/ThesisInformation';
import AttachmentAdder from '../../components/attachment/AttachmentAdder';
import AttachmentList from '../../components/attachment/AttachmentList';
import PersonSelector from '../../components/person/PersonSelector';
import ThesisCouncilmeetingPicker from '../../components/thesis/ThesisCouncilmeetingPicker';
import ThesisEmails from '../../components/thesis/ThesisEmails';

export class ThesisEditPage extends Component {
    /**
     *  If allowEdit is false, we are viewing a thesis
     *  If allowEdit is true, we are editing a thesis
     */
    constructor(props) {
        super(props);
        this.state = {
            thesis: {
                id: undefined,
                authorFirstname: '',
                authorLastname: '',
                authorEmail: '',
                title: '',
                urkund: '',
                grade: '',
                graders: [],
                graderEval: '',
                studyfieldId: '',
                councilmeetingId: '',
                printDone: undefined,
                thesisEmails: {
                    graderEvalReminder: undefined,
                    printReminder: undefined,
                },
            },
            attachments: [],
            showModal: false,
            allowEdit: true,
        }
    }

    componentDidMount() {
        this.init(this.props);
    }

    componentWillReceiveProps(newProps) {
        this.init(newProps);
    }

    init(props) {
        if (props.match.params && props.match.params.id) {
            const thesisId = props.match.params.id;
            const thesis = this.findAndFormatThesis(props.theses, props.persons, props.agreements, thesisId)
            if (thesis) {
                const attachments = props.attachments.filter(attachment => {
                    const agreement = props.agreements.find(agreement => agreement.agreementId === attachment.agreementId);
                    return agreement && agreement.agreementId === attachment.agreementId
                })
                this.setState({ thesis, attachments, editMode: true })
            }
        }
    }

    findAndFormatThesis = (theses, persons, agreements, thesisId) => {
        try {
            const thesis = theses.find(thesis => thesis.thesisId == thesisId);
            const agreement = agreements.find(agreement => agreement.thesisId === thesis.thesisId);
            const author = persons.find(person => person.personId === agreement.authorId);

            thesis.authorFirstname = author.firstname;
            thesis.authorLastname = author.lastname;
            thesis.authorEmail = author.email;

            thesis.studyfieldId = agreement.studyfieldId;
            thesis.graders = persons.filter(person =>
                this.props.roles.find(role =>
                    role.personId === person.personId &&
                    role.agreementId === agreement.agreementId
                )
            );
            thesis.thesisEmails = {
                graderEvalReminder: undefined,
                printReminder: undefined,
            }
            return thesis;
        } catch (error) {
            return undefined
        }
    }

    handleSaveThesis = () => {
        this.props.updateThesis(this.state.thesis);
    }

    deleteThesis = () => {
        this.props.deleteThesis(this.state.thesis.id);
    }

    toggleEditing = () => {
        this.setState({ allowEdit: !this.state.allowEdit });
    }

    handleChange = (fieldName, fieldValue) => {
        console.log('thesis.' + fieldName + ' = ' + fieldValue);
        const thesis = this.state.thesis;
        thesis[fieldName] = fieldValue;
        this.setState({ thesis });
    }

    addAttachment = (attachment) => {
        const form = new FormData();
        //agreementId needed to link the attachment to.
        const agreement = this.props.agreements.find(agreement => agreement.thesisId === this.state.thesis.thesisId);
        form.append("json", JSON.stringify(agreement));
        form.append('attachment', attachment);
        this.props.createAttachment(form)
    }

    removeAttachment = (attachment) => {
        this.props.deleteAttachment(attachment.attachmentId);
    }

    downloadAttachment = (attachmentId) => {
        this.props.downloadAttachments([attachmentId])
    }

    handleEmail = (reminderType) => {
        this.props.sendReminder(this.state.thesis.id, reminderType);
    }

    renderControlButtons() {
        //Admin controls
        if (this.props.user.roles && this.props.user.roles.find(studyfieldRole => studyfieldRole.role === 'admin')) {
            return (

                    {this.state.allowEdit ?

Stop editing

                        :

Edit

                    }

Save

Delete

                    <button className="ui violet button" onClick={this.downloadThesis}>Download as PDF</button>

            );
        }
    }

    renderEmails() {
        const thesisEmails = this.state.thesis.thesisEmails;
        return undefined;
        /*return <ThesisEmails
            thesisEmails={thesisEmails}
            sendEmail={this.handleEmail}
            sendDone={this.setReminderDone} />
            */
    }

    renderGraderSelecter() {
        const studyfieldGraders = this.props.persons.filter(person =>
            this.props.roles.find(role =>
                (role.name == 'grader' || role.name == 'supervisor')
                && role.personId == person.personId
                && role.studyfieldId == this.state.thesis.studyfieldId
            )
        )
        return <PersonSelector
            persons={studyfieldGraders}
            selected={this.state.thesis.graders}
            changeList={(list) => this.handleChange('graders', list)}
        />
    }

    render() {
        return (

                    {this.renderControlButtons()}
                    <ThesisInformation sendChange={this.handleChange}
                        thesis={this.state.thesis}
                        studyfields={this.props.studyfields}
                        allowEdit={this.state.allowEdit} />
                    {this.renderGraderSelecter()}
                    <AttachmentAdder
                        addAttachment={this.addAttachment}
                        removeAttachment={this.removeAttachment} />
                    <AttachmentList
                        attachments={this.state.attachments}
                        downloadAttachment={this.downloadAttachment}
                        deleteAttachment={this.props.deleteAttachment} />

                    {(this.state.allowEdit) ? <ThesisCouncilmeetingPicker sendChange={this.handleChange} councilmeetings={this.props.councilmeetings} /> : undefined}
                    {(this.state.allowEdit) ? this.renderEmails() : undefined}

                <button className="ui positive button" onClick={this.handleSaveThesis}>
                    Submit
                </button>

        )
    }
}

const mapDispatchToProps = (dispatch) => ({
    updateThesis(thesis) {
        dispatch(updateThesis(thesis));
    },
    deleteThesis(thesisId) {
        dispatch(deleteThesis(thesisId));
    },
    createAttachment(attachment) {
        dispatch(createAttachment(attachment));
    },
    deleteAttachment(attachmentId) {
        dispatch(deleteAttachment(attachmentId));
    },
    downloadAttachments(attachmentIds) {
        dispatch(downloadAttachments(attachmentIds));
    },
    sendReminder(thesisId, type) {
        dispatch(sendReminder(thesisId, type));
    },
});

const mapStateToProps = (state) => ({
    agreements: state.agreements,
    attachments: state.attachments,
    councilmeetings: state.councilmeetings,
    persons: state.persons,
    roles: state.roles,
    studyfields: state.studyfields,
    theses: state.theses,
    user: state.user,
});

export default connect(mapStateToProps, mapDispatchToProps)(ThesisEditPage);<commit_msg>Clone thesis object when rendering edit page.<commit_after>import React, { Component } from 'react';

import { connect } from 'react-redux';
import { saveThesis, updateThesis, deleteThesis } from './thesisActions';
import { createAttachment, deleteAttachment, downloadAttachments } from '../attachment/attachmentActions';
import { sendReminder } from '../email/emailActions';

import ThesisConfirmModal from '../../components/thesis/ThesisConfirmModal';
import ThesisInformation from '../../components/thesis/ThesisInformation';
import AttachmentAdder from '../../components/attachment/AttachmentAdder';
import AttachmentList from '../../components/attachment/AttachmentList';
import PersonSelector from '../../components/person/PersonSelector';
import ThesisCouncilmeetingPicker from '../../components/thesis/ThesisCouncilmeetingPicker';
import ThesisEmails from '../../components/thesis/ThesisEmails';

export class ThesisEditPage extends Component {
    /**
     *  If allowEdit is false, we are viewing a thesis
     *  If allowEdit is true, we are editing a thesis
     */
    constructor(props) {
        super(props);
        this.state = {
            thesis: {
                id: undefined,
                authorFirstname: '',
                authorLastname: '',
                authorEmail: '',
                title: '',
                urkund: '',
                grade: '',
                graders: [],
                graderEval: '',
                studyfieldId: '',
                councilmeetingId: '',
                printDone: undefined,
                thesisEmails: {
                    graderEvalReminder: undefined,
                    printReminder: undefined,
                },
            },
            attachments: [],
            showModal: false,
            allowEdit: true,
        }
    }

    componentDidMount() {
        this.init(this.props);
    }

    componentWillReceiveProps(newProps) {
        this.init(newProps);
    }

    init(props) {
        if (props.match.params && props.match.params.id) {
            const thesisId = props.match.params.id;
            const thesis = this.findAndFormatThesis(props.theses, props.persons, props.agreements, thesisId)
            if (thesis) {
                const attachments = props.attachments.filter(attachment => {
                    const agreement = props.agreements.find(agreement => agreement.agreementId === attachment.agreementId);
                    return agreement && agreement.agreementId === attachment.agreementId
                })
                this.setState({ thesis, attachments, editMode: true })
            }
        }
    }

    findAndFormatThesis = (theses, persons, agreements, thesisId) => {
        try {
            const thesis = Object.assign({}, theses.find(thesis => thesis.thesisId == thesisId));
            const agreement = agreements.find(agreement => agreement.thesisId === thesis.thesisId);
            const author = persons.find(person => person.personId === agreement.authorId);

            thesis.authorFirstname = author.firstname;
            thesis.authorLastname = author.lastname;
            thesis.authorEmail = author.email;

            thesis.studyfieldId = agreement.studyfieldId;
            thesis.graders = persons.filter(person =>
                this.props.roles.find(role =>
                    role.personId === person.personId &&
                    role.agreementId === agreement.agreementId
                )
            );
            thesis.thesisEmails = {
                graderEvalReminder: undefined,
                printReminder: undefined,
            }
            return thesis;
        } catch (error) {
            return undefined
        }
    }

    handleSaveThesis = () => {
        this.props.updateThesis(this.state.thesis);
    }

    deleteThesis = () => {
        this.props.deleteThesis(this.state.thesis.id);
    }

    toggleEditing = () => {
        this.setState({ allowEdit: !this.state.allowEdit });
    }

    handleChange = (fieldName, fieldValue) => {
        console.log('thesis.' + fieldName + ' = ' + fieldValue);
        const thesis = this.state.thesis;
        thesis[fieldName] = fieldValue;
        this.setState({ thesis });
    }

    addAttachment = (attachment) => {
        const form = new FormData();
        //agreementId needed to link the attachment to.
        const agreement = this.props.agreements.find(agreement => agreement.thesisId === this.state.thesis.thesisId);
        form.append("json", JSON.stringify(agreement));
        form.append('attachment', attachment);
        this.props.createAttachment(form)
    }

    removeAttachment = (attachment) => {
        this.props.deleteAttachment(attachment.attachmentId);
    }

    downloadAttachment = (attachmentId) => {
        this.props.downloadAttachments([attachmentId])
    }

    handleEmail = (reminderType) => {
        this.props.sendReminder(this.state.thesis.id, reminderType);
    }

    renderControlButtons() {
        //Admin controls
        if (this.props.user.roles && this.props.user.roles.find(studyfieldRole => studyfieldRole.role === 'admin')) {
            return (

                    {this.state.allowEdit ?

Stop editing

                        :

Edit

                    }

Save

Delete

                    <button className="ui violet button" onClick={this.downloadThesis}>Download as PDF</button>

            );
        }
    }

    renderEmails() {
        const thesisEmails = this.state.thesis.thesisEmails;
        return undefined;
        /*return <ThesisEmails
            thesisEmails={thesisEmails}
            sendEmail={this.handleEmail}
            sendDone={this.setReminderDone} />
            */
    }

    renderGraderSelecter() {
        const studyfieldGraders = this.props.persons.filter(person =>
            this.props.roles.find(role =>
                (role.name == 'grader' || role.name == 'supervisor')
                && role.personId == person.personId
                && role.studyfieldId == this.state.thesis.studyfieldId
            )
        )
        return <PersonSelector
            persons={studyfieldGraders}
            selected={this.state.thesis.graders}
            changeList={(list) => this.handleChange('graders', list)}
        />
    }

    render() {
        return (

                    {this.renderControlButtons()}
                    <ThesisInformation sendChange={this.handleChange}
                        thesis={this.state.thesis}
                        studyfields={this.props.studyfields}
                        allowEdit={this.state.allowEdit} />
                    {this.renderGraderSelecter()}
                    <AttachmentAdder
                        addAttachment={this.addAttachment}
                        removeAttachment={this.removeAttachment} />
                    <AttachmentList
                        attachments={this.state.attachments}
                        downloadAttachment={this.downloadAttachment}
                        deleteAttachment={this.props.deleteAttachment} />

                    {(this.state.allowEdit) ? <ThesisCouncilmeetingPicker sendChange={this.handleChange} councilmeetings={this.props.councilmeetings} /> : undefined}
                    {(this.state.allowEdit) ? this.renderEmails() : undefined}

                <button className="ui positive button" onClick={this.handleSaveThesis}>
                    Submit
                </button>

        )
    }
}

const mapDispatchToProps = (dispatch) => ({
    updateThesis(thesis) {
        dispatch(updateThesis(thesis));
    },
    deleteThesis(thesisId) {
        dispatch(deleteThesis(thesisId));
    },
    createAttachment(attachment) {
        dispatch(createAttachment(attachment));
    },
    deleteAttachment(attachmentId) {
        dispatch(deleteAttachment(attachmentId));
    },
    downloadAttachments(attachmentIds) {
        dispatch(downloadAttachments(attachmentIds));
    },
    sendReminder(thesisId, type) {
        dispatch(sendReminder(thesisId, type));
    },
});

const mapStateToProps = (state) => ({
    agreements: state.agreements,
    attachments: state.attachments,
    councilmeetings: state.councilmeetings,
    persons: state.persons,
    roles: state.roles,
    studyfields: state.studyfields,
    theses: state.theses,
    user: state.user,
});

export default connect(mapStateToProps, mapDispatchToProps)(ThesisEditPage);<|endoftext|>


<commit_before>"use strict"

const MAX_NOTE_NUMBER = 127
const RULER_HEIGHT = 22
const KEY_WIDTH = 100
const KEY_HEIGHT = 14
const CONTROL_HEIGHT = 200
const PIXELS_PER_TICK = 0.1
const TIME_BASE = 480

function createNote(tick = 0, noteNumber = 48, duration = 240, velocity = 127, channel) {
  return {
    type: "channel",
    subtype: "note",
    noteNumber: noteNumber || 48,
    tick: tick || 0,
    velocity: velocity || 127,
    duration: duration || 240,
    channel: channel,
    track: channel
  }
}

class PianoRollController {
  constructor(canvas) {
    this.emitter = {}
    riot.observable(this.emitter)

    this._quantizer = new Quantizer(TIME_BASE)

    this.showNotes = this.showNotes.bind(this)
    this.onScroll = this.onScroll.bind(this)

    this.loadView(canvas)
  }

  set ticksPerBeat(ticksPerBeat) {
    this._ticksPerBeat = ticksPerBeat
    this.grid.ticksPerBeat = ticksPerBeat
  }

  set transform(t) {
    this._transform = t
    this.grid.transform = t
    this.noteContainer.transform = t
    this.keys.transform = t

    this.calcContentSize()
    this.selection = this._selection
  }

  get player() {
    return SharedService.player
  }

  set track(track) {
    if (this._track) {
      this._track.off("change", this.showNotes)
    }
    this._track = track
    this._track.on("change", this.showNotes)

    this.calcContentSize()
    this.showNotes()
  }

  set mouseMode(mode) {
    switch(mode) {
    case 0:
      this.bindMouseHandler(new PencilMouseHandler(this.noteContainer))
      break
    case 1:
      this.bindMouseHandler(new SelectionMouseHandler(this.noteContainer, this.selectionView))
      break
    }
  }

  set selection(selection) {
    this._selection = selection
    this.selectionView.visible = selection != null
    if (selection) {
      const left = this._transform.getX(selection.fromTick)
      const right = this._transform.getX(selection.toTick)
      const top = this._transform.getY(selection.fromNoteNumber)
      const bottom = this._transform.getY(selection.toNoteNumber)
      this.selectionView.x = left
      this.selectionView.y = top
      this.selectionView.setSize(right - left, bottom - top)
    } else {
      this.selectionView.setSize(0, 0)
    }
    this.stage.update()
    this.showNotes()
  }

  set quantizeDenominator(val) {
    this._quantizer.denominator = val
  }

  loadView(canvas) {
    this.canvas = canvas
    this.stage = new createjs.Stage(canvas)
    this.stage.enableMouseOver()

    this.scrollContainer = new createjs.ScrollContainer(canvas)
    this.stage.addChild(this.scrollContainer)

    this.grid = new PianoGridView(RULER_HEIGHT)
    this.scrollContainer.addChild(this.grid)

    this.noteContainer = new NoteContainer()
    this.scrollContainer.addChild(this.noteContainer)

    this.controlContainer = new VelocityControlView(this.coordConverter)
    this.scrollContainer.addChild(this.controlContainer)

    this.selectionView = new SelectionView
    this.selectionView.setSize(0, 0)
    this.noteContainer.addChild(this.selectionView)

    this.keys = new PianoKeysView(KEY_WIDTH)
    this.keys.y = RULER_HEIGHT
    this.scrollContainer.addChild(this.keys)

    this.scrollContainer.addChild(this.grid.ruler)

    this.viewDidLoad()

    const resizeFunc = () => {
      const rect = canvas.getBoundingClientRect()
      this.resizeView(rect.width, rect.height)
    }
    window.onresize = resizeFunc
    resizeFunc()
  }

  viewDidLoad() {
    this.transform = new NoteCoordTransform(PIXELS_PER_TICK, KEY_HEIGHT, MAX_NOTE_NUMBER)
    this.ticksPerBeat = TIME_BASE
    this.mouseMode = 0

    this.stage.on("stagemousedown", e => {
      this.mouseHandler.onMouseDown(e)
    })
    this.stage.on("stagemouseup", e => {
      this.mouseHandler.onMouseUp(e)
    })
    this.stage.on("stagemousemove", e => {
      this.mouseHandler.onMouseMove(e)
    })

    this.controlContainer.on("change", e => {
      this._track.updateEvent(e.noteId, {velocity: e.velocity})
    })

    this.grid.ruler.on("click", e => {
      const tick = this.coordConverter.getTicksForPixels(this.quantizer.roundX(e.localX))
      opts.onMoveCursor(tick)
    })

    this.scrollContainer.on("scroll", this.onScroll)

    setInterval(() => {
      const tick = this.player.position
      this.grid.cursorPosition = this._transform.getX(tick)
      this.stage.update()
    }, 66)
  }

  getNotes() {
    return this._track.getEvents()
      .filter(e => e.subtype == "note")
  }

  calcContentSize() {
    const noteEnds = this._track ? this.getNotes().map(n => n.tick + n.duration) : [0]
    const maxTick = Math.max.apply(null, noteEnds)
    const maxX = this._transform.getX(maxTick)
    this.contentWidth = Math.ceil(maxX + KEY_WIDTH)
    this.contentHeight = this._transform.getY(0) + RULER_HEIGHT
    this.layoutSubviews()
  }

  showNotes() {
    if (!this._track) {
      return
    }
    const tickStart = this._transform.getTicks(-this.scrollContainer.scrollX)
    const tickEnd = this._transform.getTicks(-this.scrollContainer.scrollX + this.scrollContainer.getBounds().width)
    const notes = this.getNotes()
      .filter(note => note.tick >= tickStart && note.tick <= tickEnd)
      .map(note => {
        if (this._selection) {
          note.selected = this._selection.noteIds.includes(note.id)
        } else {
          note.selected = false
        }
        return note
      })

    this.noteContainer.notes = notes
    this.controlContainer.notes = notes
    this.grid.endTick = Math.max(100000, tickEnd)

    this._notes = notes
    this.stage.update()
  }

  layoutSubviews() {
    this.scrollContainer.setBounds(0, 0, this.canvas.width, this.canvas.height)
    this.scrollContainer.contentSize = {
      width: this.contentWidth,
      height: this.contentHeight
    }

    this.grid.x = KEY_WIDTH
    this.grid.redraw()
    this.grid.ruler.x = KEY_WIDTH

    this.noteContainer.x = KEY_WIDTH
    this.noteContainer.y = RULER_HEIGHT

    this.controlContainer.x = KEY_WIDTH
    this.controlContainer.setBounds(0, 0, this.contentWidth, CONTROL_HEIGHT)

    this.onScroll()
  }

  resizeView(width, height) {
    this.canvas.width = width
    this.canvas.height = height
    this.layoutSubviews()
  }

  onScroll() {
    this.keys.x = -this.scrollContainer.scrollX
    this.grid.rulerY = -this.scrollContainer.scrollY
    this.controlContainer.y =
      this.scrollContainer.getBounds().height -
      this.controlContainer.getBounds().height -
      this.scrollContainer.scrollY - 17
    this.showNotes()
  }

  bindMouseHandler(handler) {
    if (this.mouseHandler) {
      this.mouseHandler.off("*")
    }
    this.mouseHandler = handler

    handler.on("add-note", e => {
      this._track.addEvent(createNote(
        this._quantizer.floor(this._transform.getTicks(e.x)),
        Math.ceil(this._transform.getNoteNumber(e.y))
      ))
    })

    handler.on("remove-note", id => this._track.removeEvent(id))

    handler.on("drag-note-left-edge", e => {
      // 右端を固定して長さを変更
      const dt = this._transform.getTicks(e.movement.x)
      const tick = this._quantizer.round(e.note.tick + dt)
      if (e.note.tick < tick) {
        return
      }

      this._track.updateEvent(e.note.id, {
        tick: tick,
        duration: e.note.duration + (e.note.tick - tick)
      })
    })

    handler.on("drag-note-right-edge", e => {
      // 長さを変更
      const dt = this._transform.getTicks(e.movement.x)
      const duration = Math.max(this._quantizer.unit,
        this._quantizer.round(dt + e.note.duration))
      if (e.note.duration == duration) {
        return
      }

      this._track.updateEvent(e.note.id, {duration: duration})
    })

    handler.on("drag-note-center", e => {
      // 移動
      const dt = this._transform.getTicks(e.movement.x)
      const tick = this._quantizer.round(e.note.tick + dt)
      const dn = Math.round(this._transform.getDeltaNoteNumber(e.movement.y))
      const noteNumber = e.note.noteNumber + dn
      if (e.note.tick == tick && dn == 0) {
        return
      }

      this._track.updateEvent(e.note.id, {
        tick: tick,
        noteNumber: noteNumber
      })
    })

    handler.on("change-cursor", cursor => {
      const style = this.canvas.parentNode.style
      if (style.cursor != cursor) {
        style.cursor = cursor
      }
    })

    handler.on("clear-selection", () => {
      // 選択範囲外でクリックした場合は選択範囲をリセット
      this.selection = null
    })

    handler.on("resize-selection", rect => {
      this.selection = new Selection(
        this._quantizer.round(this._transform.getTicks(rect.x)),
        Math.ceil(this._transform.getNoteNumber(rect.y)),
        this._quantizer.round(this._transform.getTicks(rect.x + rect.width)),
        Math.ceil(this._transform.getNoteNumber(rect.y + rect.height)),
        []
      )
    })

    handler.on("select-notes", ids => {
      if (!this._selection) {
        return
      }
      const notes = ids.map(i => this._track.getEventById(i))
      this.selection = new Selection(
        this._selection.fromTick,
        this._selection.fromNoteNumber,
        this._selection.toTick,
        this._selection.toNoteNumber,
        notes
      )
      this.emitter.trigger("select-notes", notes)
    })

    handler.on("drag-selection-center", e => {
      if (!this._selection) {
        return
      }
      const dt = this._quantizer.round(this._transform.getTicks(e.movement.x))
      const dn = Math.round(this._transform.getDeltaNoteNumber(e.movement.y))

      if (dt == 0 && dn == 0) {
        return
      }

      // 確定済みの選択範囲をドラッグした場合はノートと選択範囲を移動
      this.selection = this._selection.original.copyMoved(dt, dn)

      this._selection.notes.forEach(e => {
        this._track.updateEvent(e.id, {
          tick: e.tick + dt,
          noteNumber: e.noteNumber + dn
        })
      })
    })

    handler.on("end-dragging", ids => {
      if (!this._selection) {
        return
      }
      // reset selection
      const notes = this._selection.noteIds.map(i => this._track.getEventById(i))
      this.selection = this._selection.copyUpdated(notes)
    })

    handler.on("drag-selection-left-edge", e => {
      if (!this._selection) {
        return
      }
      const dt = this._quantizer.floor(this._transform.getTicks(e.movement.x))
      if (dt > 0) {
        return
      }

      const notes = this._selection.notes.map(e => { return {
        id: e.id,
        tick: e.tick + dt,
        duration: e.duration - dt
      }})

      // 幅がゼロになるノートがあるときは変形しない
      if (!_.every(notes, r => r.duration > 0)) {
        return
      }

      // 右端を固定して長さを変更
      this.selection = this._selection.original.copyMoved(dt, 0, -dt)
      notes.forEach(e => this._track.updateEvent(e.id, e))
    })

    handler.on("drag-selection-right-edge", e => {
      if (!this._selection) {
        return
      }
      const dt = this._quantizer.floor(this._transform.getTicks(e.movement.x))
      if (dt == 0) {
        return
      }

      const notes = this._selection.notes.map(e => { return {
        id: e.id,
        duration: Math.max(this._quantizer.unit, e.duration + dt)
      }})

      // 左端を固定して長さを変更
      this.selection = this._selection.original.copyMoved(0, 0, dt)
      notes.forEach(e => this._track.updateEvent(e.id, e))
    })
  }

}<commit_msg>fix selection movement<commit_after>"use strict"

const MAX_NOTE_NUMBER = 127
const RULER_HEIGHT = 22
const KEY_WIDTH = 100
const KEY_HEIGHT = 14
const CONTROL_HEIGHT = 200
const PIXELS_PER_TICK = 0.1
const TIME_BASE = 480

function createNote(tick = 0, noteNumber = 48, duration = 240, velocity = 127, channel) {
  return {
    type: "channel",
    subtype: "note",
    noteNumber: noteNumber || 48,
    tick: tick || 0,
    velocity: velocity || 127,
    duration: duration || 240,
    channel: channel,
    track: channel
  }
}

class PianoRollController {
  constructor(canvas) {
    this.emitter = {}
    riot.observable(this.emitter)

    this._quantizer = new Quantizer(TIME_BASE)

    this.showNotes = this.showNotes.bind(this)
    this.onScroll = this.onScroll.bind(this)

    this.loadView(canvas)
  }

  set ticksPerBeat(ticksPerBeat) {
    this._ticksPerBeat = ticksPerBeat
    this.grid.ticksPerBeat = ticksPerBeat
  }

  set transform(t) {
    this._transform = t
    this.grid.transform = t
    this.noteContainer.transform = t
    this.keys.transform = t

    this.calcContentSize()
    this.selection = this._selection
  }

  get player() {
    return SharedService.player
  }

  set track(track) {
    if (this._track) {
      this._track.off("change", this.showNotes)
    }
    this._track = track
    this._track.on("change", this.showNotes)

    this.calcContentSize()
    this.showNotes()
  }

  set mouseMode(mode) {
    switch(mode) {
    case 0:
      this.bindMouseHandler(new PencilMouseHandler(this.noteContainer))
      break
    case 1:
      this.bindMouseHandler(new SelectionMouseHandler(this.noteContainer, this.selectionView))
      break
    }
  }

  set selection(selection) {
    this._selection = selection
    this.selectionView.visible = selection != null
    if (selection) {
      const left = this._transform.getX(selection.fromTick)
      const right = this._transform.getX(selection.toTick)
      const top = this._transform.getY(selection.fromNoteNumber)
      const bottom = this._transform.getY(selection.toNoteNumber)
      this.selectionView.x = left
      this.selectionView.y = top
      this.selectionView.setSize(right - left, bottom - top)
    } else {
      this.selectionView.setSize(0, 0)
    }
    this.stage.update()
    this.showNotes()
  }

  set quantizeDenominator(val) {
    this._quantizer.denominator = val
  }

  loadView(canvas) {
    this.canvas = canvas
    this.stage = new createjs.Stage(canvas)
    this.stage.enableMouseOver()

    this.scrollContainer = new createjs.ScrollContainer(canvas)
    this.stage.addChild(this.scrollContainer)

    this.grid = new PianoGridView(RULER_HEIGHT)
    this.scrollContainer.addChild(this.grid)

    this.noteContainer = new NoteContainer()
    this.scrollContainer.addChild(this.noteContainer)

    this.controlContainer = new VelocityControlView(this.coordConverter)
    this.scrollContainer.addChild(this.controlContainer)

    this.selectionView = new SelectionView
    this.selectionView.setSize(0, 0)
    this.noteContainer.addChild(this.selectionView)

    this.keys = new PianoKeysView(KEY_WIDTH)
    this.keys.y = RULER_HEIGHT
    this.scrollContainer.addChild(this.keys)

    this.scrollContainer.addChild(this.grid.ruler)

    this.viewDidLoad()

    const resizeFunc = () => {
      const rect = canvas.getBoundingClientRect()
      this.resizeView(rect.width, rect.height)
    }
    window.onresize = resizeFunc
    resizeFunc()
  }

  viewDidLoad() {
    this.transform = new NoteCoordTransform(PIXELS_PER_TICK, KEY_HEIGHT, MAX_NOTE_NUMBER)
    this.ticksPerBeat = TIME_BASE
    this.mouseMode = 0

    this.stage.on("stagemousedown", e => {
      this.mouseHandler.onMouseDown(e)
    })
    this.stage.on("stagemouseup", e => {
      this.mouseHandler.onMouseUp(e)
    })
    this.stage.on("stagemousemove", e => {
      this.mouseHandler.onMouseMove(e)
    })

    this.controlContainer.on("change", e => {
      this._track.updateEvent(e.noteId, {velocity: e.velocity})
    })

    this.grid.ruler.on("click", e => {
      const tick = this.coordConverter.getTicksForPixels(this.quantizer.roundX(e.localX))
      opts.onMoveCursor(tick)
    })

    this.scrollContainer.on("scroll", this.onScroll)

    setInterval(() => {
      const tick = this.player.position
      this.grid.cursorPosition = this._transform.getX(tick)
      this.stage.update()
    }, 66)
  }

  getNotes() {
    return this._track.getEvents()
      .filter(e => e.subtype == "note")
  }

  calcContentSize() {
    const noteEnds = this._track ? this.getNotes().map(n => n.tick + n.duration) : [0]
    const maxTick = Math.max.apply(null, noteEnds)
    const maxX = this._transform.getX(maxTick)
    this.contentWidth = Math.ceil(maxX + KEY_WIDTH)
    this.contentHeight = this._transform.getY(0) + RULER_HEIGHT
    this.layoutSubviews()
  }

  showNotes() {
    if (!this._track) {
      return
    }
    const tickStart = this._transform.getTicks(-this.scrollContainer.scrollX)
    const tickEnd = this._transform.getTicks(-this.scrollContainer.scrollX + this.scrollContainer.getBounds().width)
    const notes = this.getNotes()
      .filter(note => note.tick >= tickStart && note.tick <= tickEnd)
      .map(note => {
        if (this._selection) {
          note.selected = this._selection.noteIds.includes(note.id)
        } else {
          note.selected = false
        }
        return note
      })

    this.noteContainer.notes = notes
    this.controlContainer.notes = notes
    this.grid.endTick = Math.max(100000, tickEnd)

    this._notes = notes
    this.stage.update()
  }

  layoutSubviews() {
    this.scrollContainer.setBounds(0, 0, this.canvas.width, this.canvas.height)
    this.scrollContainer.contentSize = {
      width: this.contentWidth,
      height: this.contentHeight
    }

    this.grid.x = KEY_WIDTH
    this.grid.redraw()
    this.grid.ruler.x = KEY_WIDTH

    this.noteContainer.x = KEY_WIDTH
    this.noteContainer.y = RULER_HEIGHT

    this.controlContainer.x = KEY_WIDTH
    this.controlContainer.setBounds(0, 0, this.contentWidth, CONTROL_HEIGHT)

    this.onScroll()
  }

  resizeView(width, height) {
    this.canvas.width = width
    this.canvas.height = height
    this.layoutSubviews()
  }

  onScroll() {
    this.keys.x = -this.scrollContainer.scrollX
    this.grid.rulerY = -this.scrollContainer.scrollY
    this.controlContainer.y =
      this.scrollContainer.getBounds().height -
      this.controlContainer.getBounds().height -
      this.scrollContainer.scrollY - 17
    this.showNotes()
  }

  bindMouseHandler(handler) {
    if (this.mouseHandler) {
      this.mouseHandler.off("*")
    }
    this.mouseHandler = handler

    handler.on("add-note", e => {
      this._track.addEvent(createNote(
        this._quantizer.floor(this._transform.getTicks(e.x)),
        Math.ceil(this._transform.getNoteNumber(e.y))
      ))
    })

    handler.on("remove-note", id => this._track.removeEvent(id))

    handler.on("drag-note-left-edge", e => {
      // 右端を固定して長さを変更
      const dt = this._transform.getTicks(e.movement.x)
      const tick = this._quantizer.round(e.note.tick + dt)
      if (e.note.tick < tick) {
        return
      }

      this._track.updateEvent(e.note.id, {
        tick: tick,
        duration: e.note.duration + (e.note.tick - tick)
      })
    })

    handler.on("drag-note-right-edge", e => {
      // 長さを変更
      const dt = this._transform.getTicks(e.movement.x)
      const duration = Math.max(this._quantizer.unit,
        this._quantizer.round(dt + e.note.duration))
      if (e.note.duration == duration) {
        return
      }

      this._track.updateEvent(e.note.id, {duration: duration})
    })

    handler.on("drag-note-center", e => {
      // 移動
      const dt = this._transform.getTicks(e.movement.x)
      const tick = this._quantizer.round(e.note.tick + dt)
      const dn = Math.round(this._transform.getDeltaNoteNumber(e.movement.y))
      const noteNumber = e.note.noteNumber + dn
      if (e.note.tick == tick && dn == 0) {
        return
      }

      this._track.updateEvent(e.note.id, {
        tick: tick,
        noteNumber: noteNumber
      })
    })

    handler.on("change-cursor", cursor => {
      const style = this.canvas.parentNode.style
      if (style.cursor != cursor) {
        style.cursor = cursor
      }
    })

    handler.on("clear-selection", () => {
      // 選択範囲外でクリックした場合は選択範囲をリセット
      this.selection = null
    })

    handler.on("resize-selection", rect => {
      this.selection = new Selection(
        this._quantizer.round(this._transform.getTicks(rect.x)),
        Math.ceil(this._transform.getNoteNumber(rect.y)),
        this._quantizer.round(this._transform.getTicks(rect.x + rect.width)),
        Math.ceil(this._transform.getNoteNumber(rect.y + rect.height)),
        []
      )
    })

    handler.on("select-notes", ids => {
      if (!this._selection) {
        return
      }
      const notes = ids.map(i => this._track.getEventById(i))
      this.selection = new Selection(
        this._selection.fromTick,
        this._selection.fromNoteNumber,
        this._selection.toTick,
        this._selection.toNoteNumber,
        notes
      )
      this.emitter.trigger("select-notes", notes)
    })

    handler.on("drag-selection-center", e => {
      if (!this._selection) {
        return
      }
      const dt = this._quantizer.round(this._transform.getTicks(e.movement.x))
      const dn = Math.round(this._transform.getDeltaNoteNumber(e.movement.y))

      // 確定済みの選択範囲をドラッグした場合はノートと選択範囲を移動
      this.selection = this._selection.original.copyMoved(dt, dn)

      this._selection.notes.forEach(e => {
        this._track.updateEvent(e.id, {
          tick: e.tick + dt,
          noteNumber: e.noteNumber + dn
        })
      })
    })

    handler.on("end-dragging", ids => {
      if (!this._selection) {
        return
      }
      // reset selection
      const notes = this._selection.noteIds.map(i => this._track.getEventById(i))
      this.selection = this._selection.copyUpdated(notes)
    })

    handler.on("drag-selection-left-edge", e => {
      if (!this._selection) {
        return
      }
      const dt = this._quantizer.floor(this._transform.getTicks(e.movement.x))
      if (dt > 0) {
        return
      }

      const notes = this._selection.notes.map(e => { return {
        id: e.id,
        tick: e.tick + dt,
        duration: e.duration - dt
      }})

      // 幅がゼロになるノートがあるときは変形しない
      if (!_.every(notes, r => r.duration > 0)) {
        return
      }

      // 右端を固定して長さを変更
      this.selection = this._selection.original.copyMoved(dt, 0, -dt)
      notes.forEach(e => this._track.updateEvent(e.id, e))
    })

    handler.on("drag-selection-right-edge", e => {
      if (!this._selection) {
        return
      }
      const dt = this._quantizer.floor(this._transform.getTicks(e.movement.x))
      if (dt == 0) {
        return
      }

      const notes = this._selection.notes.map(e => { return {
        id: e.id,
        duration: Math.max(this._quantizer.unit, e.duration + dt)
      }})

      // 左端を固定して長さを変更
      this.selection = this._selection.original.copyMoved(0, 0, dt)
      notes.forEach(e => this._track.updateEvent(e.id, e))
    })
  }

}<|endoftext|>


<commit_before>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");

module.exports = {
    componentWillMount: function() {
        var cli = MatrixClientPeg.get();
        cli.on("RoomState.members", this.onRoomStateMember);

        var members = this.roomMembers();
        this.setState({
            memberDict: members
        });
    },

    componentWillUnmount: function() {
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
        }
    },

    // Remember to set 'key' on a MemberList to the ID of the room it's for
    /*componentWillReceiveProps: function(newProps) {
    },*/

    onRoomStateMember: function(ev, state, member) {
        var members = this.roomMembers();
        this.setState({
            memberDict: members
        });
    },

    roomMembers() {
        var cli = MatrixClientPeg.get();
        var all_members = cli.getRoom(this.props.roomId).currentState.members;
        var to_display = {};
        for (var i = 0; i < Object.keys(all_members).length; ++i) {
            var user_id = Object.keys(all_members)[i];
            var m = all_members[user_id];

            if (m.membership == 'join' || m.membership == 'invite') {
                to_display[user_id] = m;
            }
        }
        return to_display;
    }
};

<commit_msg>Apparently Object.keys is kinda slow<commit_after>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");

module.exports = {
    componentWillMount: function() {
        var cli = MatrixClientPeg.get();
        cli.on("RoomState.members", this.onRoomStateMember);

        var members = this.roomMembers();
        this.setState({
            memberDict: members
        });
    },

    componentWillUnmount: function() {
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
        }
    },

    // Remember to set 'key' on a MemberList to the ID of the room it's for
    /*componentWillReceiveProps: function(newProps) {
    },*/

    onRoomStateMember: function(ev, state, member) {
        var members = this.roomMembers();
        this.setState({
            memberDict: members
        });
    },

    roomMembers() {
        var cli = MatrixClientPeg.get();
        var all_members = cli.getRoom(this.props.roomId).currentState.members;
        var all_user_ids = Object.keys(all_members);
        var to_display = {};
        for (var i = 0; i < all_user_ids.length; ++i) {
            var user_id = all_user_ids[i];
            var m = all_members[user_id];

            if (m.membership == 'join' || m.membership == 'invite') {
                to_display[user_id] = m;
            }
        }
        return to_display;
    }
};

<|endoftext|>


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

/*
    ___ usage ___ en_US ___
    compassion channel <child options>

    options:

        -l, --log <filename|->
            file to read

        -I, --island <string>
            name of the island

        -i, --id <string>
            colleague id

        -p, --ping <integer>
            milliseconds between keep alive pings (defualt 250)

        -t, --timeout <integer>
            milliseconds before a participant is considered unreachable (defualt 1000)

        --help
            display help message

    ___ $ ___ en_US ___

        bind is required:
            the `--bind` argument is a required argument

        name is required:
            the `--name` argument is a required argument
    ___ . ___

 */
require('arguable')(module, require('cadence')(function (async, program) {
    var Shuttle = require('prolific.shuttle')
    var fs = require('fs')
    var Channel = require('./channel')
    var Merger = require('./merger')
    var Staccato = require('staccato')
    var Recorder = require('./recorder')
    var byline = require('byline')

    var Conduit = require('conduit')

    var logger = require('prolific.logger').createLogger('compassion.channel')

    var shuttle = Shuttle.shuttle(program, logger)
    var Monitor = require('compassion.colleague/monitor')
    var Kibitzer = require('kibitz')
    var coalesce = require('extant')
    var Destructor = require('destructible')
    var cadence = require('cadence')

    var Thereafter = require('thereafter')

    var Reader = require('./reader')

    program.helpIf(program.ultimate.help)

    var stream = program.ultimate.log == null
               ? program.stdin
               : fs.createReadStream(program.ultimate.log)

    var kibitzer = new Kibitzer({
        id: program.ultimate.id,
        ping: coalesce(program.ultimate.ping, 1000),
        timeout: coalesce(program.ultimate.timeout, 5000)
    })

    var channel = new Channel(kibitzer)
    var monitor = new Monitor

    var merger = new Merger(kibitzer, channel)

    kibitzer.played.shifter().pump(new Recorder('kibitz', logger, merger.play), 'enqueue')
    kibitzer.paxos.outbox.shifter().pump(new Recorder('paxos', logger, merger.play), 'enqueue')
    kibitzer.islander.outbox.shifter().pump(new Recorder('islander', logger, merger.play), 'enqueue')

    var destructible = new Destructor('channel.bin')

    program.on('shutdown', destructible.destroy.bind(destructible))

    destructible.addDestructor('shuttle', shuttle, 'close')

    var thereafter = new Thereafter
    destructible.addDestructor('thereafter', thereafter, 'cancel')

    thereafter.run(function (ready) {
        cadence(function (async) {
            destructible.addDestructor('monitor', monitor, 'destroy')
            monitor.ready.wait(ready, 'unlatch')
            async(function () {
                monitor.run(program, async())
            }, function (exitCode, signal) {
                logger.info('exited', { exitCode: exitCode, signal: signal })
            })
        })(destructible.monitor('monitor'))
    })

    destructible.addDestructor('channel', channel, 'destroy')

    // Gives an `ENOENT` time to report and cancel the series.
    thereafter.run(function (ready) {
        cadence(function () {
            setImmediate(async())
        }, function () {
            ready.unlatch()
        })(destructible.rescue('startup'))
    })

    thereafter.run(function (ready) {
        var conduit = new Conduit(monitor.child.stdio[3], monitor.child.stdio[3], channel)
        destructible.addDestructor('conduit', conduit, 'destroy')
        destructible.addDestructor('write', channel.write, 'push')
        conduit.ready.wait(ready, 'unlatch')
        conduit.listen(null, destructible.monitor('conduit'))
    })

    thereafter.run(function (ready) {
        var reader = new Reader
        destructible.addDestructor('reader', reader, 'destroy')
        reader.ready.wait(ready, 'unlatch')
        reader.read(stream, merger, destructible.monitor('readable'))
    })
    stream.once('error', function () { console.log(error.stack) })
    monitor.child.stdio[3].once('error', function (error) { console.log(error.stack) })

    thereafter.run(function (ready) {
        destructible.addDestructor('merger', merger, 'destroy')
        merger.ready.wait(ready, 'unlatch')
        merger.merge(destructible.monitor('merger'))
    })

    thereafter.ready.wait(program.ready, 'unlatch')

    destructible.completed(5000, async())
}))
<commit_msg>Remove pipe error listeners.<commit_after>#!/usr/bin/env node

/*
    ___ usage ___ en_US ___
    compassion channel <child options>

    options:

        -l, --log <filename|->
            file to read

        -I, --island <string>
            name of the island

        -i, --id <string>
            colleague id

        -p, --ping <integer>
            milliseconds between keep alive pings (defualt 250)

        -t, --timeout <integer>
            milliseconds before a participant is considered unreachable (defualt 1000)

        --help
            display help message

    ___ $ ___ en_US ___

        bind is required:
            the `--bind` argument is a required argument

        name is required:
            the `--name` argument is a required argument
    ___ . ___

 */
require('arguable')(module, require('cadence')(function (async, program) {
    var Shuttle = require('prolific.shuttle')
    var fs = require('fs')
    var Channel = require('./channel')
    var Merger = require('./merger')
    var Staccato = require('staccato')
    var Recorder = require('./recorder')
    var byline = require('byline')

    var Conduit = require('conduit')

    var logger = require('prolific.logger').createLogger('compassion.channel')

    var shuttle = Shuttle.shuttle(program, logger)
    var Monitor = require('compassion.colleague/monitor')
    var Kibitzer = require('kibitz')
    var coalesce = require('extant')
    var Destructor = require('destructible')
    var cadence = require('cadence')

    var Thereafter = require('thereafter')

    var Reader = require('./reader')

    program.helpIf(program.ultimate.help)

    var stream = program.ultimate.log == null
               ? program.stdin
               : fs.createReadStream(program.ultimate.log)

    var kibitzer = new Kibitzer({
        id: program.ultimate.id,
        ping: coalesce(program.ultimate.ping, 1000),
        timeout: coalesce(program.ultimate.timeout, 5000)
    })

    var channel = new Channel(kibitzer)
    var monitor = new Monitor

    var merger = new Merger(kibitzer, channel)

    kibitzer.played.shifter().pump(new Recorder('kibitz', logger, merger.play), 'enqueue')
    kibitzer.paxos.outbox.shifter().pump(new Recorder('paxos', logger, merger.play), 'enqueue')
    kibitzer.islander.outbox.shifter().pump(new Recorder('islander', logger, merger.play), 'enqueue')

    var destructible = new Destructor('channel.bin')

    program.on('shutdown', destructible.destroy.bind(destructible))

    destructible.addDestructor('shuttle', shuttle, 'close')

    var thereafter = new Thereafter
    destructible.addDestructor('thereafter', thereafter, 'cancel')

    thereafter.run(function (ready) {
        cadence(function (async) {
            destructible.addDestructor('monitor', monitor, 'destroy')
            monitor.ready.wait(ready, 'unlatch')
            async(function () {
                monitor.run(program, async())
            }, function (exitCode, signal) {
                logger.info('exited', { exitCode: exitCode, signal: signal })
            })
        })(destructible.monitor('monitor'))
    })

    destructible.addDestructor('channel', channel, 'destroy')

    // Gives an `ENOENT` time to report and cancel the series.
    thereafter.run(function (ready) {
        cadence(function () {
            setImmediate(async())
        }, function () {
            ready.unlatch()
        })(destructible.rescue('startup'))
    })

    thereafter.run(function (ready) {
        var conduit = new Conduit(monitor.child.stdio[3], monitor.child.stdio[3], channel)
        destructible.addDestructor('conduit', conduit, 'destroy')
        destructible.addDestructor('write', channel.write, 'push')
        conduit.ready.wait(ready, 'unlatch')
        conduit.listen(null, destructible.monitor('conduit'))
    })

    thereafter.run(function (ready) {
        var reader = new Reader
        destructible.addDestructor('reader', reader, 'destroy')
        reader.ready.wait(ready, 'unlatch')
        reader.read(stream, merger, destructible.monitor('readable'))
    })
//    stream.once('error', function () { console.log(error.stack) })
//    monitor.child.stdio[3].once('error', function (error) { console.log(error.stack) })

    thereafter.run(function (ready) {
        destructible.addDestructor('merger', merger, 'destroy')
        merger.ready.wait(ready, 'unlatch')
        merger.merge(destructible.monitor('merger'))
    })

    thereafter.ready.wait(program.ready, 'unlatch')

    destructible.completed(5000, async())
}))
<|endoftext|>


<commit_before>Template.playerModal.helpers({
	'currentPlayerDoingAction': function() {
		return Session.get('currentPlayerForModal').firstName.charAt(0) + ". " + Session.get('currentPlayerForModal').lastName;
	}
});

Template.playerModal.events({
	'click #correctionAction': function() {
		$('.buttonForAction').prepend('-1 ');
		$('#correctionAction').addClass('cancelCorrectionAction');
	},
	'click #closeModalButton': function() {
		$('.actionBadge').remove();
		$('#correctionAction').removeClass('cancelCorrectionAction');
	},
	'click .cancelCorrectionAction': function() {
		$('.actionBadge').remove();
		$('#correctionAction').removeClass('cancelCorrectionAction');
	},
	'hide.bs.modal .modal': function() {
		$('.actionBadge').remove();
		$('#correctionAction').removeClass('cancelCorrectionAction');
	},
	// Positive action
	'click #onePoint': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('onePoint', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #twoPoint': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('twoPoints', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #threePoint': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('threePoints', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #assist': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('assists', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #offReb': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('offRebs', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defReb': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defRebs', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #offProvFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('offProvFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #steal': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('steals', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #block': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('blocks', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defProvFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defProvFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	// Negative action
	'click #onePointMiss': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('onePointMiss', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #twoPointMiss': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('twoPointsMiss', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #threePointMiss': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('threePointsMiss', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #turnover': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('turnovers', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #offFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('offFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoulOneFT': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFoulsOneFT', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoulTwoFT': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFoulsTwoFT', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoulthreeFT': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFoulsThreeFT', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #techFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('techFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #antiSportFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('antiSportFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #disqualifyingFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('disqualifyingFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	}
});
<commit_msg>WIP for correctionAction feature<commit_after>Template.playerModal.helpers({
	'currentPlayerDoingAction': function() {
		return Session.get('currentPlayerForModal').firstName.charAt(0) + ". " + Session.get('currentPlayerForModal').lastName;
	}
});

Template.playerModal.events({
	'click #correctionAction': function() {
		$('.buttonForAction').prepend('-1 ').addClass('cancelAction');
		$('#correctionAction').addClass('cancelCorrectionAction');
	},
	'click #closeModalButton': function() {
		$('.actionBadge').remove();
		$('#correctionAction').removeClass('cancelCorrectionAction');
		$('.buttonForAction').removeClass('cancelAction');
	},
	'click .cancelCorrectionAction': function() {
		$('.actionBadge').remove();
		$('#correctionAction').removeClass('cancelCorrectionAction');
		$('.buttonForAction').removeClass('cancelAction');
	},
	'hidden.bs.modal .modal': function() {
		$('.actionBadge').remove();
		$('#correctionAction').removeClass('cancelCorrectionAction');
		$('.buttonForAction').removeClass('cancelAction');
	},
	// Positive action
	'click #onePoint': function(e, t) {
		console.log(e);
		console.log(t);
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('onePoint', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #twoPoint': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('twoPoints', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #threePoint': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('threePoints', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #assist': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('assists', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #offReb': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('offRebs', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defReb': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defRebs', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #offProvFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('offProvFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #steal': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('steals', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #block': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('blocks', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defProvFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defProvFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	// Negative action
	'click #onePointMiss': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('onePointMiss', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #twoPointMiss': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('twoPointsMiss', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #threePointMiss': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('threePointsMiss', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #turnover': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('turnovers', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #offFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('offFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoulOneFT': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFoulsOneFT', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoulTwoFT': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFoulsTwoFT', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #defFoulthreeFT': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('defFoulsThreeFT', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #techFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('techFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #antiSportFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('antiSportFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	},
	'click #disqualifyingFoul': function(e) {
		var actionInfo = {
			gameId: Template.parentData(1)._id,
			playerIndex: Session.get('currentPlayerForModal').playerIndex,
			team: Session.get('currentPlayerForModal').team
		};
		Meteor.call('disqualifyingFouls', actionInfo, function(error) {
			if (error) {
				return throwError(error.message);
			}
		});
	}
});
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name angularApp.controller:AppCtrl
 * @description
 * # AboutCtrl
 * Controller of the angularApp
 */
angularApp.controller('AppCtrl', ["$scope","config","$window","$timeout","Applications","ApplicationAccess","ApplicationInfo","Util",
function ($scope,config,$window,$timeout,Applications,ApplicationAccess,ApplicationInfo,Util) {
    $scope.page_index = 0;
    $scope.page_size = 20;
    $scope.applications = [];
    $scope.exec_logs = [];
    $scope.showList  = ["list","logs","application","exec"]
    $scope.showScope = $scope.showList[0];
    $timeout(function () {
            Applications.read({
                "page_index":$scope.page_index,
                "page_size":$scope.page_size
            },function(res){
                if(res.status=="success"){
                    var applications =  res.data;
                    for(var i=0;i<applications.length;i++){
                        var application = applications[i];
                        var ports = (application.inspect_container && application.inspect_container.NetworkSettings  && application.inspect_container.NetworkSettings.Ports)?application.inspect_container.NetworkSettings.Ports:[];
                        var tPorts = [];
                        for(var p in ports){
                            if(ports[p] && ports[p].length>0){
                                var tPort =  ports[p][0];
                                tPort["PortAndType"] = p;
                                tPorts.push(tPort)
                            }
                        }
                        $window.console.log(tPorts);
                        var urls = [];
                        for(var j=0;j<tPorts.length;j++){
                            var url = "http://"+(application.singleton?"":application.user_name+"-"+application.project_name+".")+application.address_prefix+":"+tPorts[j].HostPort;
                            urls.push({
                                "PortAndType":tPorts[j].PortAndType,
                                "PortUrl":url
                            });
                        }
                        $window.console.log(urls);
                        applications[i]["urls"] = urls;
                    }
                    $scope.applications = applications;
                }else{
                    alert('数据为空');
                }
            },function(e,err){
                alert('请求失败');
            });
    }, 100);
    $scope.showAppliactions = function(){
        $scope.showScope = $scope.showList[0];
    }
    $scope.container_access = function(access_type,_id,content){
      ApplicationAccess.start(null,$.param({"type":access_type,"id":_id,"content":content}),function(res){
              if(res.status=="success"){
                    alert("操作成功");
                    if(access_type=="delete"){
                        var deleteIndex = -1;
                        for(var i=0;i<$scope.applications.length;i++){
                            if($scope.applications[i]._id == _id){
                                deleteIndex = i;
                            }
                        }
                        if(deleteIndex!=-1)
                            $scope.applications.splice(deleteIndex,1);
                    }
                }else{
                    alert(res.msg);
                }
      },function(e,err){
        alert('请求失败');
      })
    }

    $scope.getContainerInfo = function(_id){
        ApplicationInfo.info(null,$.param({
          "application_id":_id
        }),function(res){
            var run_status = res.data.status;
            var run_info = res.data.logs;
            for(var i=0;i<run_info.length;i++){
                 run_info[i].log = Util.FormatLog(run_info[i].info);
            }
            $scope.application["run_status"] = run_status;
            $scope.application["run_info"] = run_info;
        },function(e,err){
            $scope.application["run_status"] = "抱歉，网络原因无法得知当前状态";
            $scope.application["run_info"] = "抱歉,网络原因无法更新日志";
        });
    }
    // 获取构建日志
    $scope.show_run_logs = function(_id){
      // 获取日志
        for(var i=0;i<$scope.applications.length;i++){
            if($scope.applications[i]._id == _id){
                  $scope.application = $scope.applications[i];
                  $scope.showScope = $scope.showList[2];
                  $scope.getContainerInfo(_id);
            }
        }
    }
    // 获取容器日志
    $scope.show_container_logs = function(_id){
      // 获取日志

      // 切换视图
      $scope.showScope = $scope.showList[2];
    }
    // 追加交互日志
    $scope.append_exec_logs = function(content){
      if(content==""){
        $scope.exec_logs.push("");
      }else{
        // 和后台进行交互获取日志

        // 将结果呈现在界面上
        $scope.exec_logs.push(content);
      }
    }
    $scope.show_exec = function(_id){
      // 查找application
      var findArr = $scope.applications.filter(function(item,index){
        return item._id==_id;
      });
      if(findArr.length>=1){
        $scope.application = findArr[0];
        // 清空交互日志
        $scope.exec_logs = [];
        // 切换视图
        $scope.showScope = $scope.showList[2];
      }else{
        $window.console.log("没有找到容器");
      }
    }
}]);
<commit_msg>Update application.js<commit_after>'use strict';

/**
 * @ngdoc function
 * @name angularApp.controller:AppCtrl
 * @description
 * # AboutCtrl
 * Controller of the angularApp
 */
angularApp.controller('AppCtrl', ["$scope","config","$window","$timeout","Applications","ApplicationAccess","ApplicationInfo","Util",
function ($scope,config,$window,$timeout,Applications,ApplicationAccess,ApplicationInfo,Util) {
    $scope.page_index = 0;
    $scope.page_size = 20;
    $scope.applications = [];
    $scope.exec_logs = [];
    $scope.showList  = ["list","logs","application","exec"]
    $scope.showScope = $scope.showList[0];
    $timeout(function () {
            Applications.read({
                "page_index":$scope.page_index,
                "page_size":$scope.page_size
            },function(res){
                if(res.status=="success"){
                    var applications =  res.data;
                    for(var i=0;i<applications.length;i++){
                        var application = applications[i];
                        var ports = (application.inspect_container && application.inspect_container.NetworkSettings  && application.inspect_container.NetworkSettings.Ports)?application.inspect_container.NetworkSettings.Ports:[];
                        var tPorts = [];
                        for(var p in ports){
                            if(ports[p] && ports[p].length>0){
                                var tPort =  ports[p][0];
                                tPort["PortAndType"] = p;
                                tPorts.push(tPort)
                            }
                        }
                        $window.console.log(tPorts);
                        var urls = [];
                        for(var j=0;j<tPorts.length;j++){
                            var url = "http://"+(application.singleton?"":application.user_name+"-"+application.project_name+".")+application.address_prefix+":"+tPorts[j].HostPort;
                            urls.push({
                                "PortAndType":tPorts[j].PortAndType,
                                "PortUrl":url
                            });
                        }
                        $window.console.log(urls);
                        applications[i]["urls"] = urls;
                    }
                    $scope.applications = applications;
                }else{
                    alert('数据为空');
                }
            },function(e,err){
                alert('请求失败');
            });
    }, 100);
    $scope.showAppliactions = function(){
        $scope.showScope = $scope.showList[0];
    }
    $scope.container_access = function(access_type,_id,content){
      ApplicationAccess.start(null,$.param({"type":access_type,"id":_id,"content":content}),function(res){
              if(res.status=="success"){
                    alert("操作成功");
                    if(access_type=="delete"){
                        var deleteIndex = -1;
                        for(var i=0;i<$scope.applications.length;i++){
                            if($scope.applications[i]._id == _id){
                                deleteIndex = i;
                            }
                        }
                        if(deleteIndex!=-1)
                            $scope.applications.splice(deleteIndex,1);
                    }
                }else{
                    alert(res.msg);
                }
      },function(e,err){
        alert('请求失败');
      })
    }

    $scope.getContainerInfo = function(_id){
        ApplicationInfo.info(null,$.param({
          "application_id":_id
        }),function(res){
            var run_status = res.data.status;
            var run_info = res.data.logs;
            for(var i=0;i<run_info.length;i++){
                 run_info[i].log = Util.FormatLog(run_info[i].info);
            }
            $scope.application["run_status"] = run_status;
            $scope.application["run_info"] = run_info;
        },function(e,err){
            $scope.application["run_status"] = "抱歉，网络原因无法得知当前状态";
            $scope.application["run_info"] = "抱歉,网络原因无法更新日志";
        });
    }
    // 获取构建日志
    $scope.show_run_logs = function(_id){
      // 获取日志
        for(var i=0;i<$scope.applications.length;i++){
            if($scope.applications[i]._id == _id){
                  $scope.application = $scope.applications[i];
                  $scope.showScope = $scope.showList[2];
                  $scope.getContainerInfo(_id);
            }
        }
    }

    $scope.getContainerLogs = function(_id){
        if($scope.container==null) $interval.cancel($scope.intervalId);

        ApplicationLogs.info(null,$.param({
          "application_id":_id
        }),function(res){
            var logs_status = res.data.status;
            var logs_info = res.data.logs;
            for(var i=0;i<logs_info.length;i++){
                 logs_info[i].log = Util.FormatLog(logs_info[i].info);
            }
            $scope.container["status"] = run_status;
            $scope.container["logs"] = logs_info;
            if(run_status=="success"){
                $interval.cancel($scope.intervalId);
            }
        },function(e,err){
            $interval.cancel($scope.intervalId);
            $scope.container["status"] = "抱歉，网络原因无法得知当前状态";
            $scope.container["logs"] = "抱歉,网络原因无法更新日志";
        });
    }

    // 获取容器日志
    $scope.show_container_logs = function(_id){
      // 获取日志
      $scope.intervalId = $interval(getContainerLogs,3000,_id);
      // 切换视图
      $scope.showScope = $scope.showList[1];
    }
    // 追加交互日志
    $scope.append_exec_logs = function(content){
      if(content==""){
        $scope.exec_logs.push("");
      }else{
        // 和后台进行交互获取日志

        // 将结果呈现在界面上
        $scope.exec_logs.push(content);
      }
    }
    $scope.show_exec = function(_id){
      // 查找application
      var findArr = $scope.applications.filter(function(item,index){
        return item._id==_id;
      });
      if(findArr.length>=1){
        $scope.application = findArr[0];
        // 清空交互日志
        $scope.exec_logs = [];
        // 切换视图
        $scope.showScope = $scope.showList[2];
      }else{
        $window.console.log("没有找到容器");
      }
    }
}]);
<|endoftext|>


<commit_before>/***********************************************
				Platformer Game
				September 2015
***********************************************/

/***********************************************
					Variables
***********************************************/

var canvas = document.getElementById("gameCanvas");
var context = canvas.getContext("2d");

var SCREEN_WIDTH = canvas.width;
var SCREEN_HEIGHT = canvas.height;

// Map related constants
var LAYER_COUNT = 2;
var LAYER_BACKGROUND = 0;
var LAYER_PLATFORMS = 1;

var LAYER_OBJECT_ENEMIES = 2;
var LAYER_OBJECT_TRIGGERS = 3;

var MAP = {tw:60, th:15};
var TILE = 35;
var TILESET_TILE = TILE * 2;
var TILESET_PADDING = 2;
var TILESET_SPACING = 2;
var TILESET_COUNT_X = 14;
var TILESET_COUNT_Y = 14;

// game state constants
var STATE_SPLASH = 0;
var STATE_GAME = 1;
var STATE_GAMEOVER = 2;
var gameState = STATE_SPLASH;

// player speed constants
var PLAYER_SPEED = 1;
var BULLET_SPEED = 6;

 // abitrary choice for 1m
var METER = TILE;
 // very exaggerated gravity (6x)
var GRAVITY = METER * 9.8 * 6;
 // max horizontal speed (10 tiles per second)
var MAXDX = METER * 10;
 // max vertical speed (15 tiles per second)
var MAXDY = METER * 150;
 // horizontal acceleration - take 1/2 second to reach maxdx
var ACCEL = MAXDX * 4;
 // horizontal friction - take 1/6 second to stop from maxdx
var FRICTION = MAXDX * 10;
 // (a large) instantaneous jump impulse
var JUMP = METER * 1500;

// player movement variables
var ENEMY_MAXDX = METER * 5;
var ENEMY_ACCEL = ENEMY_MAXDX * 2;

// player directions
var LEFT = 0;
var RIGHT = 1;

// player animation constants
var ANIM_IDLE_LEFT = 0;
var ANIM_JUMP_LEFT = 1;
var ANIM_WALK_LEFT = 2;
var ANIM_IDLE_RIGHT = 3;
var ANIM_JUMP_RIGHT = 4;
var ANIM_WALK_RIGHT = 5;
var ANIM_SHOOT_LEFT = 6;
var ANIM_SHOOT_RIGHT = 7;
var ANIM_MAX = 8;

// frames per second variables
var fps = 0;
var fpsCount = 0;
var fpsTime = 0;

// sound effects and music
var musicBackground;
var sfxFire;

// Built from classes
var player = new Player();
var keyboard = new Keyboard();

// current level stuff
var currentLevel = level1;
var levelId = 1;

// Object arrays
var bullets = [];
var enemies = [];

/***********************************************
				Delta Time Function
***********************************************/
var startFrameMillis = Date.now();
var endFrameMillis = Date.now();

// Returns the time in seconds since the function was last called
function getDeltaTime()
{
	endFrameMillis = startFrameMillis;
	startFrameMillis = Date.now();

	var deltaTime = (startFrameMillis - endFrameMillis) * 0.001;

	// validate that the delta is within range
	if(deltaTime > 1)
		deltaTime = 1;

	return deltaTime;
}

var cells = []; // the array that holds our simplified collision data
function initialize() {
	for(var layerIdx = 0; layerIdx < LAYER_COUNT; layerIdx++) { // initialize the collision map
		cells[layerIdx] = [];
		var idx = 0;
		for(var y = 0; y < currentLevel.layers[layerIdx].height; y++) {
			cells[layerIdx][y] = [];
			for(var x = 0; x < currentLevel.layers[layerIdx].width; x++) {
				if(currentLevel.layers[layerIdx].data[idx] != 0) {
					// for each tile we find in the layer data, we need to create 4 collisions
					// (because our collision squares are 35x35 but the tile in the
					// level are 70x70)
					cells[layerIdx][y][x] = 1;
					cells[layerIdx][y-1][x] = 1;
					cells[layerIdx][y-1][x+1] = 1;
					cells[layerIdx][y][x+1] = 1;
				}
				else if(cells[layerIdx][y][x] != 1) {
					// if we haven't set this cell's value, then set it to 0 now
					cells[layerIdx][y][x] = 0;
				}
				idx++;
			}
		}
	}

	// add enemies
	idx = 0;
	for(var y = 0; y < currentLevel.layers[LAYER_OBJECT_ENEMIES].height; y++) {
		for(var x = 0; x < currentLevel.layers[LAYER_OBJECT_ENEMIES].width; x++) {
			if(currentLevel.layers[LAYER_OBJECT_ENEMIES].data[idx] != 0) {
				var px = tileToPixel(x);
				var py = tileToPixel(y);
				var e = new Enemy(px, py);
				enemies.push(e);
			}
			idx++;
		}
	}
	// initialize trigger layer in collision map
	cells[LAYER_OBJECT_TRIGGERS] = [];
	idx = 0;
	for(var y = 0; y < currentLevel.layers[LAYER_OBJECT_TRIGGERS].height; y++) {
		cells[LAYER_OBJECT_TRIGGERS][y] = [];
		for(var x = 0; x < currentLevel.layers[LAYER_OBJECT_TRIGGERS].width; x++) {
			if(currentLevel.layers[LAYER_OBJECT_TRIGGERS].data[idx] != 0) {
				cells[LAYER_OBJECT_TRIGGERS][y][x] = 1;
				cells[LAYER_OBJECT_TRIGGERS][y-1][x] = 1;
				cells[LAYER_OBJECT_TRIGGERS][y-1][x+1] = 1;
				cells[LAYER_OBJECT_TRIGGERS][y][x+1] = 1;
			}
			else if(cells[LAYER_OBJECT_TRIGGERS][y][x] != 1) {
				// if we haven't set this cell's value, then set it to 0 now
				cells[LAYER_OBJECT_TRIGGERS][y][x] = 0;
			}
			idx++;
		}
	}

	// sound objects using howl library
	musicBackground = new Howl(
	{
		urls: ["sound/background.ogg"],
		loop: true,
		buffer: true,
		volume: 0.5
	} );
		musicBackground.play();
		sfxFire = new Howl(
	{
		urls: ["sound/fireEffect.ogg"],
		buffer: true,
		volume: 1,
		onend: function() {
		isSfxPlaying = false;
	}
	} );

}

/***********************************************
				Main Function
				Run at 60 FPS
***********************************************/

function main()
{
	context.fillStyle = "#ccc";
	context.fillRect(0, 0, canvas.width, canvas.height);

	var deltaTime = getDeltaTime();

	switch(gameState) {
		case STATE_SPLASH:
			runSplash(deltaTime);
			break;
		case STATE_GAME:
			runGame(deltaTime);
			break;
		case STATE_GAMEOVER:
			runGameOver(deltaTime);
			break;
	}
	drawFPS(deltaTime)
}

initialize();

/***********************************************
					Reset Game
***********************************************/
function resetGame() {
	var gameState = STATE_SPLASH;
}

/***********************************************
					Framework
***********************************************/
(function() {
  var onEachFrame;
  if (window.requestAnimationFrame) {
    onEachFrame = function(cb) {
      var _cb = function() { cb(); window.requestAnimationFrame(_cb); }
      _cb();
    };
  } else if (window.mozRequestAnimationFrame) {
    onEachFrame = function(cb) {
      var _cb = function() { cb(); window.mozRequestAnimationFrame(_cb); }
      _cb();
    };
  } else {
    onEachFrame = function(cb) {
      setInterval(cb, 1000 / 60);
    }
  }

  window.onEachFrame = onEachFrame;
})();

window.onEachFrame(main);
<commit_msg>added a few comments<commit_after>/***********************************************
				Platformer Game
				September 2015
***********************************************/

/***********************************************
					Variables
***********************************************/

var canvas = document.getElementById("gameCanvas");
var context = canvas.getContext("2d");

var SCREEN_WIDTH = canvas.width;
var SCREEN_HEIGHT = canvas.height;

// Map related constants
var LAYER_COUNT = 2;
var LAYER_BACKGROUND = 0;
var LAYER_PLATFORMS = 1;

var LAYER_OBJECT_ENEMIES = 2;
var LAYER_OBJECT_TRIGGERS = 3;

var MAP = {tw:60, th:15};
var TILE = 35;
var TILESET_TILE = TILE * 2;
var TILESET_PADDING = 2;
var TILESET_SPACING = 2;
var TILESET_COUNT_X = 14;
var TILESET_COUNT_Y = 14;

// game state constants
var STATE_SPLASH = 0;
var STATE_GAME = 1;
var STATE_GAMEOVER = 2;
var gameState = STATE_SPLASH;

// player speed constants
var PLAYER_SPEED = 1;
var BULLET_SPEED = 6;

 // abitrary choice for 1m
var METER = TILE;
 // very exaggerated gravity (6x)
var GRAVITY = METER * 9.8 * 6;
 // max horizontal speed (10 tiles per second)
var MAXDX = METER * 10;
 // max vertical speed (15 tiles per second)
var MAXDY = METER * 150;
 // horizontal acceleration - take 1/2 second to reach maxdx
var ACCEL = MAXDX * 4;
 // horizontal friction - take 1/6 second to stop from maxdx
var FRICTION = MAXDX * 10;
 // (a large) instantaneous jump impulse
var JUMP = METER * 1500;

// player movement variables
var ENEMY_MAXDX = METER * 5;
var ENEMY_ACCEL = ENEMY_MAXDX * 2;

// player directions
var LEFT = 0;
var RIGHT = 1;

// player animation constants
var ANIM_IDLE_LEFT = 0;
var ANIM_JUMP_LEFT = 1;
var ANIM_WALK_LEFT = 2;
var ANIM_IDLE_RIGHT = 3;
var ANIM_JUMP_RIGHT = 4;
var ANIM_WALK_RIGHT = 5;
var ANIM_SHOOT_LEFT = 6;
var ANIM_SHOOT_RIGHT = 7;
var ANIM_MAX = 8;

// frames per second variables
var fps = 0;
var fpsCount = 0;
var fpsTime = 0;

// sound effects and music
var musicBackground;
var sfxFire;

// Built from classes
var player = new Player();
var keyboard = new Keyboard();

// current level stuff
var currentLevel = level1;
var levelId = 1;

// Object arrays
var bullets = [];
var enemies = [];

/***********************************************
				Delta Time Function
***********************************************/
var startFrameMillis = Date.now();
var endFrameMillis = Date.now();

// Returns the time in seconds since the function was last called
function getDeltaTime()
{
	endFrameMillis = startFrameMillis;
	startFrameMillis = Date.now();

	var deltaTime = (startFrameMillis - endFrameMillis) * 0.001;

	// validate that the delta is within range
	if(deltaTime > 1)
		deltaTime = 1;

	return deltaTime;
}

/***********************************************
				Initialisation
***********************************************/

var cells = []; // the array that holds our simplified collision data
function initialize() {
	for(var layerIdx = 0; layerIdx < LAYER_COUNT; layerIdx++) { // initialize the collision map
		cells[layerIdx] = [];
		var idx = 0;
		for(var y = 0; y < currentLevel.layers[layerIdx].height; y++) {
			cells[layerIdx][y] = [];
			for(var x = 0; x < currentLevel.layers[layerIdx].width; x++) {
				if(currentLevel.layers[layerIdx].data[idx] != 0) {
					// for each tile we find in the layer data, we need to create 4 collisions
					// (because our collision squares are 35x35 but the tile in the
					// level are 70x70)
					cells[layerIdx][y][x] = 1;
					cells[layerIdx][y-1][x] = 1;
					cells[layerIdx][y-1][x+1] = 1;
					cells[layerIdx][y][x+1] = 1;
				}
				else if(cells[layerIdx][y][x] != 1) {
					// if we haven't set this cell's value, then set it to 0 now
					cells[layerIdx][y][x] = 0;
				}
				idx++;
			}
		}
	}

	// add enemies
	idx = 0;
	for(var y = 0; y < currentLevel.layers[LAYER_OBJECT_ENEMIES].height; y++) {
		for(var x = 0; x < currentLevel.layers[LAYER_OBJECT_ENEMIES].width; x++) {
			if(currentLevel.layers[LAYER_OBJECT_ENEMIES].data[idx] != 0) {
				var px = tileToPixel(x);
				var py = tileToPixel(y);
				var e = new Enemy(px, py);
				enemies.push(e);
			}
			idx++;
		}
	}
	// initialize trigger layer in collision map
	cells[LAYER_OBJECT_TRIGGERS] = [];
	idx = 0;
	for(var y = 0; y < currentLevel.layers[LAYER_OBJECT_TRIGGERS].height; y++) {
		cells[LAYER_OBJECT_TRIGGERS][y] = [];
		for(var x = 0; x < currentLevel.layers[LAYER_OBJECT_TRIGGERS].width; x++) {
			if(currentLevel.layers[LAYER_OBJECT_TRIGGERS].data[idx] != 0) {
				cells[LAYER_OBJECT_TRIGGERS][y][x] = 1;
				cells[LAYER_OBJECT_TRIGGERS][y-1][x] = 1;
				cells[LAYER_OBJECT_TRIGGERS][y-1][x+1] = 1;
				cells[LAYER_OBJECT_TRIGGERS][y][x+1] = 1;
			}
			else if(cells[LAYER_OBJECT_TRIGGERS][y][x] != 1) {
				// if we haven't set this cell's value, then set it to 0 now
				cells[LAYER_OBJECT_TRIGGERS][y][x] = 0;
			}
			idx++;
		}
	}

	/***********************************************
						Howl Sounds
	***********************************************/
	musicBackground = new Howl(
	{
		urls: ["sound/background.ogg"],
		loop: true,
		buffer: true,
		volume: 0.5
	} );
		musicBackground.play();
		sfxFire = new Howl(
	{
		urls: ["sound/fireEffect.ogg"],
		buffer: true,
		volume: 1,
		onend: function() {
		isSfxPlaying = false;
	}
	} );

}

/***********************************************
				Main Function
				Run at 60 FPS
***********************************************/

function main()
{
	context.fillStyle = "#ccc";
	context.fillRect(0, 0, canvas.width, canvas.height);

	var deltaTime = getDeltaTime();

	switch(gameState) {
		case STATE_SPLASH:
			runSplash(deltaTime);
			break;
		case STATE_GAME:
			runGame(deltaTime);
			break;
		case STATE_GAMEOVER:
			runGameOver(deltaTime);
			break;
	}
	drawFPS(deltaTime)
}

initialize();

/***********************************************
					Reset Game
***********************************************/
function resetGame() {
	var gameState = STATE_SPLASH;
}

/***********************************************
					Framework
***********************************************/
(function() {
  var onEachFrame;
  if (window.requestAnimationFrame) {
    onEachFrame = function(cb) {
      var _cb = function() { cb(); window.requestAnimationFrame(_cb); }
      _cb();
    };
  } else if (window.mozRequestAnimationFrame) {
    onEachFrame = function(cb) {
      var _cb = function() { cb(); window.mozRequestAnimationFrame(_cb); }
      _cb();
    };
  } else {
    onEachFrame = function(cb) {
      setInterval(cb, 1000 / 60);
    }
  }

  window.onEachFrame = onEachFrame;
})();

window.onEachFrame(main);
<|endoftext|>