dolt 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ });