- #%]
-
-[% PROCESS global/header.html.tmpl
- title = "Patch Review Help"
- header = "Patch Review Help"
-%]
-
-Splinter Patch Review
-
- Splinter is an add-on for [% terms.Bugzilla %] to allow conveniently
- reviewing patches that people have attached to
- [%+ terms.Bugzilla %]. More
- information about Splinter.
-
-The patch review view
-
- If you get to Splinter by clicking on a link next to an
- attachment in [% terms.Bugzilla %], you are presented with the patch
- review view. This view has a number of different pages that can
- be switched between with the links at the top of the screen.
- The first page is the Overview page, the other pages correspond to
- individual files changed by the review.
-
-
- On the Overview page, from top to bottom are shown:
-
-
- - Introductory text to the patch. For a patch that was created
- using 'git format-patch' this will be the Git commit
- message.
- - Controls for creating a new review
- - Previous reviews that other people have written.
-
-
- The pages for each file show a two-column view of the changes.
- The left column is the previous contents of the file,
- the right column is the new contents of the file. (If the file
- is an entirely new file or an entirely deleted file, only one
- column will be shown.) Red indicates lines that have been
- removed, green lines that have been added, and blue lines that
- were modified.
-
-
- If people have previously made comments on individual lines of
- the patch, they will show up both summarized on the Overview
- page and also inline when looking at the files of the patch.
-
-Reviewing an existing patch
-
- There are three components to a review:
-
-
- -
- An overall comment. The text area on the first page allows
- you to enter your overall thoughts on the [% terms.bug %].
-
- -
- Detailed comments on changes within the files. To comment on a
- line in a patch, double click on it, and a text area will open
- beneath that comment. When you are done, click the Save button
- to save your comment or the Cancel button to throw your
- comment away. You can double-click on a saved comment to start
- editing it again and make further changes.
-
- -
- A change to the attachment status. (This is specific to
- [%+ terms.Bugzilla %] instances that have attachment status, which is a
- non-upstream patch. It's somewhat similar to attachment flags,
- which splinter doesn't currently support displaying or
- changing.) This allows you to mark a patch as read to commit
- or needing additional work. This is done by changing the
- drop-down next to the Publish button.
-
-
-
- Once you are done writing your review, go back to Overview page
- and click the "Publish" button to submit it as a comment on the
- [%+ terms.bug %]. The comment will have a link back to the review page so
- that people can see your comments with the full context.
-
-Saved drafts
-
- Whenever you start making changes, a draft is automatically
- saved. If you come back to the patch review page for the same
- attachment, that draft will automatically be resumed. Drafts are
- not visible to anybody else until published.
-
-
- Note that saving drafts requires the your browser to have support
- for the "DOM Storage" standard. At time of writing, this is
- available only in a few very recent browsers, like Firefox
- 3.5. Strict privacy protections like disabling cookies may also
- disable DOM Storage, since it provides another mechanism for
- sites to track information about their users.
-
-Responding to someone's review
-
- A response is treated just like any other review and created the
- same way. A couple of features are helpful when responding: you
- can double-click on an inline comment to respond to it. And on
- the overview page, when you click on a detailed comment, you are
- taken directly to the original location of the comment.
-
-Uploading patches for review
-
- Splinter doesn't really care how patches are provided to
- [%+ terms.Bugzilla %], as long as they are well-formatted patches. If you are
- using Git for version control, you can either format changes as
- patches
- using 'git
- format-patch and attach them manually to the [% terms.bug %], or you
- can
- use git-bz.
- git-bz is highly recommended; it automates most of the steps
- that Splinter can't handle: it files new [% terms.bugs %], attaches updated
- attachments to existing [% terms.bugs %], and closes [% terms.bugs %] when you push the
- corresponding git commits to your central repository.
-
-The [% terms.bug %] review view
-
- Splinter also has a view where it shows all patches attached to
- the [% terms.bug %] with their status and links to review them. You are
- taken to this page after publishing a review. You can also get
- to this page with the [% terms.bug %] link in the upper-right corner of the
- patch review view.
-
-Your reviews
-
- Splinter can also show you a list of all your draft and
- published reviews. Access this page with the "Your reviews"
- link at the bottom of the [% terms.bug %] review view. In-progress drafts
- are shown in bold.
-
-
-[% PROCESS global/footer.html.tmpl %]
diff --git a/extensions/Splinter/web/splinter.css b/extensions/Splinter/web/splinter.css
deleted file mode 100644
index 1cad9a96cb..0000000000
--- a/extensions/Splinter/web/splinter.css
+++ /dev/null
@@ -1,435 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * This Source Code Form is "Incompatible With Secondary Licenses", as
- * defined by the Mozilla Public License, v. 2.0. */
-
-#note {
- padding: .5em;
- background-color: var(--informative-message-background-color);
-}
-
-#error {
- border: 1px solid var(--secondary-control-border-color);
- padding: .5em;
- color: var(--error-message-foreground-color);
-}
-
-#chooseReview {
- margin-top: 1em;
-}
-
-.review-draft .review-desc,
-.review-draft .review-attachment {
- font-weight: bold;
-}
-
-#bugInfo,
-#attachInfo {
- margin-top: .5em;
- margin-bottom: 1em;
-}
-
-#helpful-links {
- float: right;
-}
-
-#chooseAttachment table {
- margin-bottom: 1em;
-}
-
-#attachWarning {
- color: var(--error-message-foreground-color);
- font-weight: bold;
-}
-
-.attachment-draft .attachment-id,
-.attachment-draft .attachment-desc {
- font-weight: bold;
-}
-
-.attachment-obsolete .attachment-desc {
- text-decoration: line-through;
-}
-
-#navigation {
- color: var(--secondary-label-color);
-}
-
-.navigation-link {
- text-decoration: none;
- white-space: nowrap;
-}
-
-.navigation-link-selected {
- color: inherit !important;
- text-decoration: none !important;
- cursor: default;
-}
-
-#haveDraftNotice {
- float: right;
- color: var(--error-message-foreground-color);
- font-weight: bold;
-}
-
-#overview {
- margin-top: .5em;
- margin-bottom: .5em;
-}
-
-#patchIntro {
- margin-bottom: 1em;
- border: 1px solid #888888;
- padding: .5em;
- font-size: var(--font-size-small);
-}
-
-.reviewer-0 .reviewer-box {
- border-left: 10px solid green;
-}
-
-.reviewer-1 .reviewer-box {
- border-left: 10px solid blue;
-}
-
-.reviewer-2 .reviewer-box {
- border-left: 10px solid red;
-}
-
-.reviewer-3 .reviewer-box {
- border-left: 10px solid yellow;
-}
-
-.reviewer-4 .reviewer-box {
- border-left: 10px solid purple;
-}
-
-.reviewer-5 .reviewer-box {
- border-left: 10px solid orange;
-}
-
-.reviewer {
- float: left;
-}
-
-.review-date {
- float: right;
-}
-
-.review-info-bottom {
- clear: both;
-}
-
-.review {
- margin-top: .25em;
- margin-bottom: 1em;
- border: 1px solid var(--secondary-control-border-color);
- font-size: var(--font-size-small);
-}
-
-.review-intro {
- margin-top: .5em;
-}
-
-.review-patch-file {
- margin-top: .5em;
- font-weight: bold;
-}
-
-.review-patch-comment {
- margin-top: .5em;
- margin-bottom: .5em;
- border: 1px solid var(--secondary-region-border-color);
- padding: 1px;
- background-color: var(--secondary-region-background-color);
- cursor: pointer;
-}
-
-.review-patch-comment:hover {
- border: 1px solid var(--hovered-primary-button-border-color);
-}
-
-.review-patch-comment .file-table {
- width: 50%;
-}
-
-.review-patch-comment .file-table-changed {
- width: 100%;
-}
-
-.review-patch-comment-separator {
- margin: .5em;
-}
-
-div.review-patch-comment-text {
- margin-left: 2em;
-}
-
-.review-patch-comment .reviewer-box {
- border-left-width: 4px;
-}
-
-#restored {
- margin-bottom: .5em;
- color: var(--error-message-foreground-color);
-}
-
-#myCommentFrame {
- position: relative;
- margin-top: .25em;
- border: 1px solid var(--secondary-control-border-color);
- padding-right: 8px;
- /* compensate for child's padding */
-}
-
-#myComment {
- margin: 0;
- width: 100%;
- height: 10em;
-}
-
-#emptyCommentNotice {
- position: absolute;
- top: 8px;
- left: 8px;
- color: var(--placeholder-text-color);
-}
-
-#myPatchComments {
- border: 1px solid var(--secondary-control-border-color);
- border-top-width: 0;
- padding: .5em;
-}
-
-#buttonBox {
- float: right;
- margin-top: .5em;
-}
-
-.clear {
- clear: both;
-}
-
-.pre-wrap {
- white-space: pre-wrap;
-}
-
-#splinter-files {
- position: relative;
- margin-top: .5em;
- margin-bottom: .5em;
-}
-
-.file-label {
- margin-top: 1em;
- margin-bottom: .5em;
-}
-
-.file-label-name {
- font-weight: bold;
-}
-
-.file-label-extra {
- font-size: var(--font-size-small);
- font-style: italic;
-}
-
-.hunk-header {
- border: 1px solid var(--grid-border-color);
-}
-
-.hunk-header td {
- background-color: var(--grid-header-background-color);
- font-weight: bold;
-}
-
-.hunk-cell {
- padding: 2px;
-}
-
-.old-line,
-.new-line {
- font-family: var(--font-family-monospace);
- font-size-adjust: .5;
- white-space: pre-wrap;
-}
-
-.old-line.removed-line,
-.old-line.changed-line {
- background-color: rgba(var(--accent-color-pink-1), .5);
-}
-
-.new-line.added-line,
-.new-line.changed-line {
- background-color: rgba(var(--accent-color-lightgreen-1), .5);
-}
-
-.file-table {
- table-layout: fixed;
- border: 1px solid var(--grid-border-color);
- width: 100%;
- background-color: var(--grid-background-color);
-}
-
-.file-table td {
- padding: 2px 4px;
-}
-
-.line-middle {
- border-left: 1px solid var(--grid-border-color);
- padding: 0 !important;
- width: 0;
-}
-
-.line-number {
- color: var(--tertiary-label-color);
- font-size: var(--font-size-small);
- font-size-adjust: .5;
- font-family: var(--font-family-monospace);
- text-align: right;
- -moz-user-select: none;
- -webkit-user-select: none;
- user-select: none;
-}
-
-.line-number.old.removed-line,
-.line-number.old.changed-line {
- color: var(--secondary-label-color);
- background-color: rgba(var(--accent-color-pink-1), .8);
-}
-
-.line-number.new.added-line,
-.line-number.new.changed-line {
- color: var(--secondary-label-color);
- background-color: rgba(var(--accent-color-lightgreen-1), .8);
-}
-
-.line-number-column {
- width: 2em;
-}
-
-.file-table-wide-numbers .line-number-column {
- width: 3em;
-}
-
-.middle-column {
- width: 3px;
-}
-
-.file-table-changed .comment-removed {
- float: left;
- width: 50%;
-}
-
-.file-table-changed .comment-changed {
- clear: both;
- margin-left: 25%;
- margin-right: 25%;
-}
-
-.file-table-changed .comment-added {
- float: right;
- width: 50%;
-}
-
-.comment-frame {
- border: 1px solid var(--secondary-control-border-color);
- margin-top: 4px;
- margin-bottom: 4px;
- margin-left: 2em;
-}
-
-.file-table-wide-numbers .comment-frame {
- margin-left: 3em;
-}
-
-.comment .review-info {
- margin-top: .5em;
- font-size: var(--font-size-small);
-}
-
-#commentTextFrame {
- margin-bottom: 4px;
-}
-
-#commentEditorInner {
- margin-left: 2em;
- padding: 4px;
-}
-
-.file-table-wide-numbers #commentEditorInner {
- margin-left: 3em;
-}
-
-#commentEditor textarea {
- width: 100%;
- height: 10em;
-}
-
-#commentEditorLeftButtons {
- float: left;
-}
-
-#commentEditorLeftButtons input {
- margin-right: .5em;
-}
-
-#commentEditorRightButtons {
- float: right;
-}
-
-.comment-separator-removed {
- clear: left;
-}
-
-.comment-separator-added {
- clear: right;
-}
-
-#saveDraftNotice {
- position: fixed;
- bottom: 0;
- right: 0;
- border: 1px solid var(--secondary-control-border-color);
- padding: .5em;
- background-color: var(--informative-message-background-color);
-}
-
-#credits {
- padding: 10px;
- color: var(--secondary-label-color);
- font-size: var(--font-size-small);
- text-align: center;
-}
-
-#quickHelpShow a,
-#quickHelpContent a {
- text-decoration: none;
-}
-
-#quickHelpContent {
- margin-bottom: 10px;
- border: 1px solid var(--secondary-region-border-color);
- border-radius: 4px;
- padding-left: .5em;
- background-color: var(--secondary-region-background-color);
-}
-
-.file-label-collapse {
- padding-right: 4px;
- font-family: var(--font-family-monospace);
-}
-
-.file-review-label {
- font-size: var(--font-size-small);
-}
-
-.file-reviewed-nav {
- text-decoration: line-through;
-}
-
-.trailing-whitespace {
- background: rgb(var(--accent-color-pink-1));
-}
diff --git a/extensions/Splinter/web/splinter.js b/extensions/Splinter/web/splinter.js
deleted file mode 100644
index 3316b7779f..0000000000
--- a/extensions/Splinter/web/splinter.js
+++ /dev/null
@@ -1,2718 +0,0 @@
-// Splinter - patch review add-on for Bugzilla
-// By Owen Taylor
-// Copyright 2009, Red Hat, Inc.
-// Licensed under MPL 1.1 or later, or GPL 2 or later
-// http://git.fishsoup.net/cgit/splinter
-// Converted to YUI by David Lawrence
-
-YAHOO.namespace('Splinter');
-
-var Dom = YAHOO.util.Dom;
-var Event = YAHOO.util.Event;
-var Splinter = YAHOO.Splinter;
-var Element = YAHOO.util.Element;
-
-Splinter.domCache = {
- cache : [0],
- expando : 'data' + new Date(),
- data : function (elem) {
- var cacheIndex = elem[Splinter.domCache.expando];
- var nextCacheIndex = Splinter.domCache.cache.length;
- if (!cacheIndex) {
- cacheIndex = elem[Splinter.domCache.expando] = nextCacheIndex;
- Splinter.domCache.cache[cacheIndex] = {};
- }
- return Splinter.domCache.cache[cacheIndex];
- }
-};
-
-Splinter.Utils = {
- assert : function(condition) {
- if (!condition) {
- throw new Error("Assertion failed");
- }
- },
-
- assertNotReached : function() {
- throw new Error("Assertion failed: should not be reached");
- },
-
- strip : function(string) {
- return (/^\s*([\s\S]*?)\s*$/).exec(string)[1];
- },
-
- lstrip : function(string) {
- return (/^\s*([\s\S]*)$/).exec(string)[1];
- },
-
- rstrip : function(string) {
- return (/^([\s\S]*?)\s*$/).exec(string)[1];
- },
-
- formatDate : function(date, now) {
- if (now == null) {
- now = new Date();
- }
- var daysAgo = (now.getTime() - date.getTime()) / (24 * 60 * 60 * 1000);
- if (daysAgo < 0 && now.getDate() != date.getDate()) {
- return date.toLocaleDateString();
- } else if (daysAgo < 1 && now.getDate() == date.getDate()) {
- return date.toLocaleTimeString();
- } else if (daysAgo < 7 && now.getDay() != date.getDay()) {
- return ['Sun', 'Mon','Tue','Wed','Thu','Fri','Sat'][date.getDay()] + " " + date.toLocaleTimeString();
- } else {
- return date.toLocaleDateString();
- }
- },
-
- preWrapLines : function(el, text) {
- while ((m = Splinter.LINE_RE.exec(text)) != null) {
- var div = document.createElement("div");
- div.className = "pre-wrap";
- div.appendChild(document.createTextNode(m[1].length == 0 ? " " : m[1]));
- el.appendChild(div);
- }
- },
-
- isDigits : function (str) {
- return str.match(/^[0-9]+$/);
- }
-};
-
-Splinter.Bug = {
- TIMEZONES : {
- CEST: '200',
- CET: '100',
- BST: '100',
- GMT: '000',
- UTC: '000',
- EDT: '-400',
- EST: '-500',
- CDT: '-500',
- CST: '-600',
- MDT: '-600',
- MST: '-700',
- PDT: '-700',
- PST: '-800'
- },
-
- parseDate : function(d) {
- var m = /^\s*(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)(?::(\d+))?\s+(?:([A-Z]{3,})|([-+]\d{3,}))\s*$/.exec(d);
- if (!m) {
- return null;
- }
-
- var year = parseInt(m[1], 10);
- var month = parseInt(m[2] - 1, 10);
- var day = parseInt(m[3], 10);
- var hour = parseInt(m[4], 10);
- var minute = parseInt(m[5], 10);
- var second = m[6] ? parseInt(m[6], 10) : 0;
-
- var tzoffset = 0;
- if (m[7]) {
- if (m[7] in Splinter.Bug.TIMEZONES) {
- tzoffset = Splinter.Bug.TIMEZONES[m[7]];
- }
- } else {
- tzoffset = parseInt(m[8], 10);
- }
-
- var unadjustedDate = new Date(Date.UTC(m[1], m[2] - 1, m[3], m[4], m[5]));
-
- // 430 => 4:30. Easier to do this computation for only positive offsets
- var sign = tzoffset < 0 ? -1 : 1;
- tzoffset *= sign;
- var adjustmentHours = Math.floor(tzoffset/100);
- var adjustmentMinutes = tzoffset - adjustmentHours * 100;
-
- return new Date(unadjustedDate.getTime() -
- sign * adjustmentHours * 3600000 -
- sign * adjustmentMinutes * 60000);
- },
-
- _formatWho : function(name, email) {
- if (name && email) {
- return name + " <" + email + ">";
- } else if (name) {
- return name;
- } else {
- return email;
- }
- }
-};
-
-Splinter.Bug.Attachment = function(bug, id) {
- this._init(bug, id);
-};
-
-Splinter.Bug.Attachment.prototype = {
- _init : function(bug, id) {
- this.bug = bug;
- this.id = id;
- }
-};
-
-Splinter.Bug.Comment = function(bug) {
- this._init(bug);
-};
-
-Splinter.Bug.Comment.prototype = {
- _init : function(bug) {
- this.bug = bug;
- },
-
- getWho : function() {
- return Splinter.Bug._formatWho(this.whoName, this.whoEmail);
- }
-};
-
-Splinter.Bug.Bug = function() {
- this._init();
-};
-
-Splinter.Bug.Bug.prototype = {
- _init : function() {
- this.attachments = [];
- this.comments = [];
- },
-
- getAttachment : function(attachmentId) {
- var i;
- for (i = 0; i < this.attachments.length; i++) {
- if (this.attachments[i].id == attachmentId) {
- return this.attachments[i];
- }
- }
- return null;
- },
-
- getReporter : function() {
- return Splinter.Bug._formatWho(this.reporterName, this.reporterEmail);
- }
-};
-
-Splinter.Dialog = function() {
- this._init.apply(this, arguments);
-};
-
-Splinter.Dialog.prototype = {
- _init: function(prompt) {
- this.buttons = [];
- this.dialog = new YAHOO.widget.SimpleDialog('dialog', {
- width: "300px",
- fixedcenter: true,
- visible: false,
- modal: true,
- draggable: false,
- close: false,
- hideaftersubmit: true,
- constraintoviewport: true
- });
- this.dialog.setHeader(prompt);
- },
-
- addButton : function (label, callback, isdefault) {
- this.buttons.push({ text : label,
- handler : function () { this.hide(); callback(); },
- isDefault : isdefault });
- this.dialog.cfg.queueProperty("buttons", this.buttons);
- },
-
- show : function () {
- this.dialog.render(document.body);
- this.dialog.show();
- }
-};
-
-Splinter.Patch = {
- ADDED : 1 << 0,
- REMOVED : 1 << 1,
- CHANGED : 1 << 2,
- NEW_NONEWLINE : 1 << 3,
- OLD_NONEWLINE : 1 << 4,
-
- FILE_START_RE : new RegExp(
- '^(?:' + // start of optional header
- '(?:Index|index|===|RCS|diff)[^\\n]*\\n' + // header
- '(?:(?:copy|rename) from [^\\n]+\\n)?' + // git copy/rename from
- '(?:(?:copy|rename) to [^\\n]+\\n)?' + // git copy/rename to
- ')*' + // end of optional header
- '\\-\\-\\-[ \\t]*(\\S+).*\\n' + // --- line
- '\\+\\+\\+[ \\t]*(\\S+).*\\n' + // +++ line
- '(?=@@)', // @@ line
- 'mg'
- ),
- HUNK_START1_RE: /^@@[ \t]+-(\d+),(\d+)[ \t]+\+(\d+),(\d+)[ \t]+@@(.*)\n/mg, // -l,s +l,s
- HUNK_START2_RE: /^@@[ \t]+-(\d+),(\d+)[ \t]+\+(\d+)[ \t]+@@(.*)\n/mg, // -l,s +l
- HUNK_START3_RE: /^@@[ \t]+-(\d+)[ \t]+\+(\d+),(\d+)[ \t]+@@(.*)\n/mg, // -l +l,s
- HUNK_START4_RE: /^@@[ \t]+-(\d+)[ \t]+\+(\d+)[ \t]+@@(.*)\n/mg, // -l +l
- HUNK_RE : /((?:(?!--- )[ +\\-].*(?:\n|$)|(?:\n|$))*)/mg,
-
- GIT_BINARY_RE : /^diff --git a\/(\S+).*\n(?:(new|deleted) file mode \d+\n)?(?:index.*\n)?GIT binary patch\n(delta )?/mg,
-
- _cleanIntro : function(intro) {
- var m;
-
- intro = Splinter.Utils.strip(intro) + "\n\n";
-
- // Git: remove binary diffs
- var binary_re = /^(?:diff --git .*\n|literal \d+\n)(?:.+\n)+\n/mg;
- m = binary_re.exec(intro);
- while (m) {
- intro = intro.substr(m.index + m[0].length);
- binary_re.lastIndex = 0;
- m = binary_re.exec(intro);
- }
-
- // Git: remove leading 'From '
- m = /^From\s+[a-f0-9]{40}.*\n/.exec(intro);
- if (m) {
- intro = intro.substr(m.index + m[0].length);
- }
-
- // Git: remove 'diff --stat' output from the end
- m = /^---\n(?:^\s.*\n)+\s+\d+\s+files changed.*\n?(?!.)/m.exec(intro);
- if (m) {
- intro = intro.substr(0, m.index);
- }
-
- return Splinter.Utils.strip(intro);
- }
-};
-
-Splinter.Patch.Hunk = function(oldStart, oldCount, newStart, newCount, functionLine, text) {
- this._init(oldStart, oldCount, newStart, newCount, functionLine, text);
-};
-
-Splinter.Patch.Hunk.prototype = {
- _init : function(oldStart, oldCount, newStart, newCount, functionLine, text) {
- var rawlines = text.split("\n");
- if (rawlines.length > 0 && Splinter.Utils.strip(rawlines[rawlines.length - 1]) == "") {
- rawlines.pop(); // Remove trailing element from final \n
- }
-
- this.oldStart = oldStart;
- this.oldCount = oldCount;
- this.newStart = newStart;
- this.newCount = newCount;
- this.functionLine = Splinter.Utils.strip(functionLine);
- this.comment = null;
-
- var lines = [];
- var totalOld = 0;
- var totalNew = 0;
-
- var currentStart = -1;
- var currentOldCount = 0;
- var currentNewCount = 0;
-
- // A segment is a series of lines added/removed/changed with no intervening
- // unchanged lines. We make the classification of Patch.ADDED/Patch.REMOVED/Patch.CHANGED
- // in the flags for the entire segment
- function startSegment() {
- if (currentStart < 0) {
- currentStart = lines.length;
- }
- }
-
- function endSegment() {
- if (currentStart >= 0) {
- if (currentOldCount > 0 && currentNewCount > 0) {
- var j;
- for (j = currentStart; j < lines.length; j++) {
- lines[j][2] &= ~(Splinter.Patch.ADDED | Splinter.Patch.REMOVED);
- lines[j][2] |= Splinter.Patch.CHANGED;
- }
- }
-
- currentStart = -1;
- currentOldCount = 0;
- currentNewCount = 0;
- }
- }
-
- var i;
- for (i = 0; i < rawlines.length; i++) {
- var line = rawlines[i];
- var op = line.substr(0, 1);
- var strippedLine = line.substring(1);
- var noNewLine = 0;
- if (i + 1 < rawlines.length && rawlines[i + 1].substr(0, 1) == '\\') {
- noNewLine = op == '-' ? Splinter.Patch.OLD_NONEWLINE : Splinter.Patch.NEW_NONEWLINE;
- }
-
- if (op == ' ') {
- endSegment();
- totalOld++;
- totalNew++;
- lines.push([strippedLine, strippedLine, 0]);
- } else if (op == '-') {
- totalOld++;
- startSegment();
- lines.push([strippedLine, null, Splinter.Patch.REMOVED | noNewLine]);
- currentOldCount++;
- } else if (op == '+') {
- totalNew++;
- startSegment();
- if (currentStart + currentNewCount >= lines.length) {
- lines.push([null, strippedLine, Splinter.Patch.ADDED | noNewLine]);
- } else {
- lines[currentStart + currentNewCount][1] = strippedLine;
- lines[currentStart + currentNewCount][2] |= Splinter.Patch.ADDED | noNewLine;
- }
- currentNewCount++;
- }
- }
-
- // git mail-formatted patches end with --\n like a signature
- // This is troublesome since it looks like a subtraction at the end
- // of last hunk of the last file. Handle this specifically rather than
- // generically stripping excess lines to be kind to hand-edited patches
- if (totalOld > oldCount &&
- lines[lines.length - 1][1] == null &&
- lines[lines.length - 1][0].substr(0, 1) == '-')
- {
- lines.pop();
- currentOldCount--;
- if (currentOldCount == 0 && currentNewCount == 0) {
- currentStart = -1;
- }
- }
-
- endSegment();
-
- this.lines = lines;
- },
-
- iterate : function(cb) {
- var i;
- var oldLine = this.oldStart;
- var newLine = this.newStart;
- for (i = 0; i < this.lines.length; i++) {
- var line = this.lines[i];
- cb(this.location + i, oldLine, line[0], newLine, line[1], line[2], line);
- if (line[0] != null) {
- oldLine++;
- }
- if (line[1] != null) {
- newLine++;
- }
- }
- }
-};
-
-Splinter.Patch.File = function(filename, status, extra, hunks) {
- this._init(filename, status, extra, hunks);
-};
-
-Splinter.Patch.File.prototype = {
- _init : function(filename, status, extra, hunks) {
- this.filename = filename;
- this.status = status;
- this.extra = extra;
- this.hunks = hunks;
- this.fileReviewed = false;
-
- var l = 0;
- var i;
- for (i = 0; i < this.hunks.length; i++) {
- var hunk = this.hunks[i];
- hunk.location = l;
- l += hunk.lines.length;
- }
- },
-
- // A "location" is just a linear index into the lines of the patch in this file
- getLocation : function(oldLine, newLine) {
- var i;
- for (i = 0; i < this.hunks.length; i++) {
- var hunk = this.hunks[i];
- if (oldLine != null && hunk.oldStart > oldLine) {
- continue;
- }
- if (newLine != null && hunk.newStart > newLine) {
- continue;
- }
-
- if ((oldLine != null && oldLine < hunk.oldStart + hunk.oldCount) ||
- (newLine != null && newLine < hunk.newStart + hunk.newCount))
- {
- var location = -1;
- hunk.iterate(function(loc, oldl, oldText, newl, newText, flags) {
- if ((oldLine == null || oldl == oldLine) &&
- (newLine == null || newl == newLine))
- {
- location = loc;
- }
- });
-
- if (location != -1) {
- return location;
- }
- }
- }
-
- throw "Bad oldLine,newLine: " + oldLine + "," + newLine;
- },
-
- getHunk : function(location) {
- var i;
- for (i = 0; i < this.hunks.length; i++) {
- var hunk = this.hunks[i];
- if (location >= hunk.location && location < hunk.location + hunk.lines.length) {
- return hunk;
- }
- }
-
- throw "Bad location: " + location;
- },
-
- toString : function() {
- return "Splinter.Patch.File(" + this.filename + ")";
- }
-};
-
-Splinter.Patch.Patch = function(text) {
- this._init(text);
-};
-
-Splinter.Patch.Patch.prototype = {
- // cf. parsing in Review.Review.parse()
- _init : function(text) {
- // Canonicalize newlines to simplify the following
- if (/\r/.test(text)) {
- text = text.replace(/(\r\n|\r|\n)/g, "\n");
- }
-
- this.files = [];
-
- var m = Splinter.Patch.FILE_START_RE.exec(text);
- var bm = Splinter.Patch.GIT_BINARY_RE.exec(text);
- if (m == null && bm == null)
- throw "Not a patch";
- this.intro = m == null ? '' : Splinter.Patch._cleanIntro(text.substring(0, m.index));
-
- // show binary files in the intro
-
- if (bm && this.intro.length)
- this.intro += "\n\n";
- while (bm != null) {
- if (bm[2]) {
- // added or deleted file
- this.intro += bm[2].charAt(0).toUpperCase() + bm[2].slice(1) + ' Binary File: ' + bm[1] + "\n";
- } else {
- // delta
- this.intro += 'Modified Binary File: ' + bm[1] + "\n";
- }
- bm = Splinter.Patch.GIT_BINARY_RE.exec(text);
- }
-
- while (m != null) {
- // git shows a diff between a/foo/bar.c and b/foo/bar.c or between
- // a/foo/bar.c and /dev/null for removals and the reverse for
- // additions.
- var filename;
- var status = undefined;
- var extra = undefined;
-
- if (/^a\//.test(m[1]) && /^b\//.test(m[2])) {
- filename = m[2].substring(2);
- status = Splinter.Patch.CHANGED;
- } else if (/^a\//.test(m[1]) && /^\/dev\/null/.test(m[2])) {
- filename = m[1].substring(2);
- status = Splinter.Patch.REMOVED;
- } else if (/^\/dev\/null/.test(m[1]) && /^b\//.test(m[2])) {
- filename = m[2].substring(2);
- status = Splinter.Patch.ADDED;
- // Handle non-git cases as well
- } else if (!/^\/dev\/null/.test(m[1]) && /^\/dev\/null/.test(m[2])) {
- filename = m[1];
- status = Splinter.Patch.REMOVED;
- } else if (/^\/dev\/null/.test(m[1]) && !/^\/dev\/null/.test(m[2])) {
- filename = m[2];
- status = Splinter.Patch.ADDED;
- } else {
- filename = m[1];
- }
-
- // look for rename/copy
- if (/^diff /.test(m[0])) {
- // possibly git
- var lines = m[0].split(/\n/);
- for (var i = 0, il = lines.length; i < il && !extra; i++) {
- var line = lines[i];
- if (line != '' && !/^(?:diff|---|\+\+\+) /.test(line)) {
- if (/^copy from /.test(line))
- extra = 'copied from ' + m[1].substring(2);
- if (/^rename from /.test(line))
- extra = 'renamed from ' + m[1].substring(2);
- }
- }
- } else if (/^=== renamed /.test(m[0])) {
- // bzr
- filename = m[2];
- extra = 'renamed from ' + m[1];
- }
-
- var hunks = [];
- var pos = Splinter.Patch.FILE_START_RE.lastIndex;
- while (true) {
- var found = false;
- var oldStart, oldCount, newStart, newCount, context;
-
- // -l,s +l,s
- var re = Splinter.Patch.HUNK_START1_RE;
- re.lastIndex = pos;
- var m2 = re.exec(text);
- if (m2 != null && m2.index == pos) {
- oldStart = parseInt(m2[1], 10);
- oldCount = parseInt(m2[2], 10);
- newStart = parseInt(m2[3], 10);
- newCount = parseInt(m2[4], 10);
- context = m2[5];
- found = true;
- }
-
- if (!found) {
- // -l,s +l
- re = Splinter.Patch.HUNK_START2_RE;
- re.lastIndex = pos;
- m2 = re.exec(text);
- if (m2 != null && m2.index == pos) {
- oldStart = parseInt(m2[1], 10);
- oldCount = parseInt(m2[2], 10);
- newStart = parseInt(m2[3], 10);
- newCount = 1;
- context = m2[4];
- found = true;
- }
- }
-
- if (!found) {
- // -l +l,s
- re = Splinter.Patch.HUNK_START3_RE;
- re.lastIndex = pos;
- m2 = re.exec(text);
- if (m2 != null && m2.index == pos) {
- oldStart = parseInt(m2[1], 10);
- oldCount = 1;
- newStart = parseInt(m2[2], 10);
- newCount = parseInt(m2[3], 10);
- context = m2[4];
- found = true;
- }
- }
-
- if (!found) {
- // -l +l
- re = Splinter.Patch.HUNK_START4_RE;
- re.lastIndex = pos;
- m2 = re.exec(text);
- if (m2 != null && m2.index == pos) {
- oldStart = parseInt(m2[1], 10);
- oldCount = 1;
- newStart = parseInt(m2[2], 10);
- newCount = 1;
- context = m2[3];
- found = true;
- }
- }
-
- if (!found)
- break;
-
- pos = re.lastIndex;
- Splinter.Patch.HUNK_RE.lastIndex = pos;
- var m3 = Splinter.Patch.HUNK_RE.exec(text);
- if (m3 == null || m3.index != pos) {
- break;
- }
-
- pos = Splinter.Patch.HUNK_RE.lastIndex;
- hunks.push(new Splinter.Patch.Hunk(oldStart, oldCount, newStart, newCount, context, m3[1]));
- }
-
- if (status === undefined) {
- // For non-Git we use assume patch was generated non-zero
- // context and just look at the patch to detect added/removed.
- // Bzr actually says added/removed in the diff, but SVN/CVS
- // don't
- if (hunks.length == 1 && hunks[0].oldCount == 0) {
- status = Splinter.Patch.ADDED;
- } else if (hunks.length == 1 && hunks[0].newCount == 0) {
- status = Splinter.Patch.REMOVED;
- } else {
- status = Splinter.Patch.CHANGED;
- }
- }
-
- this.files.push(new Splinter.Patch.File(filename, status, extra, hunks));
-
- Splinter.Patch.FILE_START_RE.lastIndex = pos;
- m = Splinter.Patch.FILE_START_RE.exec(text);
- }
- },
-
- getFile : function(filename) {
- var i;
- for (i = 0; i < this.files.length; i++) {
- if (this.files[i].filename == filename) {
- return this.files[i];
- }
- }
-
- return null;
- }
-};
-
-Splinter.Review = {
- _removeFromArray : function(a, element) {
- var i;
- for (i = 0; i < a.length; i++) {
- if (a[i] === element) {
- a.splice(i, 1);
- return;
- }
- }
- },
-
- _noNewLine : function(flags, flag) {
- return ((flags & flag) != 0) ? "\n\\ No newline at end of file" : "";
- },
-
- _lineInSegment : function(line) {
- return (line[2] & (Splinter.Patch.ADDED | Splinter.Patch.REMOVED | Splinter.Patch.CHANGED)) != 0;
- },
-
- _compareSegmentLines : function(a, b) {
- var op1 = a[0];
- var op2 = b[0];
- if (op1 == op2) {
- return 0;
- } else if (op1 == ' ') {
- return -1;
- } else if (op2 == ' ') {
- return 1;
- } else {
- return op1 == '-' ? -1 : 1;
- }
- },
-
- FILE_START_RE : /^:::[ \t]+(\S+)[ \t]*\n/mg,
- HUNK_START_RE : /^@@[ \t]+(?:-(\d+),(\d+)[ \t]+)?(?:\+(\d+),(\d+)[ \t]+)?@@.*\n/mg,
- HUNK_RE : /((?:(?!@@|:::).*\n?)*)/mg,
- REVIEW_RE : /^\s*review\s+of\s+attachment\s+(\d+)\s*:\s*/i
-};
-
-Splinter.Review.Comment = function(file, location, type, comment) {
- this._init(file, location, type, comment);
-};
-
-Splinter.Review.Comment.prototype = {
- _init : function(file, location, type, comment) {
- this.file = file;
- this.type = type;
- this.location = location;
- this.comment = comment;
- },
-
- getHunk : function() {
- return this.file.patchFile.getHunk(this.location);
- },
-
- getInReplyTo : function() {
- var i;
- var hunk = this.getHunk();
- var line = hunk.lines[this.location - hunk.location];
- for (i = 0; i < line.reviewComments.length; i++) {
- var comment = line.reviewComments[i];
- if (comment === this) {
- return null;
- }
- if (comment.type == this.type) {
- return comment;
- }
- }
-
- return null;
- },
-
- remove : function() {
- var hunk = this.getHunk();
- var line = hunk.lines[this.location - hunk.location];
- Splinter.Review._removeFromArray(this.file.comments, this);
- Splinter.Review._removeFromArray(line.reviewComments, this);
- }
-};
-
-Splinter.Review.File = function(review, patchFile) {
- this._init(review, patchFile);
-};
-
-Splinter.Review.File.prototype = {
- _init : function(review, patchFile) {
- this.review = review;
- this.patchFile = patchFile;
- this.comments = [];
- },
-
- addComment : function(location, type, comment) {
- var hunk = this.patchFile.getHunk(location);
- var line = hunk.lines[location - hunk.location];
- comment = new Splinter.Review.Comment(this, location, type, comment);
- if (line.reviewComments == null) {
- line.reviewComments = [];
- }
- line.reviewComments.push(comment);
- var i;
- for (i = 0; i <= this.comments.length; i++) {
- if (i == this.comments.length ||
- this.comments[i].location > location ||
- (this.comments[i].location == location && this.comments[i].type > type)) {
- this.comments.splice(i, 0, comment);
- break;
- } else if (this.comments[i].location == location &&
- this.comments[i].type == type) {
- throw "Two comments at the same location";
- }
- }
-
- return comment;
- },
-
- getComment : function(location, type) {
- var i;
- for (i = 0; i < this.comments.length; i++) {
- if (this.comments[i].location == location &&
- this.comments[i].type == type)
- {
- return this.comments[i];
- }
- }
-
- return null;
- },
-
- toString : function() {
- var str = "::: " + this.patchFile.filename + "\n";
- var first = true;
-
- var i;
- for (i = 0; i < this.comments.length; i++) {
- if (first) {
- first = false;
- } else {
- str += '\n';
- }
- var comment = this.comments[i];
- var hunk = comment.getHunk();
-
- // Find the range of lines we might want to show. That's everything in the
- // same segment as the commented line, plus up two two lines of non-comment
- // diff before.
-
- var contextFirst = comment.location - hunk.location;
- if (Splinter.Review._lineInSegment(hunk.lines[contextFirst])) {
- while (contextFirst > 0 && Splinter.Review._lineInSegment(hunk.lines[contextFirst - 1])) {
- contextFirst--;
- }
- }
-
- var j;
- for (j = 0; j < 5; j++) {
- if (contextFirst > 0 && !Splinter.Review._lineInSegment(hunk.lines[contextFirst - 1])) {
- contextFirst--;
- }
- }
-
- // Now get the diff lines (' ', '-', '+' for that range of lines)
-
- var patchOldStart = null;
- var patchNewStart = null;
- var patchOldLines = 0;
- var patchNewLines = 0;
- var unchangedLines = 0;
- var patchLines = [];
-
- function addOldLine(oldLine) {
- if (patchOldLines == 0) {
- patchOldStart = oldLine;
- }
- patchOldLines++;
- }
-
- function addNewLine(newLine) {
- if (patchNewLines == 0) {
- patchNewStart = newLine;
- }
- patchNewLines++;
- }
-
- hunk.iterate(function(loc, oldLine, oldText, newLine, newText, flags) {
- if (loc >= hunk.location + contextFirst && loc <= comment.location) {
- if ((flags & (Splinter.Patch.ADDED | Splinter.Patch.REMOVED | Splinter.Patch.CHANGED)) == 0) {
- patchLines.push('> ' + oldText + Splinter.Review._noNewLine(flags, Splinter.Patch.OLD_NONEWLINE | Splinter.Patch.NEW_NONEWLINE));
- addOldLine(oldLine);
- addNewLine(newLine);
- unchangedLines++;
- } else {
- if ((comment.type == Splinter.Patch.REMOVED
- || comment.type == Splinter.Patch.CHANGED)
- && oldText != null)
- {
- patchLines.push('> -' + oldText +
- Splinter.Review._noNewLine(flags, Splinter.Patch.OLD_NONEWLINE));
- addOldLine(oldLine);
- }
- if ((comment.type == Splinter.Patch.ADDED
- || comment.type == Splinter.Patch.CHANGED)
- && newText != null)
- {
- patchLines.push('> +' + newText +
- Splinter.Review._noNewLine(flags, Splinter.Patch.NEW_NONEWLINE));
- addNewLine(newLine);
- }
- }
- }
- });
-
- // Sort them into global order ' ', '-', '+'
- patchLines.sort(Splinter.Review._compareSegmentLines);
-
- // Completely blank context isn't useful so remove it; however if we are commenting
- // on blank lines at the start of a segment, we have to leave something or things break
- while (patchLines.length > 1 && patchLines[0].match(/^\s*$/)) {
- patchLines.shift();
- patchOldStart++;
- patchNewStart++;
- patchOldLines--;
- patchNewLines--;
- unchangedLines--;
- }
-
- if (comment.type == Splinter.Patch.CHANGED) {
- // For a CHANGED comment, we have to show the the start of the hunk - but to save
- // in length we can trim unchanged context before it
-
- if (patchOldLines + patchNewLines - unchangedLines > 5) {
- var toRemove = Math.min(unchangedLines, patchOldLines + patchNewLines - unchangedLines - 5);
- patchLines.splice(0, toRemove);
- patchOldStart += toRemove;
- patchNewStart += toRemove;
- patchOldLines -= toRemove;
- patchNewLines -= toRemove;
- unchangedLines -= toRemove;
- }
-
- str += '@@ -' + patchOldStart + ',' + patchOldLines + ' +' + patchNewStart + ',' + patchNewLines + ' @@\n';
-
- // We will use up to 10 lines more:
- // 5 old lines or 4 old lines and a "... more ... " line
- // 5 new lines or 4 new lines and a "... more ... " line
-
- var patchRemovals = patchOldLines - unchangedLines;
- var showPatchRemovals = patchRemovals > 5 ? 4 : patchRemovals;
- var patchAdditions = patchNewLines - unchangedLines;
- var showPatchAdditions = patchAdditions > 5 ? 4 : patchAdditions;
-
- j = 0;
- while (j < unchangedLines + showPatchRemovals) {
- str += "> " + patchLines[j] + "\n";
- j++;
- }
- if (showPatchRemovals < patchRemovals) {
- str += "> ... " + (patchRemovals - showPatchRemovals) + " more ...\n";
- j += patchRemovals - showPatchRemovals;
- }
- while (j < unchangedLines + patchRemovals + showPatchAdditions) {
- str += "> " + patchLines[j] + "\n";
- j++;
- }
- if (showPatchAdditions < patchAdditions) {
- str += "> ... " + (patchAdditions - showPatchAdditions) + " more ...\n";
- j += patchAdditions - showPatchAdditions;
- }
- } else {
- // We limit Patch.ADDED/Patch.REMOVED comments strictly to 5 lines after the header
- if (patchOldLines + patchNewLines - unchangedLines > 5) {
- var toRemove = patchOldLines + patchNewLines - unchangedLines - 5;
- patchLines.splice(0, toRemove);
- patchOldStart += toRemove;
- patchNewStart += toRemove;
- patchOldLines -= toRemove;
- patchNewLines -= toRemove;
- }
-
- if (comment.type == Splinter.Patch.REMOVED) {
- str += '@@ -' + patchOldStart + ',' + patchOldLines + ' @@\n';
- } else {
- str += '@@ +' + patchNewStart + ',' + patchNewLines + ' @@\n';
- }
- str += patchLines.join("\n") + "\n";
- }
- str += "\n" + comment.comment + "\n";
- }
-
- return str;
- }
-};
-
-Splinter.Review.Review = function(patch, who, date) {
- this._init(patch, who, date);
-};
-
-Splinter.Review.Review.prototype = {
- _init : function(patch, who, date) {
- this.date = null;
- this.patch = patch;
- this.who = who;
- this.date = date;
- this.intro = null;
- this.files = [];
-
- var i;
- for (i = 0; i < patch.files.length; i++) {
- this.files.push(new Splinter.Review.File(this, patch.files[i]));
- }
- },
-
- // cf. parsing in Patch.Patch._init()
- parse : function(text) {
- Splinter.Review.FILE_START_RE.lastIndex = 0;
- var m = Splinter.Review.FILE_START_RE.exec(text);
-
- var intro;
- if (m != null) {
- this.setIntro(text.substr(0, m.index));
- } else{
- this.setIntro(text);
- return;
- }
-
- while (m != null) {
- var filename = m[1];
- var file = this.getFile(filename);
- if (file == null) {
- throw "Review.Review refers to filename '" + filename + "' not in reviewed Patch.";
- }
-
- var pos = Splinter.Review.FILE_START_RE.lastIndex;
-
- while (true) {
- Splinter.Review.HUNK_START_RE.lastIndex = pos;
- var m2 = Splinter.Review.HUNK_START_RE.exec(text);
- if (m2 == null || m2.index != pos) {
- break;
- }
-
- pos = Splinter.Review.HUNK_START_RE.lastIndex;
-
- var oldStart, oldCount, newStart, newCount;
- if (m2[1]) {
- oldStart = parseInt(m2[1], 10);
- oldCount = parseInt(m2[2], 10);
- } else {
- oldStart = oldCount = null;
- }
-
- if (m2[3]) {
- newStart = parseInt(m2[3], 10);
- newCount = parseInt(m2[4], 10);
- } else {
- newStart = newCount = null;
- }
-
- var type;
- if (oldStart != null && newStart != null) {
- type = Splinter.Patch.CHANGED;
- } else if (oldStart != null) {
- type = Splinter.Patch.REMOVED;
- } else if (newStart != null) {
- type = Splinter.Patch.ADDED;
- } else {
- throw "Either old or new line numbers must be given";
- }
-
- var oldLine = oldStart;
- var newLine = newStart;
-
- Splinter.Review.HUNK_RE.lastIndex = pos;
- var m3 = Splinter.Review.HUNK_RE.exec(text);
- if (m3 == null || m3.index != pos) {
- break;
- }
-
- pos = Splinter.Review.HUNK_RE.lastIndex;
-
- var rawlines = m3[1].split("\n");
- if (rawlines.length > 0 && rawlines[rawlines.length - 1].match('^/s+$')) {
- rawlines.pop(); // Remove trailing element from final \n
- }
-
- var commentText = null;
-
- var lastSegmentOld = 0;
- var lastSegmentNew = 0;
- var i;
- for (i = 0; i < rawlines.length; i++) {
- var line = rawlines[i];
- var count = 1;
- if (i < rawlines.length - 1 && rawlines[i + 1].match(/^\.\.\. \d+\s+/)) {
- var m3 = /^\.\.\. (\d+)\s+/.exec(rawlines[i + 1]);
- count += parseInt(m3[1], 10);
- i += 1;
- }
- // The check for /^$/ is because if Bugzilla is line-wrapping it also
- // strips completely whitespace lines
- if (line.match(/^>\s+/) || line.match(/^$/)) {
- oldLine += count;
- newLine += count;
- lastSegmentOld = 0;
- lastSegmentNew = 0;
- } else if (line.match(/^(> )?-/)) {
- oldLine += count;
- lastSegmentOld += count;
- } else if (line.match(/^(> )?\+/)) {
- newLine += count;
- lastSegmentNew += count;
- } else if (line.match(/^\\/)) {
- // '\ No newline at end of file' - ignore
- } else {
- if (console)
- console.log("WARNING: Bad content in hunk: " + line);
- if (line != 'NaN more ...') {
- // Tack onto current comment even thou it's invalid
- if (commentText == null) {
- commentText = line;
- } else {
- commentText += "\n" + line;
- }
- }
- }
-
- if ((oldStart == null || oldLine == oldStart + oldCount) &&
- (newStart == null || newLine == newStart + newCount))
- {
- commentText = rawlines.slice(i + 1).join("\n");
- break;
- }
- }
-
- if (commentText == null) {
- if (console)
- console.log("WARNING: No comment found in hunk");
- commentText = "";
- }
-
-
- var location;
- try {
- if (type == Splinter.Patch.CHANGED) {
- if (lastSegmentOld >= lastSegmentNew) {
- oldLine--;
- }
- if (lastSegmentOld <= lastSegmentNew) {
- newLine--;
- }
- location = file.patchFile.getLocation(oldLine, newLine);
- } else if (type == Splinter.Patch.REMOVED) {
- oldLine--;
- location = file.patchFile.getLocation(oldLine, null);
- } else if (type == Splinter.Patch.ADDED) {
- newLine--;
- location = file.patchFile.getLocation(null, newLine);
- }
- } catch(e) {
- if (console)
- console.error(e);
- location = 0;
- }
- file.addComment(location, type, Splinter.Utils.strip(commentText));
- }
-
- Splinter.Review.FILE_START_RE.lastIndex = pos;
- m = Splinter.Review.FILE_START_RE.exec(text);
- }
- },
-
- setIntro : function (intro) {
- intro = Splinter.Utils.strip(intro);
- this.intro = intro != "" ? intro : null;
- },
-
- getFile : function (filename) {
- var i;
- for (i = 0; i < this.files.length; i++) {
- if (this.files[i].patchFile.filename == filename) {
- return this.files[i];
- }
- }
-
- return null;
- },
-
- // Making toString() serialize to our seriaization format is maybe a bit sketchy
- // But the serialization format is designed to be human readable so it works
- // pretty well.
- toString : function () {
- var str = '';
- if (this.intro != null) {
- str += Splinter.Utils.strip(this.intro);
- str += '\n';
- }
-
- var first = this.intro == null;
- var i;
- for (i = 0; i < this.files.length; i++) {
- var file = this.files[i];
- if (file.comments.length > 0) {
- if (first) {
- first = false;
- } else {
- str += '\n';
- }
- str += file.toString();
- }
- }
-
- return str;
- }
-};
-
-Splinter.ReviewStorage = {};
-
-Splinter.ReviewStorage.LocalReviewStorage = function() {
- this._init();
-};
-
-Splinter.ReviewStorage.LocalReviewStorage.available = function() {
- // The try is a workaround for
- // https://bugzilla.mozilla.org/show_bug.cgi?id=517778
- // where if cookies are disabled or set to ask, then the first attempt
- // to access the localStorage property throws a security error.
- try {
- return 'localStorage' in window && window.localStorage != null;
- } catch (e) {
- return false;
- }
-};
-
-Splinter.ReviewStorage.LocalReviewStorage.prototype = {
- _init : function() {
- var reviewInfosText = localStorage.splinterReviews;
- if (reviewInfosText == null) {
- this._reviewInfos = [];
- } else {
- this._reviewInfos = JSON.parse(reviewInfosText);
- }
- },
-
- listReviews : function() {
- return this._reviewInfos;
- },
-
- _reviewPropertyName : function(bug, attachment) {
- return 'splinterReview_' + bug.id + '_' + attachment.id;
- },
-
- loadDraft : function(bug, attachment, patch) {
- var propertyName = this._reviewPropertyName(bug, attachment);
- var reviewText = localStorage[propertyName];
- if (reviewText != null) {
- var review = new Splinter.Review.Review(patch);
- review.parse(reviewText);
- return review;
- } else {
- return null;
- }
- },
-
- _findReview : function(bug, attachment) {
- var i;
- for (i = 0 ; i < this._reviewInfos.length; i++) {
- if (this._reviewInfos[i].bugId == bug.id && this._reviewInfos[i].attachmentId == attachment.id) {
- return i;
- }
- }
-
- return -1;
- },
-
- _updateOrCreateReviewInfo : function(bug, attachment, props) {
- var reviewIndex = this._findReview(bug, attachment);
- var reviewInfo;
-
- var nowTime = Date.now();
- if (reviewIndex >= 0) {
- reviewInfo = this._reviewInfos[reviewIndex];
- this._reviewInfos.splice(reviewIndex, 1);
- } else {
- reviewInfo = {
- bugId: bug.id,
- bugShortDesc: bug.shortDesc,
- attachmentId: attachment.id,
- attachmentDescription: attachment.description,
- creationTime: nowTime
- };
- }
-
- reviewInfo.modificationTime = nowTime;
- for (var prop in props) {
- reviewInfo[prop] = props[prop];
- }
-
- this._reviewInfos.push(reviewInfo);
- localStorage.splinterReviews = JSON.stringify(this._reviewInfos);
- },
-
- _deleteReviewInfo : function(bug, attachment) {
- var reviewIndex = this._findReview(bug, attachment);
- if (reviewIndex >= 0) {
- this._reviewInfos.splice(reviewIndex, 1);
- localStorage.splinterReviews = JSON.stringify(this._reviewInfos);
- }
- },
-
- saveDraft : function(bug, attachment, review, extraProps) {
- var propertyName = this._reviewPropertyName(bug, attachment);
- if (!extraProps) {
- extraProps = {};
- }
- extraProps.isDraft = true;
- this._updateOrCreateReviewInfo(bug, attachment, extraProps);
- localStorage[propertyName] = "" + review;
- },
-
- deleteDraft : function(bug, attachment, review) {
- var propertyName = this._reviewPropertyName(bug, attachment);
-
- this._deleteReviewInfo(bug, attachment);
- delete localStorage[propertyName];
- },
-
- draftPublished : function(bug, attachment) {
- var propertyName = this._reviewPropertyName(bug, attachment);
-
- this._updateOrCreateReviewInfo(bug, attachment, { isDraft: false });
- delete localStorage[propertyName];
- }
-};
-
-Splinter.saveDraftNoticeTimeoutId = null;
-Splinter.navigationLinks = {};
-Splinter.reviewers = {};
-Splinter.savingDraft = false;
-Splinter.UPDATE_ATTACHMENT_SUCCESS = /\s*Changes\s+Submitted/;
-Splinter.LINE_RE = /(?!$)([^\r\n]*)(?:\r\n|\r|\n|$)/g;
-
-Splinter.displayError = function (msg) {
- var el = new Element(document.createElement('p'));
- el.appendChild(document.createTextNode(msg));
- Dom.get('error').appendChild(Dom.get(el));
- Dom.setStyle('error', 'display', 'block');
-};
-
-Splinter.publishReview = function () {
- Splinter.saveComment();
- Splinter.theReview.setIntro(Dom.get('myComment').value);
-
- if (Splinter.reviewStorage) {
- Splinter.reviewStorage.draftPublished(Splinter.theBug,
- Splinter.theAttachment);
- }
-
- var publish_form = Dom.get('publish');
- var publish_token = Dom.get('publish_token');
- var publish_attach_id = Dom.get('publish_attach_id');
- var publish_attach_desc = Dom.get('publish_attach_desc');
- var publish_attach_filename = Dom.get('publish_attach_filename');
- var publish_attach_contenttype = Dom.get('publish_attach_contenttype');
- var publish_attach_ispatch = Dom.get('publish_attach_ispatch');
- var publish_attach_isobsolete = Dom.get('publish_attach_isobsolete');
- var publish_attach_isprivate = Dom.get('publish_attach_isprivate');
- var publish_attach_status = Dom.get('publish_attach_status');
- var publish_review = Dom.get('publish_review');
-
- publish_token.value = Splinter.theAttachment.token;
- publish_attach_id.value = Splinter.theAttachment.id;
- publish_attach_desc.value = Splinter.theAttachment.description;
- publish_attach_filename.value = Splinter.theAttachment.filename;
- publish_attach_contenttype.value = Splinter.theAttachment.contenttypeentry;
- publish_attach_ispatch.value = Splinter.theAttachment.isPatch;
- publish_attach_isobsolete.value = Splinter.theAttachment.isObsolete;
- publish_attach_isprivate.value = Splinter.theAttachment.isPrivate;
-
- // This is a "magic string" used to identify review comments
- if (Splinter.theReview.toString()) {
- var comment = "Review of attachment " + Splinter.theAttachment.id + ":\n" +
- "-----------------------------------------------------------------\n\n" +
- Splinter.theReview.toString();
- publish_review.value = comment;
- }
-
- if (Splinter.theAttachment.status
- && Dom.get('attachmentStatus').value != Splinter.theAttachment.status)
- {
- publish_attach_status.value = Dom.get('attachmentStatus').value;
- }
-
- publish_form.submit();
-};
-
-Splinter.doDiscardReview = function () {
- if (Splinter.theAttachment.status) {
- Dom.get('attachmentStatus').value = Splinter.theAttachment.status;
- }
-
- Dom.get('myComment').value = '';
- Dom.setStyle('emptyCommentNotice', 'display', 'block');
-
- var i;
- for (i = 0; i < Splinter.theReview.files.length; i++) {
- while (Splinter.theReview.files[i].comments.length > 0) {
- Splinter.theReview.files[i].comments[0].remove();
- }
- }
-
- Splinter.updateMyPatchComments();
- Splinter.updateHaveDraft();
- Splinter.saveDraft();
-};
-
-Splinter.discardReview = function () {
- var dialog = new Splinter.Dialog("Really discard your changes?");
- dialog.addButton('No', function() {}, true);
- dialog.addButton('Yes', Splinter.doDiscardReview, false);
- dialog.show();
-};
-
-Splinter.haveDraft = function () {
- if (Splinter.readOnly) {
- return false;
- }
-
- if (Splinter.theAttachment.status && Dom.get('attachmentStatus').value != Splinter.theAttachment.status) {
- return true;
- }
-
- if (Dom.get('myComment').value != '') {
- return true;
- }
-
- var i;
- for (i = 0; i < Splinter.theReview.files.length; i++) {
- if (Splinter.theReview.files[i].comments.length > 0) {
- return true;
- }
- }
-
- for (i = 0; i < Splinter.thePatch.files.length; i++) {
- if (Splinter.thePatch.files[i].fileReviewed) {
- return true;
- }
- }
-
- if (Splinter.flagChanged == 1) {
- return true;
- }
-
- return false;
-};
-
-Splinter.updateHaveDraft = function () {
- clearTimeout(Splinter.updateHaveDraftTimeoutId);
- Splinter.updateHaveDraftTimeoutId = null;
-
- if (Splinter.haveDraft()) {
- Dom.get('publishButton').removeAttribute('disabled');
- Dom.get('cancelButton').removeAttribute('disabled');
- Dom.setStyle('haveDraftNotice', 'display', 'block');
- } else {
- Dom.get('publishButton').setAttribute('disabled', 'true');
- Dom.get('cancelButton').setAttribute('disabled', 'true');
- Dom.setStyle('haveDraftNotice', 'display', 'none');
- }
-};
-
-Splinter.queueUpdateHaveDraft = function () {
- if (Splinter.updateHaveDraftTimeoutId == null) {
- Splinter.updateHaveDraftTimeoutId = setTimeout(Splinter.updateHaveDraft, 0);
- }
-};
-
-Splinter.hideSaveDraftNotice = function () {
- clearTimeout(Splinter.saveDraftNoticeTimeoutId);
- Splinter.saveDraftNoticeTimeoutId = null;
- Dom.setStyle('saveDraftNotice', 'display', 'none');
-};
-
-Splinter.saveDraft = function () {
- if (Splinter.reviewStorage == null) {
- return;
- }
-
- clearTimeout(Splinter.saveDraftTimeoutId);
- Splinter.saveDraftTimeoutId = null;
-
- Splinter.savingDraft = true;
- Splinter.replaceText(Dom.get('saveDraftNotice'), "Saving Draft...");
- Dom.setStyle('saveDraftNotice', 'display', 'block');
- clearTimeout(Splinter.saveDraftNoticeTimeoutId);
- setTimeout(Splinter.hideSaveDraftNotice, 3000);
-
- if (Splinter.currentEditComment) {
- Splinter.currentEditComment.comment = Splinter.Utils.strip(Dom.get("commentEditor").getElementsByTagName("textarea")[0].value);
- // Messy, we don't want the empty comment in the saved draft, so remove it and
- // then add it back.
- if (!Splinter.currentEditComment.comment) {
- Splinter.currentEditComment.remove();
- }
- }
-
- Splinter.theReview.setIntro(Dom.get('myComment').value);
-
- var draftSaved = false;
- if (Splinter.haveDraft()) {
- var filesReviewed = {};
- for (var i = 0; i < Splinter.thePatch.files.length; i++) {
- var file = Splinter.thePatch.files[i];
- if (file.fileReviewed) {
- filesReviewed[file.filename] = true;
- }
- }
- Splinter.reviewStorage.saveDraft(Splinter.theBug, Splinter.theAttachment, Splinter.theReview,
- { 'filesReviewed' : filesReviewed });
- draftSaved = true;
- } else {
- Splinter.reviewStorage.deleteDraft(Splinter.theBug, Splinter.theAttachment, Splinter.theReview);
- }
-
- if (Splinter.currentEditComment && !Splinter.currentEditComment.comment) {
- Splinter.currentEditComment = Splinter.currentEditComment.file.addComment(Splinter.currentEditComment.location,
- Splinter.currentEditComment.type, "");
- }
-
- Splinter.savingDraft = false;
- if (draftSaved) {
- Splinter.replaceText(Dom.get('saveDraftNotice'), "Saved Draft");
- } else {
- Splinter.hideSaveDraftNotice();
- }
-};
-
-Splinter.replaceText = function (el, text) {
- while(el.firstChild) el.removeChild(el.firstChild);
- el.appendChild(document.createTextNode(text));
-}
-
-Splinter.queueSaveDraft = function () {
- if (Splinter.saveDraftTimeoutId == null) {
- Splinter.saveDraftTimeoutId = setTimeout(Splinter.saveDraft, 10000);
- }
-};
-
-Splinter.flushSaveDraft = function () {
- if (Splinter.saveDraftTimeoutId != null) {
- Splinter.saveDraft();
- }
-};
-
-Splinter.ensureCommentArea = function (row) {
- var file = Splinter.domCache.data(row).patchFile;
- var colSpan = file.status == Splinter.Patch.CHANGED ? 5 : 2;
-
- if (!row.nextSibling || row.nextSibling.className != "comment-area") {
- var tr = new Element(document.createElement('tr'));
- Dom.addClass(tr, 'comment-area');
- var td = new Element(document.createElement('td'));
- Dom.setAttribute(td, 'colspan', colSpan);
- td.appendTo(tr);
- Dom.insertAfter(tr, row);
- }
-
- return row.nextSibling.firstChild;
-};
-
-Splinter.getTypeClass = function (type) {
- switch (type) {
- case Splinter.Patch.ADDED:
- return "comment-added";
- case Splinter.Patch.REMOVED:
- return "comment-removed";
- case Splinter.Patch.CHANGED:
- return "comment-changed";
- }
-
- return null;
-};
-
-Splinter.getSeparatorClass = function (type) {
- switch (type) {
- case Splinter.Patch.ADDED:
- return "comment-separator-added";
- case Splinter.Patch.REMOVED:
- return "comment-separator-removed";
- }
-
- return null;
-};
-
-Splinter.getReviewerClass = function (review) {
- var reviewerIndex;
- if (review == Splinter.theReview) {
- reviewerIndex = 0;
- } else {
- reviewerIndex = (Splinter.reviewers[review.who] - 1) % 5 + 1;
- }
-
- return "reviewer-" + reviewerIndex;
-};
-
-Splinter.addCommentDisplay = function (commentArea, comment) {
- var review = comment.file.review;
-
- var separatorClass = Splinter.getSeparatorClass(comment.type);
- if (separatorClass) {
- var div = new Element(document.createElement('div'));
- Dom.addClass(div, separatorClass);
- Dom.addClass(div, Splinter.getReviewerClass(review));
- div.appendTo(commentArea);
- }
-
- var commentDiv = new Element(document.createElement('div'));
- Dom.addClass(commentDiv, 'comment');
- Dom.addClass(commentDiv, Splinter.getTypeClass(comment.type));
- Dom.addClass(commentDiv, Splinter.getReviewerClass(review));
-
- Event.addListener(Dom.get(commentDiv), 'dblclick', function () {
- Splinter.saveComment();
- Splinter.insertCommentEditor(commentArea, comment.file.patchFile,
- comment.location, comment.type);
- });
-
- var commentFrame = new Element(document.createElement('div'));
- Dom.addClass(commentFrame, 'comment-frame');
- commentFrame.appendTo(commentDiv);
-
- var reviewerBox = new Element(document.createElement('div'));
- Dom.addClass(reviewerBox, 'reviewer-box');
- reviewerBox.appendTo(commentFrame);
-
- var commentText = new Element(document.createElement('div'));
- Dom.addClass(commentText, 'comment-text');
- Splinter.Utils.preWrapLines(commentText, comment.comment);
- commentText.appendTo(reviewerBox);
-
- commentDiv.appendTo(commentArea);
-
- if (review != Splinter.theReview) {
- var reviewInfo = new Element(document.createElement('div'));
- Dom.addClass(reviewInfo, 'review-info');
-
- var reviewer = new Element(document.createElement('div'));
- Dom.addClass(reviewer, 'reviewer');
- reviewer.appendChild(document.createTextNode(review.who));
- reviewer.appendTo(reviewInfo);
-
- var reviewDate = new Element(document.createElement('div'));
- Dom.addClass(reviewDate, 'review-date');
- reviewDate.appendChild(document.createTextNode(Splinter.Utils.formatDate(review.date)));
- reviewDate.appendTo(reviewInfo);
-
- var reviewInfoBottom = new Element(document.createElement('div'));
- Dom.addClass(reviewInfoBottom, 'review-info-bottom');
- reviewInfoBottom.appendTo(reviewInfo);
-
- reviewInfo.appendTo(reviewerBox);
- }
-
- comment.div = commentDiv;
-};
-
-Splinter.saveComment = function () {
- var comment = Splinter.currentEditComment;
- if (!comment) {
- return;
- }
-
- var commentEditor = Dom.get('commentEditor');
- var commentArea = commentEditor.parentNode;
- var reviewFile = comment.file;
-
- var hunk = comment.getHunk();
- var line = hunk.lines[comment.location - hunk.location];
-
- var value = Splinter.Utils.strip(commentEditor.getElementsByTagName('textarea')[0].value);
- if (value != "") {
- comment.comment = value;
- Splinter.addCommentDisplay(commentArea, comment);
- } else {
- comment.remove();
- }
-
- if (line.reviewComments.length > 0) {
- commentEditor.parentNode.removeChild(commentEditor);
- var commentEditorSeparator = Dom.get('commentEditorSeparator');
- if (commentEditorSeparator) {
- commentEditorSeparator.parentNode.removeChild(commentEditorSeparator);
- }
- } else {
- var parentToRemove = commentArea.parentNode;
- commentArea.parentNode.parentNode.removeChild(parentToRemove);
- }
-
- Splinter.currentEditComment = null;
- Splinter.saveDraft();
- Splinter.queueUpdateHaveDraft();
-};
-
-Splinter.cancelComment = function (previousText) {
- Dom.get("commentEditor").getElementsByTagName("textarea")[0].value = previousText;
- Splinter.saveComment();
-};
-
-Splinter.deleteComment = function () {
- Dom.get('commentEditor').getElementsByTagName('textarea')[0].value = "";
- Splinter.saveComment();
-};
-
-Splinter.insertCommentEditor = function (commentArea, file, location, type) {
- Splinter.saveComment();
-
- var reviewFile = Splinter.theReview.getFile(file.filename);
- var comment = reviewFile.getComment(location, type);
- if (!comment) {
- comment = reviewFile.addComment(location, type, "");
- Splinter.queueUpdateHaveDraft();
- }
-
- var previousText = comment.comment;
-
- var typeClass = Splinter.getTypeClass(type);
- var separatorClass = Splinter.getSeparatorClass(type);
-
- var nodes = Dom.getElementsByClassName('reviewer-0', 'div', commentArea);
- var i;
- for (i = 0; i < nodes.length; i++) {
- if (separatorClass && Dom.hasClass(nodes[i], separatorClass)) {
- nodes[i].parentNode.removeChild(nodes[i]);
- }
- if (Dom.hasClass(nodes[i], typeClass)) {
- nodes[i].parentNode.removeChild(nodes[i]);
- }
- }
-
- if (separatorClass) {
- var commentEditorSeparator = new Element(document.createElement('div'));
- commentEditorSeparator.set('id', 'commentEditorSeparator');
- Dom.addClass(commentEditorSeparator, separatorClass);
- commentEditorSeparator.appendTo(commentArea);
- }
-
- var commentEditor = new Element(document.createElement('div'));
- Dom.setAttribute(commentEditor, 'id', 'commentEditor');
- Dom.addClass(commentEditor, typeClass);
- commentEditor.appendTo(commentArea);
-
- var commentEditorInner = new Element(document.createElement('div'));
- Dom.setAttribute(commentEditorInner, 'id', 'commentEditorInner');
- commentEditorInner.appendTo(commentEditor);
-
- var commentTextFrame = new Element(document.createElement('div'));
- Dom.setAttribute(commentTextFrame, 'id', 'commentTextFrame');
- commentTextFrame.appendTo(commentEditorInner);
-
- var commentTextArea = new Element(document.createElement('textarea'));
- Dom.setAttribute(commentTextArea, 'id', 'commentTextArea');
- Dom.setAttribute(commentTextArea, 'tabindex', 1);
- commentTextArea.appendChild(document.createTextNode(previousText));
- commentTextArea.appendTo(commentTextFrame);
- Event.addListener('commentTextArea', 'keydown', function (e) {
- if (e.which == 13 && e.ctrlKey) {
- Splinter.saveComment();
- } else if (e.which == 27) {
- var comment = Dom.get('commentTextArea').value;
- if (previousText == comment || comment == '') {
- Splinter.cancelComment(previousText);
- }
- } else {
- Splinter.queueSaveDraft();
- }
- });
- Event.addListener('commentTextArea', 'focusin', function () { Dom.addClass(commentEditor, 'focused'); });
- Event.addListener('commentTextArea', 'focusout', function () { Dom.removeClass(commentEditor, 'focused'); });
- Dom.get(commentTextArea).focus();
-
- var commentEditorLeftButtons = new Element(document.createElement('div'));
- commentEditorLeftButtons.set('id', 'commentEditorLeftButtons');
- commentEditorLeftButtons.appendTo(commentEditorInner);
-
- var commentCancel = new Element(document.createElement('input'));
- commentCancel.set('id','commentCancel');
- commentCancel.set('type', 'button');
- commentCancel.set('value', 'Cancel');
- Dom.setAttribute(commentCancel, 'tabindex', 4);
- commentCancel.appendTo(commentEditorLeftButtons);
- Event.addListener('commentCancel', 'click', function () { Splinter.cancelComment(previousText); });
-
- if (previousText) {
- var commentDelete = new Element(document.createElement('input'));
- commentDelete.set('id','commentDelete');
- commentDelete.set('type', 'button');
- commentDelete.set('value', 'Delete');
- Dom.setAttribute(commentDelete, 'tabindex', 3);
- commentDelete.appendTo(commentEditorLeftButtons);
- Event.addListener('commentDelete', 'click', Splinter.deleteComment);
- }
-
- var commentEditorRightButtons = new Element(document.createElement('div'));
- commentEditorRightButtons.set('id', 'commentEditorRightButtons');
- commentEditorRightButtons.appendTo(commentEditorInner);
-
- var commentSave = new Element(document.createElement('input'));
- commentSave.set('id','commentSave');
- commentSave.set('type', 'button');
- commentSave.set('value', 'Save');
- Dom.setAttribute(commentSave, 'tabindex', 2);
- commentSave.appendTo(commentEditorRightButtons);
- Event.addListener('commentSave', 'click', Splinter.saveComment);
-
- var clear = new Element(document.createElement('div'));
- Dom.addClass(clear, 'clear');
- clear.appendTo(commentEditorInner);
-
- Splinter.currentEditComment = comment;
-};
-
-Splinter.insertCommentForRow = function (clickRow, clickType) {
- var file = Splinter.domCache.data(clickRow).patchFile;
- var clickLocation = Splinter.domCache.data(clickRow).patchLocation;
-
- var row = clickRow;
- var location = clickLocation;
- var type = clickType;
-
- Splinter.saveComment();
- var commentArea = Splinter.ensureCommentArea(row);
- Splinter.insertCommentEditor(commentArea, file, location, type);
-};
-
-Splinter.EL = function (element, cls, text, title) {
- var e = document.createElement(element);
- if (text != null) {
- e.appendChild(document.createTextNode(text));
- }
- if (cls) {
- e.className = cls;
- }
- if (title) {
- Dom.setAttribute(e, 'title', title);
- }
-
- return e;
-};
-
-Splinter.textTD = function (cls, text, title) {
- if (text == "") {
- return Splinter.EL("td", cls, "\u00a0", title);
- }
- var m = text.match(/^(.*?)(\s+)$/);
- if (m) {
- var td = Splinter.EL("td", cls, m[1], title);
- td.insertBefore(Splinter.EL("span", cls + " trailing-whitespace", m[2], title), null);
- return td;
- } else {
- return Splinter.EL("td", cls, text, title);
- }
-}
-
-Splinter.getElementPosition = function (element) {
- var left = element.offsetLeft;
- var top = element.offsetTop;
- var parent = element.offsetParent;
- while (parent && parent != document.body) {
- left += parent.offsetLeft;
- top += parent.offsetTop;
- parent = parent.offsetParent;
- }
-
- return [left, top];
-};
-
-Splinter.scrollToElement = function (element) {
- var windowHeight;
- if ('innerHeight' in window) { // Not IE
- windowHeight = window.innerHeight;
- } else { // IE
- windowHeight = document.documentElement.clientHeight;
- }
- var pos = Splinter.getElementPosition(element);
- var yCenter = pos[1] + element.offsetHeight / 2;
- window.scrollTo(0, yCenter - windowHeight / 2);
-};
-
-Splinter.onRowDblClick = function (e) {
- var file = Splinter.domCache.data(this).patchFile;
- var type;
-
- if (file.status == Splinter.Patch.CHANGED) {
- var pos = Splinter.getElementPosition(this);
- var delta = e.pageX - (pos[0] + this.offsetWidth/2);
- if (delta < - 20) {
- type = Splinter.Patch.REMOVED;
- } else if (delta < 20) {
- // CHANGED comments disabled due to breakage
- // type = Splinter.Patch.CHANGED;
- type = Splinter.Patch.ADDED;
- } else {
- type = Splinter.Patch.ADDED;
- }
- } else {
- type = file.status;
- }
-
- Splinter.insertCommentForRow(this, type);
-};
-
-Splinter.appendPatchTable = function (type, maxLine, parentDiv) {
- var fileTableContainer = new Element(document.createElement('div'));
- Dom.addClass(fileTableContainer, 'file-table-container');
- fileTableContainer.appendTo(parentDiv);
-
- var fileTable = new Element(document.createElement('table'));
- Dom.addClass(fileTable, 'file-table');
- fileTable.appendTo(fileTableContainer);
-
- var colQ = new Element(document.createElement('colgroup'));
- colQ.appendTo(fileTable);
-
- var col1, col2;
- if (type != Splinter.Patch.ADDED) {
- col1 = new Element(document.createElement('col'));
- Dom.addClass(col1, 'line-number-column');
- Dom.setAttribute(col1, 'span', '1');
- col1.appendTo(colQ);
- col2 = new Element(document.createElement('col'));
- Dom.addClass(col2, 'old-column');
- Dom.setAttribute(col2, 'span', '1');
- col2.appendTo(colQ);
- }
- if (type == Splinter.Patch.CHANGED) {
- col1 = new Element(document.createElement('col'));
- Dom.addClass(col1, 'middle-column');
- Dom.setAttribute(col1, 'span', '1');
- col1.appendTo(colQ);
- }
- if (type != Splinter.Patch.REMOVED) {
- col1 = new Element(document.createElement('col'));
- Dom.addClass(col1, 'line-number-column');
- Dom.setAttribute(col1, 'span', '1');
- col1.appendTo(colQ);
- col2 = new Element(document.createElement('col'));
- Dom.addClass(col2, 'new-column');
- Dom.setAttribute(col2, 'span', '1');
- col2.appendTo(colQ);
- }
-
- if (type == Splinter.Patch.CHANGED) {
- Dom.addClass(fileTable, 'file-table-changed');
- }
-
- if (maxLine >= 1000) {
- Dom.addClass(fileTable, "file-table-wide-numbers");
- }
-
- var tbody = new Element(document.createElement('tbody'));
- tbody.appendTo(fileTable);
-
- return tbody;
-};
-
-Splinter.appendPatchHunk = function (file, hunk, tableType, includeComments, clickable, tbody, filter) {
- hunk.iterate(function(loc, oldLine, oldText, newLine, newText, flags, line) {
- if (filter && !filter(loc)) {
- return;
- }
-
- var tr = document.createElement("tr");
-
- var oldStyle = "";
- var newStyle = "";
- if ((flags & Splinter.Patch.CHANGED) != 0) {
- oldStyle = newStyle = "changed-line";
- } else if ((flags & Splinter.Patch.REMOVED) != 0) {
- oldStyle = "removed-line";
- } else if ((flags & Splinter.Patch.ADDED) != 0) {
- newStyle = "added-line";
- }
-
- var title = "Double click the line to add a review comment";
-
- if (tableType != Splinter.Patch.ADDED) {
- if (oldText != null) {
- tr.appendChild(Splinter.EL("td", "line-number old " + oldStyle, oldLine.toString(), title));
- tr.appendChild(Splinter.textTD("old-line " + oldStyle, oldText, title));
- oldLine++;
- } else {
- tr.appendChild(Splinter.EL("td", "line-number"));
- tr.appendChild(Splinter.EL("td", "old-line"));
- }
- }
-
- if (tableType == Splinter.Patch.CHANGED) {
- tr.appendChild(Splinter.EL("td", "line-middle"));
- }
-
- if (tableType != Splinter.Patch.REMOVED) {
- if (newText != null) {
- tr.appendChild(Splinter.EL("td", "line-number new " + newStyle, newLine.toString(), title));
- tr.appendChild(Splinter.textTD("new-line " + newStyle, newText, title));
- newLine++;
- } else if (tableType == Splinter.Patch.CHANGED) {
- tr.appendChild(Splinter.EL("td", "line-number"));
- tr.appendChild(Splinter.EL("td", "new-line"));
- }
- }
-
- if (!Splinter.readOnly && clickable) {
- Splinter.domCache.data(tr).patchFile = file;
- Splinter.domCache.data(tr).patchLocation = loc;
- Event.addListener(tr, 'dblclick', Splinter.onRowDblClick);
- }
-
- tbody.appendChild(tr);
-
- if (includeComments && line.reviewComments != null) {
- var k;
- for (k = 0; k < line.reviewComments.length; k++) {
- var commentArea = Splinter.ensureCommentArea(tr);
- Splinter.addCommentDisplay(commentArea, line.reviewComments[k]);
- }
- }
- });
-};
-
-Splinter.addPatchFile = function (file) {
- var fileDiv = new Element(document.createElement('div'));
- Dom.addClass(fileDiv, 'file');
- fileDiv.appendTo(Dom.get('splinter-files'));
- file.div = fileDiv;
-
- var statusString;
- switch (file.status) {
- case Splinter.Patch.ADDED:
- statusString = " (new file)";
- break;
- case Splinter.Patch.REMOVED:
- statusString = " (removed)";
- break;
- case Splinter.Patch.CHANGED:
- statusString = "";
- break;
- }
-
- var fileLabel = new Element(document.createElement('div'));
- Dom.addClass(fileLabel, 'file-label');
- fileLabel.appendTo(fileDiv);
-
- var fileCollapseLink = document.createElement('a');
- fileCollapseLink.classList.add('file-label-collapse');
- fileCollapseLink.appendChild(document.createTextNode("[-]"));
- fileCollapseLink.setAttribute('href', "javascript:void(0);");
- fileCollapseLink.addEventListener("click", function() {
- Splinter.toggleCollapsed(encodeURIComponent(file.filename));
- });
- fileCollapseLink.setAttribute("title", 'Click to expand or collapse this file table');
- new Element(fileCollapseLink).appendTo(fileLabel);
-
- var fileLabelName = new Element(document.createElement('span'));
- Dom.addClass(fileLabelName, 'file-label-name');
- fileLabelName.appendChild(document.createTextNode(file.filename));
- fileLabelName.appendTo(fileLabel);
-
- var fileLabelStatus = new Element(document.createElement('span'));
- Dom.addClass(fileLabelStatus, 'file-label-status');
- fileLabelStatus.appendChild(document.createTextNode(statusString));
- fileLabelStatus.appendTo(fileLabel);
-
- if (!Splinter.readOnly) {
- var fileReviewed = new Element(document.createElement('span'));
- Dom.addClass(fileReviewed, 'file-review');
- Dom.setAttribute(fileReviewed, 'title', 'Indicates that a review has been completed for this file. ' +
- 'This is for personal tracking purposes only and has no effect ' +
- 'on the published review.');
- fileReviewed.appendTo(fileLabel);
-
- var fileReviewedInput = document.createElement('input');
- fileReviewedInput.setAttribute("type", "checkbox");
- fileReviewedInput.setAttribute("id", 'file-review-checkbox-' + encodeURIComponent(file.filename));
- fileReviewedInput.addEventListener("change", function() {
- Splinter.toggleFileReviewed(encodeURIComponent(file.filename));
- });
-
- if (file.fileReviewed) {
- fileReviewedInput.setAttribute("checked", 'true');
- }
- new Element(fileReviewedInput).appendTo(fileReviewed);
-
- var fileReviewedLabel = new Element(document.createElement('label'));
- Dom.addClass(fileReviewedLabel, 'file-review-label')
- Dom.setAttribute(fileReviewedLabel, 'for', 'file-review-checkbox-' + encodeURIComponent(file.filename));
- fileReviewedLabel.appendChild(document.createTextNode(' Reviewed'));
- fileReviewedLabel.appendTo(fileReviewed);
- }
-
- if (file.extra) {
- var extraContainer = new Element(document.createElement('div'));
- Dom.addClass(extraContainer, 'file-extra-container');
- var extraMargin = new Element(document.createElement('span'));
- Dom.addClass(extraMargin, 'file-label-collapse');
- extraMargin.appendChild(document.createTextNode('\u00a0\u00a0\u00a0'));
- extraMargin.appendTo(extraContainer);
- var extraLabel = new Element(document.createElement('span'));
- Dom.addClass(extraLabel, 'file-label-extra');
- extraLabel.appendChild(document.createTextNode(file.extra));
- extraLabel.appendTo(extraContainer);
- extraContainer.appendTo(fileLabel);
- }
-
- if (file.hunks.length == 0)
- return;
-
- var lastHunk = file.hunks[file.hunks.length - 1];
- var lastLine = Math.max(lastHunk.oldStart + lastHunk.oldCount - 1,
- lastHunk.newStart + lastHunk.newCount - 1);
-
- var tbody = Splinter.appendPatchTable(file.status, lastLine, fileDiv);
-
- var i;
- for (i = 0; i < file.hunks.length; i++) {
- var hunk = file.hunks[i];
- if (hunk.oldStart > 1) {
- var hunkHeader = Splinter.EL("tr", "hunk-header");
- tbody.appendChild(hunkHeader);
- hunkHeader.appendChild(Splinter.EL("td")); // line number column
- var hunkCell = Splinter.EL(
- "td",
- "hunk-cell",
- "Lines " + hunk.oldStart + '-' +
- Math.max(hunk.oldStart + hunk.oldCount - 1, hunk.newStart + hunk.newCount - 1) +
- "\u00a0\u00a0" + hunk.functionLine
- );
- hunkCell.colSpan = file.status == Splinter.Patch.CHANGED ? 4 : 1;
- hunkHeader.appendChild(hunkCell);
- }
-
- Splinter.appendPatchHunk(file, hunk, file.status, true, true, tbody);
- }
-};
-
-Splinter.appendReviewComment = function (comment, parentDiv) {
- var commentDiv = Splinter.EL("div", "review-patch-comment");
- Event.addListener(commentDiv, 'click', function() {
- Splinter.showPatchFile(comment.file.patchFile);
- if (comment.file.review == Splinter.theReview) {
- // Immediately start editing the comment again
- var commentDivParent = Dom.getAncestorByClassName(comment.div, 'comment-area');
- var commentArea = commentDivParent.getElementsByTagName('td')[0];
- Splinter.insertCommentEditor(commentArea, comment.file.patchFile, comment.location, comment.type);
- Splinter.scrollToElement(Dom.get('commentEditor'));
- } else {
- // Just scroll to the comment, don't start a reply yet
- Splinter.scrollToElement(Dom.get(comment.div));
- }
- });
-
- var inReplyTo = comment.getInReplyTo();
- if (inReplyTo) {
- var div = new Element(document.createElement('div'));
- Dom.addClass(div, Splinter.getReviewerClass(inReplyTo.file.review));
- div.appendTo(commentDiv);
-
- var reviewerBox = new Element(document.createElement('div'));
- Dom.addClass(reviewerBox, 'reviewer-box');
- Splinter.Utils.preWrapLines(reviewerBox, inReplyTo.comment);
- reviewerBox.appendTo(div);
-
- var reviewPatchCommentText = new Element(document.createElement('div'));
- Dom.addClass(reviewPatchCommentText, 'review-patch-comment-text');
- Splinter.Utils.preWrapLines(reviewPatchCommentText, comment.comment);
- reviewPatchCommentText.appendTo(commentDiv);
-
- } else {
- var hunk = comment.getHunk();
-
- var lastLine = Math.max(hunk.oldStart + hunk.oldCount- 1,
- hunk.newStart + hunk.newCount- 1);
- var tbody = Splinter.appendPatchTable(comment.type, lastLine, commentDiv);
-
- Splinter.appendPatchHunk(comment.file.patchFile, hunk, comment.type, false, false, tbody,
- function(loc) {
- return (loc <= comment.location && comment.location - loc < 5);
- });
-
- var tr = new Element(document.createElement('tr'));
- var td = new Element(document.createElement('td'));
- td.appendTo(tr);
- td = new Element(document.createElement('td'));
- Dom.addClass(td, 'review-patch-comment-text');
- Splinter.Utils.preWrapLines(td, comment.comment);
- td.appendTo(tr);
- tr.appendTo(tbody);
- }
-
- parentDiv.appendChild(commentDiv);
-};
-
-Splinter.appendReviewComments = function (review, parentDiv) {
- var i;
- for (i = 0; i < review.files.length; i++) {
- var file = review.files[i];
-
- if (file.comments.length == 0) {
- continue;
- }
-
- parentDiv.appendChild(Splinter.EL("div", "review-patch-file", file.patchFile.filename));
- var firstComment = true;
- var j;
- for (j = 0; j < file.comments.length; j++) {
- if (firstComment) {
- firstComment = false;
- } else {
- parentDiv.appendChild(Splinter.EL("div", "review-patch-comment-separator"));
- }
-
- Splinter.appendReviewComment(file.comments[j], parentDiv);
- }
- }
-};
-
-Splinter.updateMyPatchComments = function () {
- var myPatchComments = Dom.get("myPatchComments");
- Splinter.replaceText(myPatchComments, '');
- Splinter.appendReviewComments(Splinter.theReview, myPatchComments);
- if (Dom.getChildren(myPatchComments).length > 0) {
- Dom.setStyle(myPatchComments, 'display', 'block');
- } else {
- Dom.setStyle(myPatchComments, 'display', 'none');
- }
-};
-
-Splinter.selectNavigationLink = function (identifier) {
- var navigationLinks = Dom.getElementsByClassName('navigation-link');
- var i;
- for (i = 0; i < navigationLinks.length; i++) {
- Dom.removeClass(navigationLinks[i], 'navigation-link-selected');
- }
- Dom.addClass(Splinter.navigationLinks[identifier], 'navigation-link-selected');
-};
-
-Splinter.addNavigationLink = function (identifier, title, callback, selected) {
- var navigationDiv = Dom.get('navigation');
- if (Dom.getChildren(navigationDiv).length > 0) {
- navigationDiv.appendChild(document.createTextNode(' | '));
- }
-
- var navigationLink = new Element(document.createElement('a'));
- Dom.addClass(navigationLink, 'navigation-link');
- Dom.setAttribute(navigationLink, 'href', 'javascript:void(0);');
- Dom.setAttribute(navigationLink, 'id', 'switch-' + encodeURIComponent(identifier));
- Dom.setAttribute(navigationLink, 'title', identifier);
- navigationLink.appendChild(document.createTextNode(title));
- navigationLink.appendTo(navigationDiv);
-
- // FIXME: Find out why I need to use an id here instead of just passing
- // navigationLink to Event.addListener()
- Event.addListener('switch-' + encodeURIComponent(identifier), 'click', function () {
- if (!Dom.hasClass(this, 'navigation-link-selected')) {
- callback();
- }
- });
-
- if (selected) {
- Dom.addClass(navigationLink, 'navigation-link-selected');
- }
-
- Splinter.navigationLinks[identifier] = navigationLink;
-};
-
-Splinter.showOverview = function () {
- Splinter.selectNavigationLink('__OVERVIEW__');
- Dom.setStyle('overview', 'display', 'block');
- Dom.getElementsByClassName('file', 'div', '', function (node) {
- Dom.setStyle(node, 'display', 'none');
- });
- if (!Splinter.readOnly)
- Splinter.updateMyPatchComments();
-};
-
-Splinter.showAllFiles = function () {
- Splinter.selectNavigationLink('__ALL__');
- Dom.setStyle('overview', 'display', 'none');
- Dom.setStyle('file-collapse-all', 'display', 'block');
-
- var i;
- for (i = 0; i < Splinter.thePatch.files.length; i++) {
- var file = Splinter.thePatch.files[i];
- if (!file.div) {
- Splinter.addPatchFile(file);
- } else {
- Dom.setStyle(file.div, 'display', 'block');
- }
- }
-}
-
-Splinter.toggleCollapsed = function (filename, display) {
- filename = decodeURIComponent(filename);
- var i;
- for (i = 0; i < Splinter.thePatch.files.length; i++) {
- var file = Splinter.thePatch.files[i];
- if (!filename || filename == file.filename) {
- var fileTableContainer = file.div.getElementsByClassName('file-table-container')[0];
- var fileExtraContainer = file.div.getElementsByClassName('file-extra-container')[0];
- var fileCollapseLink = file.div.getElementsByClassName('file-label-collapse')[0];
- if (!display) {
- display = Dom.getStyle(fileTableContainer, 'display') == 'block' ? 'none' : 'block';
- }
- Dom.setStyle(fileTableContainer, 'display', display);
- Dom.setStyle(fileExtraContainer, 'display', display);
- Splinter.replaceText(fileCollapseLink, (display == 'block' ? '[-]' : '[+]'));
- }
- }
-}
-
-Splinter.toggleFileReviewed = function (filename) {
- var checkbox = Dom.get('file-review-checkbox-' + filename);
- if (checkbox) {
- filename = decodeURIComponent(filename);
- for (var i = 0; i < Splinter.thePatch.files.length; i++) {
- var file = Splinter.thePatch.files[i];
- if (file.filename == filename) {
- file.fileReviewed = checkbox.checked;
-
- Splinter.saveDraft();
- Splinter.queueUpdateHaveDraft();
-
- // Strike through file names to show review was completed
- var fileNavLink = Dom.get('switch-' + encodeURIComponent(filename));
- if (file.fileReviewed) {
- Dom.addClass(fileNavLink, 'file-reviewed-nav');
- }
- else {
- Dom.removeClass(fileNavLink, 'file-reviewed-nav');
- }
- }
- }
- }
-}
-
-Splinter.showPatchFile = function (file) {
- Splinter.selectNavigationLink(file.filename);
- Dom.setStyle('overview', 'display', 'none');
- Dom.setStyle('file-collapse-all', 'display', 'none');
-
- Dom.getElementsByClassName('file', 'div', '', function (node) {
- Dom.setStyle(node, 'display', 'none');
- });
-
- if (file.div) {
- Dom.setStyle(file.div, 'display', 'block');
- } else {
- Splinter.addPatchFile(file);
- }
-};
-
-Splinter.addFileNavigationLink = function (file) {
- var basename = file.filename.replace(/.*\//, "");
- Splinter.addNavigationLink(file.filename, basename, function() {
- Splinter.showPatchFile(file);
- });
-};
-
-Splinter.start = function () {
- Dom.setStyle('attachmentInfo', 'display', 'block');
- Dom.setStyle('navigationContainer', 'display', 'block');
- Dom.setStyle('overview', 'display', 'block');
- Dom.setStyle('splinter-files', 'display', 'block');
- Dom.setStyle('attachmentStatusSpan', 'display', 'none');
-
- if (Splinter.thePatch.intro) {
- Splinter.Utils.preWrapLines(Dom.get('patchIntro'), Splinter.thePatch.intro);
- } else {
- Dom.setStyle('patchIntro', 'display', 'none');
- }
-
- Splinter.addNavigationLink('__OVERVIEW__', "Overview", Splinter.showOverview, true);
- Splinter.addNavigationLink('__ALL__', "All Files", Splinter.showAllFiles, false);
-
- var i;
- for (i = 0; i < Splinter.thePatch.files.length; i++) {
- Splinter.addFileNavigationLink(Splinter.thePatch.files[i]);
- }
-
- var navigation = Dom.get('navigation');
-
- var haveDraftNotice = new Element(document.createElement('div'));
- Dom.setAttribute(haveDraftNotice, 'id', 'haveDraftNotice');
- haveDraftNotice.appendChild(document.createTextNode('Draft'));
- haveDraftNotice.appendTo(navigation);
-
- var clear = new Element(document.createElement('div'));
- Dom.addClass(clear, 'clear');
- clear.appendTo(navigation);
-
- var numReviewers = 0;
- for (i = 0; i < Splinter.theBug.comments.length; i++) {
- var comment = Splinter.theBug.comments[i];
- var m = Splinter.Review.REVIEW_RE.exec(comment.text);
-
- if (m && parseInt(m[1], 10) == Splinter.attachmentId) {
- var review = new Splinter.Review.Review(Splinter.thePatch, comment.getWho(), comment.date);
- review.parse(comment.text.substr(m[0].length));
-
- var reviewerIndex;
- if (review.who in Splinter.reviewers) {
- reviewerIndex = Splinter.reviewers[review.who];
- } else {
- reviewerIndex = ++numReviewers;
- Splinter.reviewers[review.who] = reviewerIndex;
- }
-
- var reviewDiv = new Element(document.createElement('div'));
- Dom.addClass(reviewDiv, 'review');
- Dom.addClass(reviewDiv, Splinter.getReviewerClass(review));
- reviewDiv.appendTo(Dom.get('oldReviews'));
-
- var reviewerBox = new Element(document.createElement('div'));
- Dom.addClass(reviewerBox, 'reviewer-box');
- reviewerBox.appendTo(reviewDiv);
-
- var reviewer = new Element(document.createElement('div'));
- Dom.addClass(reviewer, 'reviewer');
- reviewer.appendChild(document.createTextNode(review.who));
- reviewer.appendTo(reviewerBox);
-
- var reviewDate = new Element(document.createElement('div'));
- Dom.addClass(reviewDate, 'review-date');
- reviewDate.appendChild(document.createTextNode(Splinter.Utils.formatDate(review.date)));
- reviewDate.appendTo(reviewerBox);
-
- var reviewInfoBottom = new Element(document.createElement('div'));
- Dom.addClass(reviewInfoBottom, 'review-info-bottom');
- reviewInfoBottom.appendTo(reviewerBox);
-
- var reviewIntro = new Element(document.createElement('div'));
- Dom.addClass(reviewIntro, 'review-intro');
- Splinter.Utils.preWrapLines(reviewIntro, review.intro? review.intro : "");
- reviewIntro.appendTo(reviewerBox);
-
- Dom.setStyle('oldReviews', 'display', 'block');
-
- Splinter.appendReviewComments(review, reviewerBox);
- }
- }
-
- // We load the saved draft or create a new review *after* inserting the existing reviews
- // so that the ordering comes out right.
-
- if (Splinter.reviewStorage) {
- Splinter.theReview = Splinter.reviewStorage.loadDraft(Splinter.theBug, Splinter.theAttachment, Splinter.thePatch);
- if (Splinter.theReview) {
- var storedReviews = Splinter.reviewStorage.listReviews();
- Dom.setStyle('restored', 'display', 'block');
- for (i = 0; i < storedReviews.length; i++) {
- if (storedReviews[i].bugId == Splinter.theBug.id &&
- storedReviews[i].attachmentId == Splinter.theAttachment.id)
- {
- Splinter.replaceText(Dom.get("restoredLastModified"), Splinter.Utils.formatDate(new Date(storedReviews[i].modificationTime)));
- // Restore file reviewed checkboxes
- if (storedReviews[i].filesReviewed) {
- for (var j = 0; j < Splinter.thePatch.files.length; j++) {
- var file = Splinter.thePatch.files[j];
- if (storedReviews[i].filesReviewed[file.filename]) {
- file.fileReviewed = true;
- // Strike through file names to show that review was completed
- var fileNavLink = Dom.get('switch-' + encodeURIComponent(file.filename));
- Dom.addClass(fileNavLink, 'file-reviewed-nav');
- }
- }
- }
- }
- }
- }
- }
-
- if (!Splinter.theReview) {
- Splinter.theReview = new Splinter.Review.Review(Splinter.thePatch);
- }
-
- if (Splinter.theReview.intro) {
- Dom.setStyle('emptyCommentNotice', 'display', 'none');
- }
-
- if (!Splinter.readOnly) {
- var myComment = Dom.get('myComment');
- myComment.value = Splinter.theReview.intro ? Splinter.theReview.intro : "";
- Event.addListener(myComment, 'focus', function () {
- Dom.setStyle('emptyCommentNotice', 'display', 'none');
- });
- Event.addListener(myComment, 'blur', function () {
- if (myComment.value == '') {
- Dom.setStyle('emptyCommentNotice', 'display', 'block');
- }
- });
- Event.addListener(myComment, 'keydown', function () {
- Splinter.queueSaveDraft();
- Splinter.queueUpdateHaveDraft();
- });
-
- Splinter.updateMyPatchComments();
-
- Splinter.queueUpdateHaveDraft();
-
- Event.addListener("publishButton", "click", Splinter.publishReview);
- Event.addListener("cancelButton", "click", Splinter.discardReview);
- } else {
- Dom.setStyle('haveDraftNotice', 'display', 'none');
- }
-};
-
-Splinter.newPageUrl = function (newBugId, newAttachmentId) {
- var newUrl = Splinter.configBase;
- if (newBugId != null) {
- newUrl += (newUrl.indexOf("?") < 0) ? "?" : "&";
- newUrl += "bug=" + escape("" + newBugId);
- if (newAttachmentId != null) {
- newUrl += "&attachment=" + escape("" + newAttachmentId);
- }
- }
-
- return newUrl;
-};
-
-Splinter.showNote = function () {
- var noteDiv = Dom.get("note");
- if (noteDiv && Splinter.configNote) {
- Splinter.replaceText(noteDiv, Splinter.configNote);
- Dom.setStyle(noteDiv, 'display', 'block');
- }
-};
-
-Splinter.showEnterBug = function () {
- Splinter.showNote();
-
- Event.addListener("enterBugGo", "click", function () {
- var newBugId = Splinter.Utils.strip(Dom.get("enterBugInput").value);
- document.location = Splinter.newPageUrl(newBugId);
- });
-
- Dom.setStyle('enterBug', 'display', 'block');
-
- if (!Splinter.reviewStorage) {
- return;
- }
-
- var storedReviews = Splinter.reviewStorage.listReviews();
- if (storedReviews.length == 0) {
- return;
- }
-
- var i;
- var reviewData = [];
- for (i = storedReviews.length - 1; i >= 0; i--) {
- var reviewInfo = storedReviews[i];
- var modificationDate = Splinter.Utils.formatDate(new Date(reviewInfo.modificationTime));
- var extra = reviewInfo.isDraft ? "(draft)" : "";
-
- reviewData.push([
- reviewInfo.bugId,
- reviewInfo.bugId + ":" + reviewInfo.attachmentId,
- reviewInfo.attachmentDescription,
- modificationDate,
- extra
- ]);
- }
-
- var attachLink = function (elLiner, oRecord, oColumn, oData) {
- var splitResult = oData.split(':', 2);
- elLiner.innerHTML = "" + splitResult[1] + "";
- };
-
- var bugLink = function (elLiner, oRecord, oColumn, oData) {
- elLiner.innerHTML = "" + oData + "";
- };
-
- var attachDesc = function (elLiner, oRecord, oColumn, oData) {
- Splinter.replaceText(elLiner, oData);
- };
-
- dsConfig = {
- responseType: YAHOO.util.DataSource.TYPE_JSARRAY,
- responseSchema: { fields:["bug_id","attachment_id", "description", "date", "extra"] }
- };
-
- var columnDefs = [
- { key: "bug_id", label: "Bug", formatter: bugLink },
- { key: "attachment_id", label: "Attachment", formatter: attachLink },
- { key: "description", label: "Description", formatter: attachDesc },
- { key: "date", label: "Date" },
- { key: "extra", label: "Extra" }
- ];
-
- var dataSource = new YAHOO.util.LocalDataSource(reviewData, dsConfig);
- var dataTable = new YAHOO.widget.DataTable("chooseReviewTable", columnDefs, dataSource);
-
- Dom.setStyle('chooseReview', 'display', 'block');
-};
-
-Splinter.showChooseAttachment = function () {
- var drafts = {};
- var published = {};
- if (Splinter.reviewStorage) {
- var storedReviews = Splinter.reviewStorage.listReviews();
- var j;
- for (j = 0; j < storedReviews.length; j++) {
- var reviewInfo = storedReviews[j];
- if (reviewInfo.bugId == Splinter.theBug.id) {
- if (reviewInfo.isDraft) {
- drafts[reviewInfo.attachmentId] = 1;
- } else {
- published[reviewInfo.attachmentId] = 1;
- }
- }
- }
- }
-
- var attachData = [];
-
- var i;
- for (i = 0; i < Splinter.theBug.attachments.length; i++) {
- var attachment = Splinter.theBug.attachments[i];
-
- if (!attachment.isPatch || attachment.isObsolete) {
- continue;
- }
-
- var href = Splinter.newPageUrl(Splinter.theBug.id, attachment.id);
-
- var date = Splinter.Utils.formatDate(attachment.date);
- var status = (attachment.status && attachment.status != 'none') ? attachment.status : '';
-
- var extra = '';
- if (attachment.id in drafts) {
- extra = '(draft)';
- } else if (attachment.id in published) {
- extra = '(published)';
- }
-
- attachData.push([ attachment.id, attachment.description, attachment.date, extra ]);
- }
-
- var attachLink = function (elLiner, oRecord, oColumn, oData) {
- elLiner.innerHTML = "" + oData + "";
- };
-
- var attachDesc = function (elLiner, oRecord, oColumn, oData) {
- Splinter.replaceText(elLiner, oData);
- };
-
- dsConfig = {
- responseType: YAHOO.util.DataSource.TYPE_JSARRAY,
- responseSchema: { fields:["id","description","date", "extra"] }
- };
-
- var columnDefs = [
- { key: "id", label: "ID", formatter: attachLink },
- { key: "description", label: "Description", formatter: attachDesc },
- { key: "date", label: "Date" },
- { key: "extra", label: "Extra" }
- ];
-
- var dataSource = new YAHOO.util.LocalDataSource(attachData, dsConfig);
- var dataTable = new YAHOO.widget.DataTable("chooseAttachmentTable", columnDefs, dataSource);
-
- Dom.setStyle('chooseAttachment', 'display', 'block');
-};
-
-Splinter.quickHelpToggle = function () {
- var quickHelpShow = Dom.get('quickHelpShow');
- var quickHelpContent = Dom.get('quickHelpContent');
- var quickHelpToggle = Dom.get('quickHelpToggle');
-
- if (quickHelpContent.style.display == 'none') {
- quickHelpContent.style.display = 'block';
- quickHelpShow.style.display = 'none';
- } else {
- quickHelpContent.style.display = 'none';
- quickHelpShow.style.display = 'block';
- }
-};
-
-Splinter.init = function () {
- Splinter.showNote();
-
- if (Splinter.ReviewStorage.LocalReviewStorage.available()) {
- Splinter.reviewStorage = new Splinter.ReviewStorage.LocalReviewStorage();
- }
-
- if (Splinter.theBug == null) {
- Splinter.showEnterBug();
- return;
- }
-
- Splinter.replaceText(Dom.get("bugId"), Splinter.theBug.id);
- Dom.get("bugLink").setAttribute('href', Splinter.configBugUrl + "show_bug.cgi?id=" + Splinter.theBug.id);
- Splinter.replaceText(Dom.get("bugShortDesc"), Splinter.theBug.shortDesc);
- Splinter.replaceText(Dom.get("bugReporter"), Splinter.theBug.getReporter());
- Splinter.replaceText(Dom.get("bugCreationDate"), Splinter.Utils.formatDate(Splinter.theBug.creationDate));
- Dom.setStyle('bugInfo', 'display', 'block');
-
- if (Splinter.attachmentId) {
- Splinter.theAttachment = Splinter.theBug.getAttachment(Splinter.attachmentId);
-
- if (Splinter.theAttachment == null) {
- Splinter.displayError("Attachment " + Splinter.attachmentId + " is not an attachment to bug " + Splinter.theBug.id);
- }
- else if (!Splinter.theAttachment.isPatch) {
- Splinter.displayError("Attachment " + Splinter.attachmentId + " is not a patch");
- Splinter.theAttachment = null;
- }
- }
-
- if (Splinter.theAttachment == null) {
- Splinter.showChooseAttachment();
-
- } else {
- Splinter.replaceText(Dom.get("attachId"), Splinter.theAttachment.id);
- Dom.get("attachLink").setAttribute('href', Splinter.configBugUrl + "attachment.cgi?id=" + Splinter.theAttachment.id);
- Splinter.replaceText(Dom.get("attachDesc"), Splinter.theAttachment.description);
- Splinter.replaceText(Dom.get("attachCreator"), Splinter.Bug._formatWho(Splinter.theAttachment.whoName, Splinter.theAttachment.whoEmail));
- Splinter.replaceText(Dom.get("attachDate"), Splinter.Utils.formatDate(Splinter.theAttachment.date));
- Splinter.replaceText(Dom.get("attachComment"), Splinter.attachmentComment);
- var warnings = [];
- if (Splinter.theAttachment.isObsolete)
- warnings.push('OBSOLETE');
- if (Splinter.theAttachment.isCRLF)
- warnings.push('WINDOWS PATCH');
- if (warnings.length > 0)
- Splinter.replaceText(Dom.get("attachWarning"), warnings.join(', '));
- Dom.setStyle('attachInfo', 'display', 'block');
-
- Dom.setStyle('quickHelpShow', 'display', 'block');
-
- document.title = "Patch Review of Attachment " + Splinter.theAttachment.id +
- " for Bug " + Splinter.theBug.id;
-
- Splinter.thePatch = new Splinter.Patch.Patch(Splinter.theAttachment.data);
- if (Splinter.thePatch != null) {
- Splinter.start();
- }
- }
-};
-
-YAHOO.util.Event.addListener(window, 'load', Splinter.init);
diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl
index 6c70db23b7..d83f97a2aa 100644
--- a/template/en/default/global/header.html.tmpl
+++ b/template/en/default/global/header.html.tmpl
@@ -119,7 +119,6 @@
param => {
maxattachmentsize => Param('maxattachmentsize'),
maxusermatches => Param('maxusermatches'),
- splinter_base => Param('splinter_base'),
},
constant => {
COMMENT_COLS => constants.COMMENT_COLS,