/** @jsx React.DOM */ /* scrumli --- A simple scrum web application Copyright (C) 2013 Tom Willemse scrumli is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. scrumli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with scrumli. If not, see . */ var StateIcon = React.createClass({ render: function() { var icon_names = {"TODO": "icon-check-empty", "DOING": "icon-sign-blank", "DONE": "icon-check"}; return ; } }); var AssigneeIcon = React.createClass({ render: function() { var icon; if (this.props.assignee) icon = {this.props.assignee}; else icon = ; return icon; } }); var StoryTaskRow = React.createClass({ changeState: React.autoBind(function(event) { $.post("/tasks/state", {'id': this.props.task.id}) .done(function (data, textStatus, jqXHR) { if (data.status == "ok") this.setState({state: data.state}); }.bind(this)); }), getInitialState: function () { return {state: this.props.task.state}; }, moveUp: React.autoBind(function(event) { $.post("/tasks/up", {'id': this.props.task.id}) .done(function (data) { if (data.status == "ok") this.props.onMoved(1); }.bind(this)); }), moveDown: React.autoBind(function(event) { $.post("/tasks/down", {'id': this.props.task.id}) .done(function (data) { if (data.status == "ok") this.props.onMoved(-1); }.bind(this)); }), handleAssigneeClick: React.autoBind(function(event) { this.props.onAssigneeClicked({url: "/tasks/assignee", id: this.props.task.id, assignee: this.props.task.assignee, md5: this.props.task.md5}); }), render: function() { return ( {" "} {this.state.state} {this.props.task.description} ); } }); var StoryTaskTable = React.createClass({ render: function() { var taskNodes = this.props.tasks.map(function (task) { return ; }.bind(this)); return ( {taskNodes}
); } }); var StoryTaskForm = React.createClass({ handleSubmit: React.autoBind(function() { var text = this.refs.text.getDOMNode().value.trim(); this.props.onTaskSubmit({description: text}); this.refs.text.getDOMNode().value = ''; return false; }), render: function() { return (
New task
); } }); var StoryData = React.createClass({ handleTaskSubmit: React.autoBind(function (task) { task.storyId = this.state.data.id; $.post("/stories/tasks/new", task) .done(function(data) { if (data.status == "ok") this.loadStoryFromServer(); }.bind(this)); }), loadStoryFromServer: function() { $.get("/stories/" + this.state.data.id) .done(this.setData.bind(this)); }, componentWillMount: function() { setInterval( this.loadStoryFromServer.bind(this), this.props.pollInterval ); }, getInitialState: function() { return {data: null}; }, setData: function(data) { this.setState({data: null}); this.setState({data: data}); }, handleTaskMoved: React.autoBind(function(direction) { this.loadStoryFromServer(); }), render: function() { if (this.state.data) { return (

{this.state.data.title}

{this.state.data.content}
); } return
; } }); var StoryRow = React.createClass({ handleAssigneeClick: React.autoBind(function(event) { this.props.onAssigneeClicked({url: "/story/assignee", id: this.props.story.id, assignee: this.props.story.assignee, md5: this.props.story.md5}); }), render: function() { return ( {" "} {this.state.state} As a {this.props.story.role}, I {this.props.story.necessity} to {this.props.story.title} ); }, getInitialState: function() { return {state: this.props.story.state, content: null}; }, handleClick: React.autoBind(function(event) { this.props.onTitleClicked(this.props.story.id); }), changeState: React.autoBind(function(event) { $.post("/stories/state", {'id': this.props.story.id}) .done(function(data, textStatus, jqXHR) { if (data.status == "ok") this.setState({state: data.state}); }.bind(this)); }), moveUp: React.autoBind(function(event) { $.post("/stories/up", {'id': this.props.story.id}) .done(function (data, textStatus, jqXHR) { if (data.status == "ok") this.props.onMoved(1); }.bind(this)); }), moveDown: React.autoBind(function(event) { $.post("/stories/down", {'id': this.props.story.id}) .done(function (data) { if (data.status == "ok") this.props.onMoved(-1); }.bind(this)); }) }); var StoryTable = React.createClass({ render: function() { var storyNodes = this.props.data.map(function (story) { return ; }.bind(this)); return ( {storyNodes}
); } }); var AssignmentForm = React.createClass({ handleChanged: React.autoBind(function() { var assignee = this.refs.assignee.getDOMNode().value; $.post(this.state.url, {id: this.state.id, assignee: assignee}) .done(function (data) { if (data.status == "ok") { this.refs.assignee.getDOMNode().value = ''; $(".assignModal").modal('hide'); } }.bind(this)); }), setInfo: React.autoBind(function(info) { this.setState(info); }), getInitialState: function () { return {id: 0, assignee: "", url: "", md5: ""}; }, render: function() { return ( ); } }); var StoryForm = React.createClass({ handleSubmit: React.autoBind(function() { var role = this.refs.role.getDOMNode().value.trim(); var necessity = this.refs.necessity.getDOMNode().value.trim(); var headline = this.refs.headline.getDOMNode().value.trim(); var content = this.refs.content.getDOMNode().value.trim(); $(".newTaskModal").modal('hide'); this.props.onStorySubmit({role: role, necessity: necessity, headline: headline, content: content}); this.refs.role.getDOMNode().value = ''; this.refs.necessity.getDOMNode().value = ''; this.refs.headline.getDOMNode().value = ''; this.refs.content.getDOMNode().value = ''; return false; }), render: function() { return ( ); } }); var StoryPage = React.createClass({ loadStoriesFromServer: function() { $.get(this.state.url) .done(function(data) { this.setState({data: []}); this.setState({data: data}); }.bind(this)); }, getInitialState: function() { return {data: [], url: this.props.url}; }, setUrl: React.autoBind(function(url) { this.setState({url: url}); }), componentWillMount: function() { this.loadStoriesFromServer(); setInterval( this.loadStoriesFromServer.bind(this), this.props.pollInterval ); }, handleStoryMoved: React.autoBind(function (direction) { this.loadStoriesFromServer(); }), handleStorySubmit: React.autoBind(function (story) { $.post("/stories/new", story) .done(function (data, textStatus, jqXHR) { if (data.status == "ok") this.loadStoriesFromServer(); }.bind(this)) .fail(function (jqXHR, textStatus, errorThrown) { alert("error: " + errorThrown); }.bind(this)); }), handleStorySelected: React.autoBind(function (storyId) { $.get('/stories/' + storyId) .done(function (data, textStatus, jqXHR) { this.refs.data.setData(data); }.bind(this), 'json'); }), handleAssigneeClicked: React.autoBind(function (info) { var form = this.refs.assignmentForm; form.setInfo(info); $(".assignModal").modal(); }), render: function() { return (
); } }); var StoryFilter = React.createClass({ getInitialState: function() { return {filter: 'all'}; }, handleClick: React.autoBind(function(event) { this.setState({filter: (this.state.filter != 'all' ? 'all' : 'user')}); scrumli_page.setUrl((this.state.filter == "all" ? "/stories" : "/stories/mine")); }), render: function() { var classes = {all: ['icon-group', 'All'], user: ['icon-user', 'Mine']}; return ( {" "} {classes[this.state.filter][1]} ); } }); var scrumli_page = ; React.renderComponent( scrumli_page, document.getElementById('content') ); React.renderComponent( , document.getElementById('filter') );