1 // Copyright (c) 2008 Tony Garnock-Jones <tonyg@lshift.net>
2 // Copyright (c) 2008 LShift Ltd. <query@lshift.net>
4 // Permission is hereby granted, free of charge, to any person
5 // obtaining a copy of this software and associated documentation files
6 // (the "Software"), to deal in the Software without restriction,
7 // including without limitation the rights to use, copy, modify, merge,
8 // publish, distribute, sublicense, and/or sell copies of the Software,
9 // and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 var repo = new Dvcs.Repository();
25 var fs = repo.update(null);
27 var mergeAncestor = null;
29 Dvcs._debugMode = true;
31 function redisplay_repository_history() {
32 var ordering = DrawDvcs.renderRepository(repo);
34 for (var i = 0; i < ordering.length; i++) {
35 var item = ordering[i];
36 var pictures = item.pictures;
37 for (var j = 0; j < pictures.length; j++) {
38 html = html + "<img src='img/" + pictures[j] + "' />";
40 html = html + "<span class='historyline'><span id='" + item.revId +
41 "' class='nonselected'>" +
42 "<span onclick='maybeSelectRev(\"" + item.revId + "\")'>" + item.revId + "</span>" +
43 " <span class='mergecommand" +
44 "' onclick='maybeMergeRev(\"" + item.revId + "\")'>(m)</span></span></span><br />\n";
46 document.getElementById("historyContainer").innerHTML =
47 "<p style='line-height: 0px; white-space: nowrap;'>" + html + "</p>";
50 function set_rev_span(className, revId) {
51 var revSpan = document.getElementById(revId || fs.directParent);
53 revSpan.className = className;
57 function mark_dirty(newValue, comment) {
58 if (newValue && !dirty) { set_rev_span("dirty"); }
60 document.getElementById("revertbutton").disabled = newValue ? "" : "disabled";
61 document.getElementById("commitbutton").disabled = newValue ? "" : "disabled";
62 var stateSpan = document.getElementById("statespan");
64 if (comment != undefined || stateSpan.innerHTML === "") {
65 stateSpan.innerHTML = comment ? comment : "Files changed";
68 stateSpan.innerHTML = "";
72 function sync_view_of_fs() {
73 var workspace = document.getElementById("workspace");
74 workspace.innerHTML = "";
75 for (var inode in fs.inodes) {
76 var inodeDiv = document.createElement("div");
77 workspace.appendChild(inodeDiv);
78 var filename = document.createElement("input");
79 filename.value = fs.getProp(inode, "name");
81 filename.onkeyup = function () {
82 fs.setProp(inode, "name", filename.value);
85 inodeDiv.appendChild(filename);
86 var deleteButton = document.createElement("button");
87 deleteButton.innerHTML = "Delete";
88 deleteButton.onclick = function () {
91 inodeDiv.className = "deletedFile";
93 inodeDiv.appendChild(deleteButton);
94 inodeDiv.appendChild(document.createElement("br"));
95 var contents = document.createElement("textarea");
98 contents.value = fs.getProp(inode, "text").join("\n");
99 contents.onkeyup = function () {
100 fs.setProp(inode, "text", contents.value.split(/\n/));
103 inodeDiv.appendChild(contents);
105 set_rev_span(dirty ? "dirty" : "clean");
107 //document.getElementById("log").innerHTML = "";
111 function maybeSelectRev(revId) {
117 function maybeMergeRev(revId) {
119 if (!repo.canMerge(fs.directParent, revId)) {
120 alert("Refusing to attempt merge with ancestor");
122 var m = repo.merge(fs.directParent, revId);
124 alert("Attempted to merge with ancestor");
127 for (var i = 0; i < m.conflicts.length; i++) {
128 var conflictRecord = m.conflicts[i];
129 var inode = conflictRecord.inode;
130 for (var okProp in conflictRecord.partialResult) {
131 fs.setProp(inode, okProp, conflictRecord.partialResult[okProp]);
133 for (var badProp in conflictRecord.conflictDetails) {
134 var merger = conflictRecord.conflictDetails[badProp];
135 if (badProp == "name") {
136 fs.setProp(inode, "name", merger[0].conflict.a + " / " + merger[0].conflict.b);
137 } else if (badProp == "text") {
138 fs.setProp(inode, "text", build_conflict_markers(merger));
142 set_rev_span("ancestor", m.ancestor);
143 mergeAncestor = m.ancestor;
144 mark_dirty(true, "Merge in progress (merging "+revId+" into "+fs.directParent+")");
151 function build_conflict_markers(merger) {
153 for (var i = 0; i < merger.length; i++) {
154 var item = merger[i];
156 lines = lines.concat(item.ok);
158 lines = lines.concat(["<<<<<<<<<"], item.conflict.a,
159 ["========="], item.conflict.b,
166 function selectRev(revId) {
167 set_rev_span("nonselected");
169 set_rev_span("nonselected", mergeAncestor);
170 mergeAncestor = null;
172 fs = repo.update(revId);
178 selectRev(fs.directParent);
183 var newRevId = repo.commit(fs);
184 redisplay_repository_history();
190 var inode = fs.createFile();
191 fs.setProp(inode, "name", inode);
192 fs.setProp(inode, "text", []);
197 function dvcsdemo_main() {
198 selectPresetNamed("clear");
201 function dumpRepo() {
202 log(JSON.stringify(repo, null, 2));
205 function toggleLogVisible() {
206 var e = document.getElementById("log");
207 e.className = (e.className == "invisible") ? "" : "invisible";
211 presets.clear = function () {
212 repo = new Dvcs.Repository();
213 fs = repo.update(null);
216 presets.preset1 = function () {
218 var fileA = fs.createFile();
219 fs.setProp(fileA, "name", "File A");
220 fs.setProp(fileA, "text", "A B C D E".split(/ /));
221 var rA = repo.commit(fs);
223 fs.setProp(fileA, "text", "G G G A B C D E".split(/ /));
224 var rB1 = repo.commit(fs);
225 fs.setProp(fileA, "text", "A B C D E G G G A B C D E".split(/ /));
226 var rB2 = repo.commit(fs);
227 fs = repo.update(rA);
228 fs.setProp(fileA, "name", "File A, renamed");
229 fs.setProp(fileA, "text", "A B X D E".split(/ /));
230 var rC = repo.commit(fs);
233 presets.preset2 = function () {
235 var fileA = fs.createFile();
236 fs.setProp(fileA, "name", "File A");
237 fs.setProp(fileA, "text", "A B C D E".split(/ /));
238 var rA = repo.commit(fs);
240 fs.setProp(fileA, "text", "G G G A B C D E".split(/ /));
241 var rB1 = repo.commit(fs);
242 fs.setProp(fileA, "text", "A B C D E G G G A B C D E".split(/ /));
243 var rB2 = repo.commit(fs);
244 fs = repo.update(rA);
245 fs.setProp(fileA, "name", "File A, renamed");
246 fs.setProp(fileA, "text", "A B X D E".split(/ /));
247 var rC = repo.commit(fs);
249 fs = repo.update(rB2);
250 fs.setProp(fileA, "text", "A B Z D E G G G A B C D E".split(/ /));
251 var rB3 = repo.commit(fs);
254 presets.preset3 = function () {
256 var fileA = fs.createFile();
257 fs.setProp(fileA, "name", "File A");
258 fs.setProp(fileA, "text", "A B C D E".split(/ /));
259 var rA = repo.commit(fs);
261 fs.setProp(fileA, "text", "G G G A B C D E".split(/ /));
262 var rB1 = repo.commit(fs);
263 fs.setProp(fileA, "text", "A B C D E G G G A B C D E".split(/ /));
264 var rB2 = repo.commit(fs);
265 fs = repo.update(rA);
266 fs.setProp(fileA, "name", "File A, renamed");
267 fs.setProp(fileA, "text", "A B X D E".split(/ /));
268 var rC = repo.commit(fs);
270 var mergeResult = repo.merge(rC, rB2);
271 var rMerger = repo.commit(mergeResult.files);
272 fs = repo.update(rMerger);
273 fs = repo.update("BBB");
274 fs.deleteFile(fileA);
275 var rB3 = repo.commit(fs);
276 var rMerger2 = repo.commit(repo.merge(rB3, rMerger).files);
277 fs = repo.update(rMerger2);
280 presets.ambiguousLCA = function () {
283 "46c316ca-5c4f-4474-a7ea-cfcea3b2ca0f": {
287 "8e184218-c4d8-426b-b190-916e47249ec6": {
291 "2f1dd5b6-271b-4adc-a3ea-cbd11588e95d": {
295 "6a28a74c-727b-4ea0-bda0-aa88c53c730c": {
299 "50a9df9e-e1c9-4138-a7d4-042d6b0e1e1d": {
303 "98a26661-3cc4-42bc-9cac-1d01dd64b7f3": {
307 "c8a089a0-abf3-4940-935f-6a039fdb32ed": {
311 "3e805399-d30b-4cd8-8e29-52d98650de77": {
317 "814f45c3-916d-4a51-8f91-f8c8ed24c598": {
319 "d077723c-5169-45dc-a465-0668870979d6": "46c316ca-5c4f-4474-a7ea-cfcea3b2ca0f"
322 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
324 "timestamp": 1212662063125,
325 "directParent": null,
326 "additionalParent": null
328 "ff9b6da5-b759-4c8c-8c5d-8497504f4529": {
330 "d077723c-5169-45dc-a465-0668870979d6": "8e184218-c4d8-426b-b190-916e47249ec6"
333 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
335 "timestamp": 1212662070767,
336 "directParent": "814f45c3-916d-4a51-8f91-f8c8ed24c598",
337 "additionalParent": null
339 "d092f83a-5e91-42aa-bd6e-d86e8aaeeffd": {
341 "d077723c-5169-45dc-a465-0668870979d6": "2f1dd5b6-271b-4adc-a3ea-cbd11588e95d"
344 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
346 "timestamp": 1212662073640,
347 "directParent": "ff9b6da5-b759-4c8c-8c5d-8497504f4529",
348 "additionalParent": null
350 "737f2636-9db0-4369-8521-a9b9d64d8fc6": {
352 "d077723c-5169-45dc-a465-0668870979d6": "6a28a74c-727b-4ea0-bda0-aa88c53c730c"
355 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
357 "timestamp": 1212662085012,
358 "directParent": "814f45c3-916d-4a51-8f91-f8c8ed24c598",
359 "additionalParent": null
361 "f5a7d71d-41d0-4d69-8434-c0fb68ba1bde": {
363 "d077723c-5169-45dc-a465-0668870979d6": "50a9df9e-e1c9-4138-a7d4-042d6b0e1e1d"
366 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
368 "timestamp": 1212662096545,
369 "directParent": "737f2636-9db0-4369-8521-a9b9d64d8fc6",
370 "additionalParent": "d092f83a-5e91-42aa-bd6e-d86e8aaeeffd"
372 "f06bc572-c234-4a71-980f-4a9d58bea46c": {
374 "d077723c-5169-45dc-a465-0668870979d6": "98a26661-3cc4-42bc-9cac-1d01dd64b7f3"
377 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
379 "timestamp": 1212662104627,
380 "directParent": "737f2636-9db0-4369-8521-a9b9d64d8fc6",
381 "additionalParent": null
383 "33b9c253-9378-4115-9cad-dfa0c81efc57": {
385 "d077723c-5169-45dc-a465-0668870979d6": "c8a089a0-abf3-4940-935f-6a039fdb32ed"
388 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
390 "timestamp": 1212662119727,
391 "directParent": "f06bc572-c234-4a71-980f-4a9d58bea46c",
392 "additionalParent": "d092f83a-5e91-42aa-bd6e-d86e8aaeeffd"
394 "554a6354-f6d5-4033-9fc5-b5b7a4cf5991": {
396 "d077723c-5169-45dc-a465-0668870979d6": "3e805399-d30b-4cd8-8e29-52d98650de77"
399 "changed": ["d077723c-5169-45dc-a465-0668870979d6"],
401 "timestamp": 1212662141759,
402 "directParent": "f5a7d71d-41d0-4d69-8434-c0fb68ba1bde",
403 "additionalParent": "f06bc572-c234-4a71-980f-4a9d58bea46c"
407 "814f45c3-916d-4a51-8f91-f8c8ed24c598": [
408 "ff9b6da5-b759-4c8c-8c5d-8497504f4529",
409 "737f2636-9db0-4369-8521-a9b9d64d8fc6"
411 "ff9b6da5-b759-4c8c-8c5d-8497504f4529": [
412 "d092f83a-5e91-42aa-bd6e-d86e8aaeeffd"
414 "737f2636-9db0-4369-8521-a9b9d64d8fc6": [
415 "f5a7d71d-41d0-4d69-8434-c0fb68ba1bde",
416 "f06bc572-c234-4a71-980f-4a9d58bea46c"
418 "d092f83a-5e91-42aa-bd6e-d86e8aaeeffd": [
419 "f5a7d71d-41d0-4d69-8434-c0fb68ba1bde",
420 "33b9c253-9378-4115-9cad-dfa0c81efc57"
422 "f06bc572-c234-4a71-980f-4a9d58bea46c": [
423 "33b9c253-9378-4115-9cad-dfa0c81efc57",
424 "554a6354-f6d5-4033-9fc5-b5b7a4cf5991"
426 "f5a7d71d-41d0-4d69-8434-c0fb68ba1bde": [
427 "554a6354-f6d5-4033-9fc5-b5b7a4cf5991"
433 repo.importRevisions(repoExt);
434 fs = repo.update(repo.branchTip(null)); // null -> default branch
437 function selectPreset() {
438 selectPresetNamed(document.getElementById("presetSelect").value);
441 function selectPresetNamed(name) {
443 redisplay_repository_history();
448 for (var i = 0; i < arguments.length; i++) {
449 var arg = arguments[i];
450 if (typeof(arg) == 'string') {
451 document.getElementById("log").appendChild(document.createTextNode(arg + "\n"));
453 document.getElementById("log").appendChild(document .createTextNode(uneval(arg) + "\n"));