Dependency Mapper

by Robodude

HTML

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css">
Steps to recreate this setup:<br>
<image src="http://i.imgur.com/r3sSd5V.png">
<ol>
    <li>From the 'Release List' select 'Release 3'</li>
    <li>In the 'Comes Before' dropdown menu select 'Release 1' and click '+'</li>
    <li>In the 'Comes Before' dropdown menu select 'Release 2' and click '+'</li>
    <li>In the 'Comes After' dropdown menu select 'Release 4' and click '+'</li>
    <li>In the 'Comes After' dropdown menu select 'Release 6' and click '+'</li>
    <li>In the 'Comes After' list (not the dropdown), click 'Release 4'</li>
    <li>In the 'Comes After' dropdown menu select 'Release 5' and click '+'</li>
    <li>In the 'Release List' click on each release and confirm structure.</li>
</ol>
    

<hr>
<table>
    <thead>
        <tr>
            <th>Release List</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: releases">
        <tr data-bind="click: $root.select">
            <td data-bind="text: name"></td>
        </tr>    
    </tbody>
</table>
<br>
<br>
    
<div class="before dependency">
    Comes Before<br>
<select data-bind="options: $root.releases, value: beforeAdd, optionsText: 'name'"></select>
    <button data-bind="click: $root.fnAddBefore, disable: $root.selected() == null">+</button></hr>
<div data-bind="with: $root.selected() ">
    <div data-bind="foreach: before()">
        <div class="release">
            <span data-bind="text: name, click: $root.select"></span>
            <button data-bind="click: $root.fnRemoveBefore">-</button>
        </div>

    </div>
</div>
</div>

<div data-bind="with: $root.selected()">
    <div class="cur dependency" data-bind="text: name"></div>
</div>
    
<div class="after dependency">
    Comes...

CSS

body {
    font-family: Monospace;
}
h3{
    float: left;
}
table{
    float: left;
}
.dependency {
    float:left;
    border: 1px solid black;
}
.release {
    border: 1px solid black;
}

JavaScript

function Release(options) {
    var self = this;
    self.id = options.id;
    self.name = options.name;
    self.before = ko.observableArray(options.before);
    self.after = ko.observableArray(options.after);
}

function RoadViewModel() {
    var self = this;

    self.selected = ko.observable();
    
    self.beforeAdd = ko.observable();
    self.afterAdd = ko.observable();
    
    // Editable data
    self.releases = ko.observableArray([
        new Release({id: 1, name: "Release 1", before: [], after: []}),
        new Release({id: 2, name: "Release 2", before: [], after: []}),
        new Release({id: 3, name: "Release 3", before: [], after: []}),
        new Release({id: 4, name: "Release 4", before: [], after: []}),
        new Release({id: 5, name: "Release 5", before: [], after: []}),
        new Release({id: 6, name: "Release 6", before: [], after: []})
    ]);
    
    self.select = function(data){
        self.selected(data);
    }
    self.fnAddBefore = function(){
        self.selected().before.push(self.beforeAdd());
        self.beforeAdd().after().push(self.selected());
    }    
    self.fnAddAfter = function(){
        self.selected().after.push(self.afterAdd());
        self.afterAdd().before.push(self.selected());
    }
    self.fnRemoveAfter = function(data){
        self.selected().after.remove(data);
    }
    self.fnRemoveBefore = function(data){
        self.selected().before.remove(data);
    }
}

ko.applyBindings(new RoadViewModel());