aboutsummaryrefslogtreecommitdiff
path: root/tools/gui/resources
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gui/resources')
-rw-r--r--tools/gui/resources/web/definitions.js223
-rw-r--r--tools/gui/resources/web/index.html52
-rw-r--r--tools/gui/resources/web/main.js150
-rw-r--r--tools/gui/resources/web/styles.css75
4 files changed, 378 insertions, 122 deletions
diff --git a/tools/gui/resources/web/definitions.js b/tools/gui/resources/web/definitions.js
new file mode 100644
index 0000000..d1313d4
--- /dev/null
+++ b/tools/gui/resources/web/definitions.js
@@ -0,0 +1,223 @@
+function ajax(url, data, method) {
+ let f = method == "post" ? $.post : $.get;
+ return f("/api" + url, data).fail(e =>
+ Notifications.showFail(e)
+ );
+}
+
+function getFlags() {
+ return "readme/" + $("#readme-flag")[0].checked
+ + " dotty/" + $("#dotty-flag")[0].checked
+ + " uberJar/" + $("#uberJar-flag")[0].checked
+ + " wartremover/" + $("#wartremover-flag")[0].checked;
+}
+
+let ProjectLocation = {
+ _base: "",
+
+ init: function (container, nameInput) {
+ this._container = container;
+ nameInput.keyup(function () {
+ ProjectLocation.updateName(this.value);
+ });
+ ajax("/cwd").done(path => {
+ ProjectLocation._container.append(path[0]);
+ ProjectLocation._base = ProjectLocation._container.html();
+ });
+ },
+
+ updateName: function (x) {
+ this._container.html(this._base + (x ? "/" + x : ""));
+ }
+};
+
+let Popup = {
+ init: function (container, table) {
+ this._container = container;
+ this._table = table;
+ document.body.onkeydown = function (event) {
+ if (event.keyCode == 27)
+ Popup.hide();
+ };
+ },
+
+ show: function (contents) {
+ this._container.show();
+ this._table.html(contents);
+ },
+
+ hide: function () {
+ this._container.hide();
+ this._table.html("");
+ }
+};
+
+let Notifications = {
+ init: function () {
+ Notification.requestPermission();
+ },
+
+ show: function (text, title) {
+ new Notification(title || "", {body: text});
+ },
+
+ showFail: function (e) {
+ let head = e.status == 0 ? "Error" : e.status + " " + e.statusText;
+ let body = e.status == 0 ? "No response from UI server." : e.responseText;
+ this.show(body, head);
+ }
+};
+
+let Dependencies = {
+ _list: [],
+
+ init: function (searchBtn, queryInput, dependenciesNode) {
+ this._queryInput = queryInput;
+ queryInput.keyup(function handleSearchInput(event) {
+ if (event.keyCode == 13)
+ Dependencies.search();
+ });
+ this._dependenciesNode = dependenciesNode;
+ },
+
+ serialize: function () {
+ return this._list.length == 0 ? "" :
+ this._list.map(l => l.group + "/" + l.artifact + "/" + l.version).reduce((a, b) => a + " " + b);
+ },
+
+ search: function () {
+ let query = this._queryInput.val();
+ if (query) {
+ ajax("/dependency", {query: query}).done(data => {
+ let entries = data.response.docs.map(x => ({
+ group: x.g,
+ artifact: x.a
+ }));
+ Popup.show(Dependencies._makeRowsFrom(entries, Dependencies.selectDependency));
+ });
+ document.activeElement.blur();
+ }
+ },
+
+ selectDependency: function (selected) {
+ ajax("/dependency/version", {group: selected.group, artifact: selected.artifact}).done(data => {
+ let versions = data.response.docs.map(x => ({version: x.v}));
+ Popup.show(Dependencies._makeRowsFrom(versions, function (version) {
+ Dependencies.selectDependencyVersion(selected.group, selected.artifact, version.version);
+ }));
+ });
+ },
+
+ selectDependencyVersion: function (group, artifact, version) {
+ let dependency = {group: group, artifact: artifact, version: version};
+ this._list.push(dependency);
+ let scalaName = artifact.match(/^(.+)_\d+\.\d+$/);
+ let name = scalaName && scalaName[1] ? scalaName[1] : artifact;
+ let depDiv = $("<div class='entry removable'>" + name + " " + version + "</div>");
+ depDiv.click(function () {
+ Dependencies.removeDependency(dependency, depDiv);
+ });
+ this._dependenciesNode.append(depDiv);
+ Popup.hide();
+ },
+
+ removeDependency: function (d, div) {
+ this._list.splice(this._list.indexOf(d), 1);
+ div.remove();
+ },
+
+ _makeRowsFrom: function (results, rowAction) {
+ if (results.length == 0) {
+ return [];
+ } else {
+ let rows = [];
+ let row = $("<tr></tr>");
+ rows.push(row);
+ let fields = [];
+ for (let field in results[0])
+ if (results[0].hasOwnProperty(field)) {
+ fields.push(field);
+ $("<td>" + field + "</td>").appendTo(row);
+ }
+ results.forEach(result => {
+ let row = $("<tr></tr>");
+ row.click(function () {
+ rowAction(result);
+ });
+ rows.push(row);
+ fields.forEach(field => $("<td>" + result[field] + "</td>").appendTo(row));
+ });
+ return rows;
+ }
+ }
+};
+
+let Examples = {
+ fetchExamples: () => {
+ let examplesContainer = $("#examples");
+ examplesContainer.html("");
+ ajax("/examples").done(data => {
+ data.forEach(name => {
+ var example = $("<div class='link-btn'>" + name + "</div>");
+ example.click(() => Examples.selectExample(name));
+ example.appendTo(examplesContainer);
+ });
+ });
+ },
+
+ selectExample: name => {
+ $("#examples-title").hide();
+ let selectedExample = $("#selected-example");
+ selectedExample.html(name);
+ selectedExample.show();
+ ProjectLocation.updateName(name);
+ $("#examples").hide();
+ $("#example-browser").show();
+ $("#copy-project-btn").show();
+
+ Examples._fetchExampleFiles(name);
+ },
+
+ unselectExample: () => {
+ $("#examples-title").show();
+ $("#selected-example").hide();
+ ProjectLocation.updateName("");
+ $("#examples").show();
+ $("#example-browser").hide();
+ $("#copy-project-btn").hide();
+ $("#code-browser").hide();
+ },
+
+ _fetchExampleFiles: name => {
+ let fileBrowser = $("#file-browser");
+ fileBrowser.html("");
+ ajax("/example/files", {name: name}).done(data => {
+ Examples._appendTree(data, fileBrowser, 0);
+ });
+ },
+
+ selectedFileNode: null,
+
+ _appendTree: function (node, parent, dirDepth) {
+ let div = $("<div class='browser-node'>" + node.name + "</div>");
+ div.appendTo(parent);
+ if (dirDepth % 2 == 0)
+ div.addClass("even-node");
+ if (node.children) {
+ node.children.forEach(x => Examples._appendTree(x, div, dirDepth + 1));
+ } else {
+ div.addClass("file-node");
+ div.click(() => {
+ if (Examples.selectedFileNode)
+ Examples.selectedFileNode.removeClass("selected-node");
+ Examples.selectedFileNode = div;
+ Examples.selectedFileNode.addClass("selected-node");
+ ajax("/example/file", {path: node.path}).done(data => {
+ var codeBrowser = $("#code-browser");
+ codeBrowser.show();
+ codeBrowser.html(data);
+ });
+ });
+ }
+ }
+};
diff --git a/tools/gui/resources/web/index.html b/tools/gui/resources/web/index.html
index 9ad45a5..100c65b 100644
--- a/tools/gui/resources/web/index.html
+++ b/tools/gui/resources/web/index.html
@@ -10,33 +10,57 @@
</head>
<body>
<div id="popup">
- <div onclick="hidePopup()">×</div>
+ <div class="stroke" onclick="Popup.hide()">×</div>
<table id="popup-table"></table>
</div>
<div class="container">
<h1>CBT bootstrap</h1>
- <div id="cwd" class="entry"><span>current dir:</span> </div>
- <div class="entry"><input type="text" id="name" placeholder="project name"></div>
- <div class="entry"><input type="text" id="package" placeholder="default package"></div>
+ <button class="small-btn" onclick="setFlowCreate()" id="flow-create-btn">create from scratch</button>
+ or
+ <button class="small-btn" onclick="setFlowCopy()" id="flow-copy-btn">copy an example</button>
<hr>
- <div class="entry"><input type="text" id="query" placeholder="add maven dependency" onkeyup="handleSearchInput(event)"></div>
- <button class="small-btn" onclick="search()">search</button>
- <div id="dependencies"></div>
- <hr>
+ <div id="cwd" class="entry"><span>project location:</span> </div>
- <input type="checkbox" id="readme-flag"><label for="readme-flag">readme.md</label>
- <input type="checkbox" id="dotty-flag"><label for="dotty-flag">dotty</label>
- <input type="checkbox" id="uberJar-flag"><label for="uberJar-flag">uber jar</label>
- <input type="checkbox" id="wartremover-flag"><label for="wartremover-flag">wartremover</label>
- <hr>
+ <div id="flow-create">
+ <div class="entry"><input type="text" id="name" placeholder="project name"></div>
+ <div class="entry"><input type="text" id="package" placeholder="default package"></div>
+ <hr>
+
+ <div class="entry"><input type="text" id="query" placeholder="add maven dependency"></div>
+ <button class="small-btn" onclick="Dependencies.search()" id="search-btn">search</button>
+ <div id="dependencies"></div>
+ <hr>
+
+ <input type="checkbox" id="readme-flag"><label for="readme-flag">readme.md</label>
+ <input type="checkbox" id="dotty-flag"><label for="dotty-flag">dotty</label>
+ <input type="checkbox" id="uberJar-flag"><label for="uberJar-flag">uber jar</label>
+ <input type="checkbox" id="wartremover-flag"><label for="wartremover-flag">wartremover</label>
+ <hr>
+
+ <button id="create-project-btn" onclick="createProject()">create project</button>
+ </div>
- <button id="create-project" onclick="createProject()">create project</button>
+ <div id="flow-copy">
+ <span class="entry">
+ <span id="examples-title">select an example:</span>
+ <span class="removable" id="selected-example" onclick="Examples.unselectExample()"></span>
+ </span>
+ <hr>
+ <div id="examples"></div>
+ <div id="example-browser">
+ <div id="file-browser"></div>
+ <pre id="code-browser"><code></code></pre>
+ </div>
+ <hr>
+ <button id="copy-project-btn" onclick="copyProject()">copy example</button>
+ </div>
</div>
<script src="jquery-3.1.1.min.js"></script>
+<script src="definitions.js"></script>
<script src="main.js"></script>
</body>
</html>
diff --git a/tools/gui/resources/web/main.js b/tools/gui/resources/web/main.js
index b4fe38b..139795a 100644
--- a/tools/gui/resources/web/main.js
+++ b/tools/gui/resources/web/main.js
@@ -1,129 +1,73 @@
-Notification.requestPermission();
+Notifications.init();
-$.get("/api/cwd").done(cwd => {
- $("#cwd").append(cwd[0]);
-}).fail(e => notifyFail(e));
+Popup.init($("#popup"), $("#popup-table"));
-document.body.onkeydown = function (event) {
- if (event.keyCode == 27)
- hidePopup();
-};
+Dependencies.init($("#search-btn"), $("#query"), $("#dependencies"));
-$("#create-project")[0].disabled = false;
+ProjectLocation.init($("#cwd"), $("#name"));
-let dependencies = [];
+["#create-project-btn", "#copy-project-btn", "#flow-create-btn", "#flow-copy-btn"].forEach(id => $(id)[0].disabled = false);
-function getFlags() {
- return "readme/" + $("#readme-flag")[0].checked
- + " dotty/" + $("#dotty-flag")[0].checked
- + " uberJar/" + $("#uberJar-flag")[0].checked
- + " wartremover/" + $("#wartremover-flag")[0].checked;
+$("#flow-copy-btn")[0].style.width = $("#flow-create-btn")[0].offsetWidth + "px";
+
+function setFlowCreate() {
+ $("#flow-create").show();
+ $("#flow-copy").hide();
+
+ let createBtn = $("#flow-create-btn");
+ let copyBtn = $("#flow-copy-btn");
+ createBtn.blur();
+ createBtn[0].disabled = true;
+ copyBtn[0].disabled = false;
+
+ ProjectLocation.updateName($("#name").val());
}
function createProject() {
- let button = $("#create-project")[0];
+ let button = $("#create-project-btn")[0];
let buttonText = button.innerHTML;
button.innerHTML = "...";
button.blur();
button.disabled = true;
- $.post("/api/project", {
+ ajax("/project/new", {
name: $("#name").val(),
pack: $("#package").val(),
- dependencies: dependencies.length == 0 ? "" :
- dependencies.map(l => l.group + "/" + l.artifact + "/" + l.version).reduce((a, b) => a + " " + b),
+ dependencies: Dependencies.serialize(),
flags: getFlags()
- }).done(() => {
- notify("Done.");
- }).fail(e =>
- notifyFail(e)
- ).always(() => {
+ }, "post").done(() => {
+ Notifications.show("Done.");
+ }).always(() => {
button.innerHTML = buttonText;
button.disabled = false;
});
}
-function handleSearchInput(event) {
- if (event.keyCode == 13)
- search();
-}
-function search() {
- let query = $("#query").val();
- if (query) {
- $.get("/api/dependency", { query: query }).done(data => {
- let entries = data.response.docs.map(x => ({
- group: x.g,
- artifact: x.a
- }));
- showPopup(makeRowsFrom(entries, selectDependency));
- }).fail(e => notifyFail(e));
- document.activeElement.blur();
- }
-}
-function selectDependency(selected) {
- $.get("/api/dependency/version", { group: selected.group, artifact: selected.artifact }).done(data => {
- let versions = data.response.docs.map(x => ({ version: x.v }));
- $("#popup-table").html(makeRowsFrom(versions, function (version) {
- selectDependencyVersion(selected.group, selected.artifact, version.version);
- }));
- }).fail(e => notifyFail(e));
-}
-function selectDependencyVersion(group, artifact, version) {
- let dependency = { group: group, artifact: artifact, version: version };
- dependencies.push(dependency);
- let scalaName = artifact.match(/^(.+)_\d+\.\d+$/);
- let name = scalaName && scalaName[1] ? scalaName[1] : artifact;
- var depDiv = $("<div class='entry removable'>" + name + " " + version + "</div>");
- depDiv.click(function () {
- removeDependency(dependency, depDiv);
- });
- $("#dependencies").append(depDiv);
- hidePopup();
-}
-function removeDependency(d, div) {
- dependencies.splice(dependencies.indexOf(d), 1);
- div.remove();
-}
+function setFlowCopy() {
+ $("#flow-copy").show();
+ $("#flow-create").hide();
-function showPopup(contents) {
- $("#popup").show();
- $("#popup-table").html(contents);
-}
-function hidePopup() {
- $("#popup").hide();
- $("#popup-table").html("");
-}
+ let createBtn = $("#flow-create-btn");
+ let copyBtn = $("#flow-copy-btn");
+ copyBtn.blur();
+ copyBtn[0].disabled = true;
+ createBtn[0].disabled = false;
-function makeRowsFrom(results, rowAction) {
- if (results.length == 0) {
- return [];
- } else {
- let rows = [];
- let row = $("<tr></tr>");
- rows.push(row);
- let fields = [];
- for (let field in results[0])
- if (results[0].hasOwnProperty(field)) {
- fields.push(field);
- $("<td>" + field + "</td>").appendTo(row);
- }
- results.forEach(result => {
- let row = $("<tr></tr>");
- row.click(function () {
- rowAction(result);
- });
- rows.push(row);
- fields.forEach(field => $("<td>" + result[field] + "</td>").appendTo(row));
- });
- return rows;
- }
-}
+ Examples.unselectExample();
-function notify(text, title) {
- new Notification(title || "", { body: text });
+ Examples.fetchExamples();
}
-function notifyFail(e) {
- let head = e.status == 0 ? "Error" : e.status + " " + e.statusText;
- let body = e.status == 0 ? "No response from UI server." : e.responseText;
- notify(body, head);
+function copyProject() {
+ let name = $("#selected-example").html();
+ let button = $("#copy-project-btn")[0];
+ let buttonText = button.innerHTML;
+ button.innerHTML = "...";
+ button.blur();
+ button.disabled = true;
+ ajax("/project/copy", {name: name}, "post").done(() => {
+ Notifications.show("Done.");
+ }).always(() => {
+ button.innerHTML = buttonText;
+ button.disabled = false;
+ });
}
diff --git a/tools/gui/resources/web/styles.css b/tools/gui/resources/web/styles.css
index 6aa45e9..759dd06 100644
--- a/tools/gui/resources/web/styles.css
+++ b/tools/gui/resources/web/styles.css
@@ -30,12 +30,16 @@ hr {
border-bottom: transparent solid 1px;
}
+pre {
+ margin: 0 0 1em 0;
+}
+
button, .small-btn {
background: #dc322f;
color: #fff;
font-size: 1em;
padding: 0.2em;
- border: transparent solid 0.1em;
+ border: none;
border-radius: 1em;
text-transform: uppercase;
cursor: pointer;
@@ -47,9 +51,14 @@ button, .small-btn {
padding: 0 1em;
}
+.link-btn:hover {
+ color: #dc322f;
+ cursor: pointer;
+}
+
button:hover {
- background: #073642;
- border: #fff solid 0.1em;
+ background: #fff;
+ color: #002B36;
}
button:active {
@@ -57,7 +66,8 @@ button:active {
}
button:disabled {
- background: transparent;
+ background: #073642;
+ color: #fff;
cursor: default;
}
@@ -66,6 +76,7 @@ input[type="text"] {
color: #fff;
border: none;
width: 33%;
+ min-width: 15em;
font-size: 1em;
}
@@ -115,6 +126,10 @@ input[type="checkbox"]:checked + label:after {
border-color: #dc322f;
}
+.stroke {
+ text-shadow: 0 1px 0 #002B36, 0 -1px 0 #002B36, 1px 0 0 #002B36, -1px 0 0 #002B36;
+}
+
.container {
margin: 0 8%;
text-align: center;
@@ -138,10 +153,11 @@ button, .entry {
left: 0;
right: 0;
margin: 0 auto;
+ border: #002B36 solid 0.5em;
background: #073642;
width: 84%;
max-height: 80%;
- overflow-y: scroll;
+ overflow-y: auto;
text-align: center;
display: none;
z-index: 2;
@@ -194,3 +210,52 @@ button, .entry {
#popup tr:first-child:hover {
color: #002B36;
}
+
+#flow-create, #flow-copy {
+ display: none;
+}
+
+#example-browser {
+ width: 100%;
+ float: left;
+}
+
+#file-browser {
+ overflow-x: auto;
+ padding-right: 0.4em;
+ float: left;
+ max-width: 30%;
+}
+
+#code-browser {
+ background: #073642;
+ font-size: 1.2rem;
+ text-align: left;
+ padding: 0.4em;
+ overflow-x: auto;
+ max-height: 100%;
+}
+
+.browser-node {
+ font-size: 1.2rem;
+ text-align: left;
+ line-height: 1.2em;
+ background: #002B36;
+ padding: 0.2em 0 0 0.2em;
+}
+
+.browser-node > div {
+ margin-left: 2em;
+}
+
+.file-node {
+ cursor: pointer;
+}
+
+.file-node:hover, .selected-node {
+ color: #dc322f;
+}
+
+.even-node {
+ background: #073642;
+}