dolt 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. data/.travis.yml +8 -0
  2. data/Gemfile.lock +3 -3
  3. data/bin/dolt +1 -4
  4. data/dolt.gemspec +2 -2
  5. data/lib/dolt/sinatra/actions.rb +1 -0
  6. data/lib/dolt/sinatra/multi_repo_browser.rb +2 -0
  7. data/lib/dolt/sinatra/single_repo_browser.rb +2 -0
  8. data/vendor/ui/.gitmodules +3 -0
  9. data/vendor/ui/autolint.js +13 -0
  10. data/vendor/ui/buster.js +8 -5
  11. data/vendor/ui/css/gitorious.css +13 -29
  12. data/vendor/ui/dist/gitorious3.min.js +3 -3
  13. data/vendor/ui/js/src/app.js +17 -0
  14. data/vendor/ui/js/src/components/abbrev.js +2 -3
  15. data/vendor/ui/js/src/components/blob.js +133 -18
  16. data/vendor/ui/js/src/components/clone-url-selection.js +5 -0
  17. data/vendor/ui/js/src/components/dropdown.js +3 -2
  18. data/vendor/ui/js/src/components/ganalytics.js +5 -2
  19. data/vendor/ui/js/src/components/live-markdown-preview.js +13 -17
  20. data/vendor/ui/js/src/components/ref-selector.js +4 -3
  21. data/vendor/ui/js/src/components/tree-history.js +3 -2
  22. data/vendor/ui/js/src/components/url.js +2 -1
  23. data/vendor/ui/js/src/gitorious.js +21 -15
  24. data/vendor/ui/js/src/logger.js +19 -6
  25. data/vendor/ui/js/test/components/abbrev-test.js +1 -0
  26. data/vendor/ui/js/test/components/blob-test.js +90 -0
  27. data/vendor/ui/js/test/components/clone-url-selection-test.js +25 -0
  28. data/vendor/ui/js/test/components/commit-linker-test.js +26 -21
  29. data/vendor/ui/js/test/components/live-markdown-preview-test.js +37 -0
  30. data/vendor/ui/js/test/components/profile-menu-test.js +1 -1
  31. data/vendor/ui/js/test/components/ref-selector-test.js +1 -1
  32. data/vendor/ui/js/test/components/tree-history-test.js +5 -3
  33. data/vendor/ui/js/test/components/url-template-test.js +9 -5
  34. metadata +9 -5
  35. data/lib/dolt/ruby19.rb +0 -24
@@ -1,4 +1,9 @@
1
1
  /*global cull, dome*/
