UNPKG

brackets-git

Version:
356 lines (309 loc) 14.5 kB
define(function (require) { // Brackets modules var _ = brackets.getModule("thirdparty/lodash"), DocumentManager = brackets.getModule("document/DocumentManager"), ProjectManager = brackets.getModule("project/ProjectManager"); // Local modules var moment = require("moment"), Strings = require("strings"), ErrorHandler = require("src/ErrorHandler"), Events = require("src/Events"), EventEmitter = require("src/EventEmitter"), Git = require("src/git/Git"), HistoryViewer = require("src/HistoryViewer"), Preferences = require("src/Preferences"); // Templates var gitPanelHistoryTemplate = require("text!templates/git-panel-history.html"), gitPanelHistoryCommitsTemplate = require("text!templates/git-panel-history-commits.html"); // Module variables var $gitPanel = $(null), $tableContainer = $(null), $historyList = $(null), commitCache = [], avatarType = Preferences.get("avatarType"), lastDocumentSeen = null; if (avatarType === "PICTURE" || avatarType === "IDENTICON") { var md5; require(["md5"], function (_md5) { md5 = _md5; }); } // Implementation function initVariables() { $gitPanel = $("#git-panel"); $tableContainer = $gitPanel.find(".table-container"); attachHandlers(); } function attachHandlers() { $tableContainer .off(".history") .on("scroll.history", function () { loadMoreHistory(); }) .on("click.history", ".history-commit", function () { var hash = $(this).attr("x-hash"); var commit = _.find(commitCache, function (commit) { return commit.hash === hash; }); HistoryViewer.show(commit, getCurrentDocument()); }); } var generateCssAvatar = _.memoize(function (author, email) { // Original source: http://indiegamr.com/generate-repeatable-random-numbers-in-js/ var seededRandom = function (max, min, seed) { max = max || 1; min = min || 0; seed = (seed * 9301 + 49297) % 233280; var rnd = seed / 233280.0; return min + rnd * (max - min); }; // Use `seededRandom()` to generate a pseudo-random number [0-16] to pick a color from the list var seedBase = parseInt(author.charCodeAt(3).toString(), email.length), seed = parseInt(email.charCodeAt(seedBase.toString().substring(1, 2)).toString(), 16), colors = [ "#ffb13b", "#dd5f7a", "#8dd43a", "#2f7e2f", "#4141b9", "#3dafea", "#7e3e3e", "#f2f26b", "#864ba3", "#ac8aef", "#f2f2ce", "#379d9d", "#ff6750", "#8691a2", "#d2fd8d", "#88eadf" ], texts = [ "#FEFEFE", "#FEFEFE", "#FEFEFE", "#FEFEFE", "#FEFEFE", "#FEFEFE", "#FEFEFE", "#333333", "#FEFEFE", "#FEFEFE", "#333333", "#FEFEFE", "#FEFEFE", "#FEFEFE", "#333333", "#333333" ], picked = Math.floor(seededRandom(0, 16, seed)); return "background-color: " + colors[picked] + "; color: " + texts[picked]; }, function (author, email) { // calculate hash for memoize - both are strings so we don't need to convert return author + email; }); var generateMd5 = _.memoize(function (string) { return md5(string); }); // Render history list the first time function renderHistory(file) { // clear cache commitCache = []; return Git.getCurrentBranchName().then(function (branchName) { // Get the history commits of the current branch var p = file ? Git.getFileHistory(file.relative, branchName) : Git.getHistory(branchName); return p.then(function (commits) { // calculate some missing stuff like avatars commits = addAdditionalCommitInfo(commits); commitCache = commitCache.concat(commits); var templateData = { commits: commits, usePicture: avatarType === "PICTURE", useIdenticon: avatarType === "IDENTICON", useBwAvatar: avatarType === "AVATAR_BW", useColoredAvatar: avatarType === "AVATAR_COLOR", Strings: Strings }; $tableContainer.append(Mustache.render(gitPanelHistoryTemplate, templateData, { commits: gitPanelHistoryCommitsTemplate })); $historyList = $tableContainer.find("#git-history-list") .data("file", file ? file.absolute : null) .data("file-relative", file ? file.relative : null); }); }).catch(function (err) { ErrorHandler.showError(err, "Failed to get history"); }); } // Load more rows in the history list on scroll function loadMoreHistory() { if ($historyList.is(":visible")) { if (($tableContainer.prop("scrollHeight") - $tableContainer.scrollTop()) === $tableContainer.height()) { if ($historyList.attr("x-finished") === "true") { return; } return Git.getCurrentBranchName().then(function (branchName) { var p, file = $historyList.data("file-relative"), skipCount = $tableContainer.find("tr.history-commit").length; if (file) { p = Git.getFileHistory(file, branchName, skipCount); } else { p = Git.getHistory(branchName, skipCount); } return p.then(function (commits) { if (commits.length === 0) { $historyList.attr("x-finished", "true"); return; } commits = addAdditionalCommitInfo(commits); commitCache = commitCache.concat(commits); var templateData = { commits: commits, usePicture: avatarType === "PICTURE", useIdenticon: avatarType === "IDENTICON", useBwAvatar: avatarType === "AVATAR_BW", useColoredAvatar: avatarType === "AVATAR_COLOR", Strings: Strings }; var commitsHtml = Mustache.render(gitPanelHistoryCommitsTemplate, templateData); $historyList.children("tbody").append(commitsHtml); }) .catch(function (err) { ErrorHandler.showError(err, "Failed to load more history rows"); }); }) .catch(function (err) { ErrorHandler.showError(err, "Failed to get current branch name"); }); } } } function addAdditionalCommitInfo(commits) { var mode = Preferences.get("dateMode"), format = Strings.DATE_FORMAT, // now = moment(), // yesterday = moment().subtract("d", 1).startOf("d"), ownFormat = Preferences.get("dateFormat") || Strings.DATE_FORMAT; if (mode === 2 && format.indexOf(" ")) { // only date part format = format.substring(0, format.indexOf(" ")); } _.forEach(commits, function (commit) { // Get color for AVATAR_BW and AVATAR_COLOR if (avatarType === "AVATAR_COLOR" || avatarType === "AVATAR_BW") { commit.cssAvatar = generateCssAvatar(commit.author, commit.email); commit.avatarLetter = commit.author.substring(0, 1); } if (avatarType === "PICTURE" || avatarType === "IDENTICON") { commit.emailHash = generateMd5(commit.email); } // FUTURE: convert date modes to sensible constant strings if (mode === 4) { // mode 4: Original Git date commit.date = { shown: commit.date }; return; } var date = moment(commit.date); commit.date = { title: "" }; switch (mode) { // mode 0 (default): formatted with Strings.DATE_FORMAT default: case 0: commit.date.shown = date.format(format); break; // mode 1: always relative case 1: commit.date.shown = date.fromNow(); commit.date.title = date.format(format); break; // mode 2: intelligent relative/formatted case 2: var relative = date.fromNow(), formatted = date.format(format); commit.date.shown = relative + " (" + formatted + ")"; commit.date.title = date.format(Strings.DATE_FORMAT); /* if (date.diff(yesterday) > 0) { commit.date.shown = moment.duration(Math.max(date.diff(now), -24 * 60 * 60 * 1000), "ms").humanize(true); commit.date.title = date.format(format); } else { commit.date.shown = date.format(format); } */ break; // mode 3: formatted with own format (as pref) case 3: commit.date.shown = date.format(ownFormat); commit.date.title = date.format(format); break; /* mode 4 (Original Git date) is handled above */ } }); return commits; } function getCurrentDocument() { if (HistoryViewer.isVisible()) { return lastDocumentSeen; } var doc = DocumentManager.getCurrentDocument(); if (doc) { lastDocumentSeen = doc; } return doc || lastDocumentSeen; } function handleFileChange() { var currentDocument = getCurrentDocument(); if ($historyList.is(":visible") && $historyList.data("file")) { handleToggleHistory("FILE", currentDocument); } $gitPanel.find(".git-file-history").prop("disabled", !currentDocument); } // Show or hide the history list on click of .history button // newHistoryMode can be "FILE" or "GLOBAL" function handleToggleHistory(newHistoryMode, newDocument) { // this is here to check that $historyList is still attached to the DOM $historyList = $tableContainer.find("#git-history-list"); var historyEnabled = $historyList.is(":visible"), currentFile = $historyList.data("file") || null, currentHistoryMode = historyEnabled ? (currentFile ? "FILE" : "GLOBAL") : "DISABLED", doc = newDocument ? newDocument : getCurrentDocument(), file; if (currentHistoryMode !== newHistoryMode) { // we are switching the modes so enable historyEnabled = true; } else if (!newDocument) { // we are not changing the mode and we are not switching to a new document historyEnabled = !historyEnabled; } if (historyEnabled && newHistoryMode === "FILE") { if (doc) { file = {}; file.absolute = doc.file.fullPath; file.relative = ProjectManager.makeProjectRelativeIfPossible(file.absolute); } else { // we want a file history but no file was found historyEnabled = false; } } // Render #git-history-list if is not already generated or if the viewed file for file history has changed var isEmpty = $historyList.find("tr").length === 0, fileChanged = currentFile !== (file ? file.absolute : null); if (historyEnabled && (isEmpty || fileChanged)) { if ($historyList.length > 0) { $historyList.remove(); } var $spinner = $("<div class='spinner spin large'></div>").appendTo($gitPanel); renderHistory(file).finally(function () { $spinner.remove(); }); } // disable commit button when viewing history // refresh status when history is closed and commit button will correct its disabled state if required if (historyEnabled) { $gitPanel.find(".git-commit, .check-all").prop("disabled", true); } else { Git.status(); } // Toggle visibility of .git-edited-list and #git-history-list $tableContainer.find(".git-edited-list").toggle(!historyEnabled); $historyList.toggle(historyEnabled); if (!historyEnabled) { HistoryViewer.hide(); } // Toggle history button var globalButtonActive = historyEnabled && newHistoryMode === "GLOBAL", fileButtonActive = historyEnabled && newHistoryMode === "FILE"; $gitPanel.find(".git-history-toggle").toggleClass("active", globalButtonActive) .attr("title", globalButtonActive ? Strings.TOOLTIP_HIDE_HISTORY : Strings.TOOLTIP_SHOW_HISTORY); $gitPanel.find(".git-file-history").toggleClass("active", fileButtonActive) .attr("title", fileButtonActive ? Strings.TOOLTIP_HIDE_FILE_HISTORY : Strings.TOOLTIP_SHOW_FILE_HISTORY); } // Event listeners EventEmitter.on(Events.GIT_ENABLED, function () { initVariables(); }); EventEmitter.on(Events.GIT_DISABLED, function () { lastDocumentSeen = null; $historyList.remove(); $historyList = $(); }); EventEmitter.on(Events.HISTORY_SHOW, function (mode) { handleToggleHistory(mode === "FILE" ? "FILE" : "GLOBAL"); }); EventEmitter.on(Events.BRACKETS_CURRENT_DOCUMENT_CHANGE, function () { handleFileChange(); }); });