/*global cull, dome*/ // The global, shared Gitorious namespace this.gts = this.gts || {}; /** * The ref selector builds an interactive "drop-down" menu from which the * user can select a head or tag, or lookup a specific ref. The menu will * reload the current page for the chosen ref. * * gts.refSelector(refs, current, urlTemplate) * * refs is an object containing available heads and tags and the oids they * refer to, e.g.: * * { "heads": [["production", "24e9c0d4ce36fbe1dfca4029e3bd206d64e2eecc"], * ["redesign", "4c22773401aa2cdd2391bc04443ad7eea193e7b6"], * ["web-hooks", "a08053012b9aee5d9733fceb2cf3083f29d9aa7d"], * ["master", "48ac677757da7ca052c59ebec0ded6e11eef2642"]], * "tags": [["v2.4.3", "7a3cffcb3c3db89e8005962850e29a8aab2ab09b"]] * * current is the active ref on the current page, either the refname * or the actual oid. * * urlTemplate is the URL that will be loaded, where the ref exists as a * placeholder, e.g. "/gitorious/mainline/source/#{ref}:lib". A suitable * template can be created from the current page's URL using * gts.url.templatize(window.location.href, { ref: currentRef }); */ this.gts.refSelector = (function (e) { function tpl(template, ref) { return (template || "#{ref}").replace(/#\{ref\}/g, ref); } /** * Gets the current ref. type is {heads,tags,remotes} and * refs[type] is an array of ref tuples where each tuple contains * the object id and a ref (e.g. "master"). */ function getCurrent(type, refName, refs) { return cull.select(function (ref) { return ref[0] === refName || ref[1] === refName; }, refs[type] || [])[0]; } function currentRefLink(refs, current) { var currentRef = getCurrent("heads", current, refs); var type = "branch"; if (!currentRef) { currentRef = getCurrent("tags", current, refs); type = "tag"; } if (!currentRef) { type = "ref"; } return e.a({ href: "#", className: "dropdown-toggle", innerHTML: " " + type + ": " + (currentRef && currentRef[0] || current) }); } function refInput(url) { var input = e.input({ type: "text", className: "gts-ref-input" }); var form = e.form({ className: "gts-ref-input", events: { submit: function (e) { e.preventDefault(); window.location = tpl(url, input.value); } } }, [input]); return e.li({ className: "gts-dropdown-input", events: { click: function (e) { e.stopPropagation(); } } }, [e.strong(["Enter ref: ", form])]); } function refItems(label, refs, urlTemplate) { var initial = [e.li({ className: "dropdown-label" }, [e.strong(label)])]; return cull.reduce(function (elements, ref) { elements.push(e.li(e.a({ href: tpl(urlTemplate, ref[1]) }, ref[0]))); return elements; }, initial, refs.sort()); } function refsList(refs, urlTemplate) { return e.ul({ className: "dropdown-menu" }, [refInput(urlTemplate)]. concat(refItems("Branches", refs.heads || [], urlTemplate)). concat(refItems("Tags", refs.tags || [], urlTemplate))); } function build(refs, current, urlTemplate) { return e.div({ className: "dropdown gts-branch-selector pull-right" }, [currentRefLink(refs, current), refsList(refs, urlTemplate)]); } function refSelector(placeholder, refs, ref, refUrlTemplate) { var selector = build(refs, ref, refUrlTemplate); placeholder.appendChild(selector); this.gts.dropdown(selector); } refSelector.build = build; return refSelector; }(dome.el));