2
+ this.gts = this.gts || {};
3
+
4
+ /**
5
+ * When clicking clone URLs, copy them to the related input field.
6
+ */
2
7
  this.gts.cloneUrlSelection = function cloneUrlSelection(element) {
3
8
  var input = element.getElementsByTagName("input")[0];
4
9
 
@@ -42,8 +42,9 @@ this.gts.dropdown = (function (D) {
42
42
  function toggle(element) {
43
43
  if (active) { return close(); }
44
44
 
45
- if ("ontouchstart" in document.documentElement) {
46
- // if mobile we we use a backdrop because click events don't delegate
45
+ if (document.documentElement.hasOwnProperty("ontouchstart")) {
46
+ // if mobile we we use a backdrop because click events don't
47
+ // delegate
47
48
  backdrop = D.el("div", {
48
49
  className: "dropdown-backdrop",
49
50
  events: { click: close }
@@ -11,6 +11,9 @@ gts.googleAnalytics = function (account, domainName) {
11
11
  var ga = document.createElement("script");
12
12
  ga.type = "text/javascript";
13
13
  ga.async = true;
14
- ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
15
- (document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(ga);
14
+ ga.src = ("https:" === document.location.protocol ?
15
+ "https://ssl" :
16
+ "http://www") + ".google-analytics.com/ga.js";
17
+ (document.getElementsByTagName("head")[0] ||
18
+ document.getElementsByTagName("body")[0]).appendChild(ga);
16
19
  };
@@ -1,26 +1,22 @@
1
1
  /*global Showdown*/
2
+
3
+ /**
4
+ * Monitor a textarea and render a live preview of its content parsed as
5
+ * Markdown. The textarea needs to have the data attribute
6
+ * data-gts-preview-target set, and it should be an id of an element elsewhere
7
+ * in the document. The target element needs to contain at least a div element,
8
+ * which is where the preview will be rendered.
9
+ *
10
+ * When previewing, the target will be hidden when the textarea is empty, and
11
+ * shown with block display when there is content.
12
+ */
2
13
  this.gts.liveMarkdownPreview = function liveMarkdownPreview(textarea) {
3
- var target = document.getElementById(textarea.getAttribute("data-gts-preview-target"));
14
+ var attr = textarea.getAttribute("data-gts-preview-target");
15
+ var target = document.getElementById(attr);
4
16
  if (!target || typeof Showdown === "undefined") { return; }
5
17
  var converter = new Showdown.converter();
6
18
  var previous, content;
7
19
 
8
- var cageSeed = new Date().getTime();
9
-
10
- function zeroPad(num) {
11
- return num < 10 ? "0" + num : num;
12
- }
13
-
14
- function signature() {
15
- var now = new Date();
16
- return "<p>" +
17
- "<img width=\"24\" height=\"24\" class=\"gts-avatar\" alt=\"avatar\" src=\"http://cageme.herokuapp.com/24/24?" +
18
- cageSeed + "\">" +
19
- "<a href=\"/~zmalltalker\">Marius Mathiesen</a>" +
20
- zeroPad(now.getHours()) + ":" + zeroPad(now.getMinutes()) +
21
- ". <a href=\"#\">Edit comment</a></p>";
22
- }
23
-
24
20
  function setPreview(preview) {
25
21
  target.style.display = preview ? "block" : "none";
26
22
  target.getElementsByTagName("div")[0].innerHTML = preview;
@@ -59,7 +59,7 @@ this.gts.refSelector = (function (e) {
59
59
  href: "#",
60
60
  className: "dropdown-toggle",
61
61
  innerHTML: "<span class=\"caret\"></span> <em>" +
62
- type + ":</em> " + (currentRef && currentRef[0] || current)
62
+ type + ":</em> " + ((currentRef && currentRef[0]) || current)
63
63
  });
64
64
  }
65
65
 
@@ -82,9 +82,10 @@ this.gts.refSelector = (function (e) {
82
82
  }
83
83
 
84
84
  function refItems(label, refs, urlTemplate) {
85
- var initial = [e.li({ className: "dropdown-label" }, [e.strong(label)])];
85
+ var initial = [e.li({className: "dropdown-label"}, [e.strong(label)])];
86
86
  return cull.reduce(function (elements, ref) {
87
- elements.push(e.li(e.a({ href: tpl(urlTemplate, ref[1]) }, ref[0])));
87
+ var url = tpl(urlTemplate, ref[1]);
88
+ elements.push(e.li(e.a({ href: url }, ref[0])));
88
89
  return elements;
89
90
  }, initial, refs.sort());
90
91
  }
@@ -102,7 +102,8 @@ this.gts.treeHistory = (function (c, d) {
102
102
  }
103
103
 
104
104
  function getTreeIndent(cells) {
105
- for (var i = 0, l = cells.length; i < l; ++i) {
105
+ var i, l;
106
+ for (i = 0, l = cells.length; i < l; ++i) {
106
107
  if (dome.cn.has("gts-name", cells[i])) {
107
108
  return i;
108
109
  }
@@ -112,7 +113,7 @@ this.gts.treeHistory = (function (c, d) {
112
113
  }
113
114
 
114
115
  function fileName(element) {
115
- return (element && dome.text(element) || "").trim();
116
+ return ((element && dome.text(element)) || "").trim();
116
117
  }
117
118
 
118
119
  th.annotateRow = function (tree, row) {
@@ -1,4 +1,5 @@
1
1
  /*global cull*/
2
+ /*jslint maxlen: 100*/
2
3
  // The global, shared Gitorious namespace
3
4
  this.gts = this.gts || {};
4
5
 
@@ -53,7 +54,7 @@ this.gts.url = (function () {
53
54
  function currentRef(url) {
54
55
  var regexp = /(blame|blob|tree|history|raw|source|readme)\//;
55
56
  var refPath = url.split(regexp)[2];
56
- return refPath && refPath.split(":")[0] || null;
57
+ return (refPath && refPath.split(":")[0]) || null;
57
58
  }
58
59
 
59
60
  return {
@@ -1,29 +1,34 @@
1
1
  /*global gts, reqwest, cull*/
2
2
 
3
- this.gts.loadRefs = function (url) {
4
- return reqwest({ url: url, type: "json" });
5
- };
6
-
7
- function refUrlTpl(url, ref) {
8
- return gts.url.templatize(url, { ref: ref });
9
- }
10
-
11
3
  // Environment variables
12
4
  gts.app.env("url", window.location.href);
13
5
  gts.app.env("redirect", function (url) { window.location = url; });
14
6
 
15
- if ("onpopstate" in window) {
7
+ if (window.hasOwnProperty("onpopstate")) {
16
8
  window.onpopstate = function (event) {
17
9
  gts.app.env("url", window.location.href);
18
10
  };
19
11
  }
20
12
 
21
13
  // Data
14
+ gts.app.data("ref-url-template", function (url, ref) {
15
+ return gts.url.templatize(url, { ref: ref });
16
+ }, {
17
+ depends: ["url", "current-ref"],
18
+ serializeArgs: function (url, ref) { return [url.split("#")[0], ref]; }
19
+ });
20
+
21
+ gts.app.data("repository-refs", function (url) {
22
+ return reqwest({ url: url, type: "json" });
23
+ }, { depends: ["repository-refs-url"] });
24
+
22
25
  gts.app.data("current-ref", gts.url.currentRef, { depends: ["url"] });
23
- gts.app.data("ref-url-template", refUrlTpl, { depends: ["url", "current-ref"] });
24
- gts.app.data("repository-refs", gts.loadRefs, { depends: ["repository-refs-url"] });
25
- gts.app.data("user-repo-view-state", gts.userRepoViewState, { depends: ["user-repository-path"] });
26
- gts.app.data("current-user", cull.prop("user"), { depends: ["user-repo-view-state"] });
26
+ gts.app.data("user-repo-view-state", gts.userRepoViewState, {
27
+ depends: ["user-repository-path"]
28
+ });
29
+ gts.app.data("current-user", cull.prop("user"), {
30
+ depends: ["user-repo-view-state"]
31
+ });
27
32
  gts.app.data("blob-region", gts.blob.regionFromUrl, { depends: ["url"] });
28
33
 
29
34
  // Features
@@ -64,8 +69,9 @@ gts.app.feature("highlight-region", gts.blob.highlightRegion, {
64
69
  depends: ["blob-region"]
65
70
  });
66
71
 
67
- gts.app.feature("highlight-line-mouseover", gts.blob.highlightLineOnFocus, {
68
- elements: ["gts-lines"]
72
+ gts.app.feature("track-blob-focus", gts.blob.trackFocus, {
73
+ elements: ["gts-lines"],
74
+ depends: ["redirect"]
69
75
  });
70
76
 
71
77
  gts.app.feature("live-markdown-preview", gts.liveMarkdownPreview, {
@@ -1,4 +1,4 @@
1
- /*global gts, cull, dome*/
1
+ /*global cull, dome, console, gts*/
2
2
  function uinitLogger(app, level) {
3
3
  if (typeof level === "string") {
4
4
  level = uinitLogger.levels.indexOf((level || "info").toLowerCase());
@@ -20,23 +20,29 @@ function uinitLogger(app, level) {
20
20
  app.on("loading", function (feature) {
21
21
  console.log("[Loading:", feature.name + "]");
22
22
  });
23
+
24
+ app.on("reloading", function (feature) {
25
+ console.log("[Re-loading:", feature.name + "]");
26
+ });
23
27
  }
24
28
 
25
29
  if (level <= uinitLogger.INFO) {
26
30
  app.on("pending", function (feature) {
27
- var reason, waitingFor = cull.map(cull.prop("name"), cull.select(function (f) {
31
+ var name = cull.prop("name");
32
+ var reason, pending = cull.map(name, cull.select(function (f) {
28
33
  return !f.loaded;
29
34
  }, feature.dependencies()));
30
35
 
31
- if (waitingFor.length > 0) {
36
+ if (pending.length > 0) {
32
37
  reason = "Waiting for ";
33
- reason += waitingFor.length === 1 ? "dependency" : "dependencies";
34
- reason += " [" + waitingFor.join(", ") + "]";
38
+ reason += pending.length === 1 ? "dependency" : "dependencies";
39
+ reason += " [" + pending.join(", ") + "]";
35
40
  }
36
41
 
37
42
  if (!reason && feature.elements) {
38
43
  if (dome.byClass(feature.elements).length === 0) {
39
- reason = "No matching elements for selector ." + feature.elements;
44
+ reason = "No matching elements for selector ." +
45
+ feature.elements;
40
46
  }
41
47
  }
42
48
 
@@ -48,6 +54,13 @@ function uinitLogger(app, level) {
48
54
  });
49
55
  }
50
56
 
57
+ if (level <= uinitLogger.INFO) {
58
+ app.on("skip", function (feature) {
59
+ console.log("[Skip:", feature.name + "]",
60
+ "Reload triggered, but input was unchanged");
61
+ });
62
+ }
63
+
51
64
  if (level <= uinitLogger.INFO) {
52
65
  app.on("loaded", function (feature, result) {
53
66
  console.log("[Load:", feature.name + "] =>", result);
@@ -1,3 +1,4 @@
1
+ /*global buster, assert, gts*/
1
2
  buster.testCase("Abbrev", {
2
3
  "returns short enough string": function () {
3
4
  assert.equals("Some string", gts.abbrev("Some string", 30));
@@ -0,0 +1,90 @@
1
+ /*global buster, assert, refute, jQuery, dome, gts*/
2
+
3
+ buster.testCase("Blob", {
4
+ setUp: function () {
5
+ this.el = dome.el("ol", [
6
+ dome.el("li", { className: "L0" }, "First line"),
7
+ dome.el("li", { className: "L1" }, "Second line"),
8
+ dome.el("li", { className: "L2" }, "Third line"),
9
+ dome.el("li", { className: "L3" }, "Fourth line")
10
+ ]);
11
+ },
12
+
13
+ "regionFromUrl": {
14
+ "extracts single line number": function () {
15
+ var region = gts.blob.regionFromUrl("/some/url#l1");
16
+ assert.equals(region, [1, 1]);
17
+ },
18
+
19
+ "extracts region": function () {
20
+ var region = gts.blob.regionFromUrl("/some/url#l1-10");
21
+ assert.equals(region, [1, 10]);
22
+ },
23
+
24
+ "extracts ordered region": function () {
25
+ var region = gts.blob.regionFromUrl("/some/url#l29-8");
26
+ assert.equals(region, [8, 29]);
27
+ },
28
+
29
+ "matches URL case-insensitively": function () {
30
+ var region = gts.blob.regionFromUrl("/some/url#L9");
31
+ assert.equals(region, [9, 9]);
32
+ }
33
+ },
34
+
35
+ "highlightRegion": {
36
+ "highlights first line": function () {
37
+ gts.blob.highlightRegion(this.el, [1, 1]);
38
+ assert.className(this.el.childNodes[0], "region");
39
+ refute.className(this.el.childNodes[1], "region");
40
+ refute.className(this.el.childNodes[2], "region");
41
+ refute.className(this.el.childNodes[3], "region");
42
+ },
43
+
44
+ "highlights region": function () {
45
+ gts.blob.highlightRegion(this.el, [2, 4]);
46
+ refute.className(this.el.childNodes[0], "region");
47
+ assert.className(this.el.childNodes[1], "region");
48
+ assert.className(this.el.childNodes[2], "region");
49
+ assert.className(this.el.childNodes[3], "region");
50
+ },
51
+
52
+ "un-highlights elements as region changes": function () {
53
+ gts.blob.highlightRegion(this.el, [2, 4]);
54
+ gts.blob.highlightRegion(this.el, [1, 2]);
55
+ assert.className(this.el.childNodes[0], "region");
56
+ assert.className(this.el.childNodes[1], "region");
57
+ refute.className(this.el.childNodes[2], "region");
58
+ refute.className(this.el.childNodes[3], "region");
59
+ }
60
+ },
61
+
62
+ "trackFocus": {
63
+ setUp: function () {
64
+ // Required for event triggering to work
65
+ document.body.appendChild(this.el);
66
+ this.redirect = this.spy();
67
+ gts.blob.trackFocus(this.el, this.redirect);
68
+ var lines = this.el.getElementsByTagName("li");
69
+ this.trigger = function (lineNum) {
70
+ var line = jQuery(lines[lineNum]);
71
+ line.trigger.apply(line, [].slice.call(arguments, 1));
72
+ };
73
+ },
74
+
75
+ "selects first line as region": function () {
76
+ this.trigger(0, "click");
77
+ assert.className(this.el.childNodes[0], "region");
78
+ assert.calledOnceWith(this.redirect, "#L1");
79
+ },
80
+
81
+ "selects discrete lines with multiple clicks": function () {
82
+ this.trigger(0, "click");
83
+ assert.className(this.el.childNodes[0], "region");
84
+
85
+ this.trigger(1, "click");
86
+ refute.className(this.el.childNodes[0], "region");
87
+ assert.className(this.el.childNodes[1], "region");
88
+ }
89
+ }
90
+ });
@@ -0,0 +1,25 @@
1
+ /*global buster, assert, jQuery, gts*/
2
+
3
+ buster.testCase("Clone URL selection", {
4
+ setUp: function () {
5
+ /*:DOC element = <div class="btn-group gts-repo-urls">
6
+ <a class="btn gts-repo-url" href="git://gitorious.org/gitorious/mainline.git">Git</a>
7
+ <a class="btn gts-repo-url" href="http://git.gitorious.org/gitorious/mainline.git">HTTP</a>
8
+ <a class="active btn gts-repo-url" href="git@gitorious.org:gitorious/mainline.git">SSH</a>
9
+ <input class="span4 gts-current-repo-url gts-select-onfocus" type="url" value="git@gitorious.org:gitorious/mainline.git">
10
+ <button data-toggle="collapse" data-target="#repo-url-help" class="gts-repo-url-help btn">?</button>
11
+ </div>*/
12
+ this.input = this.element.getElementsByTagName("input")[0];
13
+ document.body.appendChild(this.element);
14
+ var buttons = this.element.getElementsByTagName("a");
15
+ this.click = function (num) {
16
+ jQuery(buttons[num]).trigger("click");
17
+ };
18
+ },
19
+
20
+ "// copies href to input on click": "Click triggering currently not working"
21
+ /*function () {
22
+ this.click(0);
23
+ assert.equals(this.input.value, "git://gitorious.org/gitorious/mainline.git");
24
+ }*/
25
+ });
@@ -1,41 +1,46 @@
1
+ /*global buster, assert, refute, jQuery, gts*/
1
2
  buster.testCase("Commit linker", {
3
+ setUp: function () {
4
+ this.el = document.createElement("div");
5
+ // Required for even triggering to work properly
6
+ document.body.appendChild(this.el);
7
+ },
8
+
2
9
  "triggers handler for gts-commit-oid link": function () {
3
- var callback = this.spy();
4
- var el = document.createElement("div");
5
- el.innerHTML = "<span class=\"gts-commit-oid\" data-gts-commit-oid=\"master\">master</span>";
10
+ var cb = this.spy();
11
+ this.el.innerHTML = "<span class=\"gts-commit-oid\" " +
12
+ "data-gts-commit-oid=\"master\">master</span>";
6
13
 
7
- gts.commitLinker(el, "/gitorious/mainline/commit/#{oid}", callback);
8
- jQuery(el.firstChild).trigger("click");
14
+ gts.commitLinker(this.el, "/gitorious/mainline/commit/#{oid}", cb);
15
+ jQuery(this.el.firstChild).trigger("click");
9
16
 
10
- assert.calledOnceWith(callback, "/gitorious/mainline/commit/master");
17
+ assert.calledOnceWith(cb, "/gitorious/mainline/commit/master");
11
18
  },
12
19
 
13
20
  "does not trigger handler for regular link": function () {
14
- var callback = this.spy();
15
- var el = document.createElement("div");
16
- el.innerHTML = "<span>master</span>";
21
+ var cb = this.spy();
22
+ this.el.innerHTML = "<span>master</span>";
17
23
 
18
- gts.commitLinker(el, "/gitorious/mainline/commit/#{oid}", callback);
19
- jQuery(el.firstChild).trigger("click");
24
+ gts.commitLinker(this.el, "/gitorious/mainline/commit/#{oid}", cb);
25
+ jQuery(this.el.firstChild).trigger("click");
20
26
 
21
- refute.called(callback);
27
+ refute.called(cb);
22
28
  },
23
29
 
24
30
  "triggers handler for link added later": function () {
25
- var callback = this.spy();
26
- var el = document.createElement("div");
31
+ var cb = this.spy();
27
32
 
28
- gts.commitLinker(el, "/gitorious/mainline/commit/#{oid}", callback);
29
- el.innerHTML = "<span class=\"gts-commit-oid\" data-gts-commit-oid=\"master\">master</span>";
30
- jQuery(el.firstChild).trigger("click");
33
+ gts.commitLinker(this.el, "/gitorious/mainline/commit/#{oid}", cb);
34
+ this.el.innerHTML = "<span class=\"gts-commit-oid\" " +
35
+ "data-gts-commit-oid=\"master\">master</span>";
36
+ jQuery(this.el.firstChild).trigger("click");
31
37
 
32
- assert.calledOnce(callback);
38
+ assert.calledOnce(cb);
33
39
  },
34
40
 
35
41
  "adds class name to root element": function () {
36
- var el = document.createElement("div");
37
- gts.commitLinker(el, "/gitorious/mainline/commit/#{oid}");
42
+ gts.commitLinker(this.el, "/gitorious/mainline/commit/#{oid}");
38
43
 
39
- assert.className(el, "gts-commit-linker");
44
+ assert.className(this.el, "gts-commit-linker");
40
45
  }
41
46
  });
@@ -0,0 +1,37 @@
1
+ /*global buster, assert, dome, gts*/
2
+
3
+ buster.testCase("Live markdown preview", {
4
+ setUp: function () {
5
+ var el = dome.el("div", [
6
+ dome.el("textarea"),
7
+ dome.el("div", { id: "target" }, [dome.el("div")])
8
+ ]);
9
+
10
+ document.body.appendChild(el);
11
+ this.textarea = el.firstChild;
12
+ this.textarea.setAttribute("data-gts-preview-target", "target");
13
+ this.target = el.lastChild.firstChild;
14
+ this.clock = this.useFakeTimers();
15
+ },
16
+
17
+ "renders markdown as html in div": function () {
18
+ gts.liveMarkdownPreview(this.textarea);
19
+ this.textarea.innerHTML = "*hey*";
20
+
21
+ this.clock.tick(50);
22
+
23
+ assert.match(this.target.innerHTML, "<em>hey</em>");
24
+ },
25
+
26
+ "updates rendered html": function () {
27
+ gts.liveMarkdownPreview(this.textarea);
28
+ this.textarea.innerHTML = "*hey*";
29
+ this.clock.tick(50);
30
+
31
+ this.textarea.innerHTML = "# OH!";
32
+ this.clock.tick(50);
33
+
34
+ refute.match(this.target.innerHTML, "<em>hey</em>");
35
+ assert.match(this.target.innerHTML, /<h1.*>OH!<\/h1>/);
36
+ }
37
+ });